Skip to content

Commit

Permalink
Rename PyInit syms to avoid clashes
Browse files Browse the repository at this point in the history
Built extensions in packages often have common names
like speedups, utils, _objects, cpython, etc. which
reside inside the package namespace.
The compiled extensions each have a PyInit_<module>
which needs to be renamed to PyInit_<pkg>_<module>
to avoid clashes when combined into a static binary.

Fixes #169
  • Loading branch information
jayvdb committed Nov 8, 2019
1 parent 35a7035 commit efe8df0
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 4 deletions.
1 change: 1 addition & 0 deletions pyoxidizer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ hex = "0.3"
itertools = "0.8"
lazy_static = "1.3"
libc = "0.2"
object = { version = "0.15.0", features = ["read", "std", "write"] }
regex = "1"
reqwest = "0.9"
rustc_version = "0.2"
Expand Down
106 changes: 102 additions & 4 deletions pyoxidizer/src/pyrepackager/repackage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ use byteorder::{LittleEndian, WriteBytesExt};
use glob::glob as findglob;
use itertools::Itertools;
use lazy_static::lazy_static;
use object::{write, Object, ObjectSection, RelocationTarget, SectionKind, SymbolKind};
use slog::{info, warn};
use std::collections::{BTreeMap, BTreeSet};
use std::collections::{BTreeMap, BTreeSet, HashMap};
use std::env;
use std::fs;
use std::fs::create_dir_all;
Expand Down Expand Up @@ -1126,7 +1127,7 @@ fn make_config_c(
}

for em in built_extension_modules.values() {
lines.push(format!("extern PyObject* {}(void);", em.init_fn));
lines.push(format!("extern PyObject* PyInit_{}(void);", em.name.replace(".", "_")));
}

lines.push(String::from("struct _inittab _PyImport_Inittab[] = {"));
Expand All @@ -1142,7 +1143,7 @@ fn make_config_c(
}

for em in built_extension_modules.values() {
lines.push(format!("{{\"{}\", {}}},", em.name, em.init_fn));
lines.push(format!("{{\"{}\", PyInit_{}}},", em.name, em.name.replace(".", "_")));
}

lines.push(String::from("{0, 0}"));
Expand All @@ -1151,6 +1152,101 @@ fn make_config_c(
lines.join("\n")
}

/// Rename object syn PyInit_foo to PyInit_<full_name> to avoid clashes
fn rename_init (
name: &String,
object_data: &[u8]
) -> Vec<u8> {
let in_object = match object::File::parse(object_data) {
Ok(object) => object,
Err(err) => {
panic!("Failed to parse compiled object for {}: {}", name, err);
}
};

let mut out_object = write::Object::new(in_object.format(), in_object.architecture());
out_object.mangling = write::Mangling::None;

let mut out_sections = HashMap::new();
for in_section in in_object.sections() {
if in_section.kind() == SectionKind::Metadata {
continue;
}
let section_id = out_object.add_section(
in_section.segment_name().unwrap_or("").as_bytes().to_vec(),
in_section.name().unwrap_or("").as_bytes().to_vec(),
in_section.kind(),
);
let out_section = out_object.section_mut(section_id);
if out_section.is_bss() {
out_section.append_bss(in_section.size(), in_section.align());
} else {
out_section.set_data(in_section.uncompressed_data().into(), in_section.align());
}
out_sections.insert(in_section.index(), section_id);
}

let mut out_symbols = HashMap::new();
for (symbol_index, in_symbol) in in_object.symbols() {
if in_symbol.kind() == SymbolKind::Null {
continue;
}
let (section, value) = match in_symbol.section_index() {
Some(index) => (
Some(*out_sections.get(&index).unwrap()),
in_symbol.address() - in_object.section_by_index(index).unwrap().address(),
),
None => (None, in_symbol.address()),
};
let in_sym_name = in_symbol.name().unwrap_or("");
let sym_name = if in_sym_name.starts_with("PyInit_") {
format!("PyInit_{}", name.replace(".", "_"))
} else {
String::from(in_sym_name)
};

let out_symbol = write::Symbol {
name: sym_name.as_bytes().to_vec(),
value,
size: in_symbol.size(),
kind: in_symbol.kind(),
scope: in_symbol.scope(),
weak: in_symbol.is_weak(),
section,
};
let symbol_id = out_object.add_symbol(out_symbol);
out_symbols.insert(symbol_index, symbol_id);
}

for in_section in in_object.sections() {
if in_section.kind() == SectionKind::Metadata {
continue;
}
let out_section = *out_sections.get(&in_section.index()).unwrap();
for (offset, in_relocation) in in_section.relocations() {
let symbol = match in_relocation.target() {
RelocationTarget::Symbol(symbol) => *out_symbols.get(&symbol).unwrap(),
RelocationTarget::Section(section) => {
out_object.section_symbol(*out_sections.get(&section).unwrap())
}
};
let out_relocation = write::Relocation {
offset,
size: in_relocation.size(),
kind: in_relocation.kind(),
encoding: in_relocation.encoding(),
symbol,
addend: in_relocation.addend(),
};
out_object
.add_relocation(out_section, out_relocation)
.unwrap();
}
}

out_object.write().unwrap()
}

#[derive(Debug)]
pub struct LibpythonInfo {
path: PathBuf,
Expand Down Expand Up @@ -1341,7 +1437,9 @@ pub fn link_libpython(
for (i, object_data) in em.object_file_data.iter().enumerate() {
let out_path = temp_dir_path.join(format!("{}.{}.o", name, i));

fs::write(&out_path, object_data).expect("unable to write object file");
let out_data = rename_init(name, object_data);

fs::write(&out_path, out_data).expect("unable to write object file");
build.object(&out_path);
}

Expand Down

0 comments on commit efe8df0

Please sign in to comment.