elf: re-enable dynamic linking codepaths
This commit is contained in:
@@ -591,6 +591,7 @@ set(ZIG_STAGE2_SOURCES
|
||||
"${CMAKE_SOURCE_DIR}/src/link/Elf/Atom.zig"
|
||||
"${CMAKE_SOURCE_DIR}/src/link/Elf/LinkerDefined.zig"
|
||||
"${CMAKE_SOURCE_DIR}/src/link/Elf/Object.zig"
|
||||
"${CMAKE_SOURCE_DIR}/src/link/Elf/SharedObject.zig"
|
||||
"${CMAKE_SOURCE_DIR}/src/link/Elf/Symbol.zig"
|
||||
"${CMAKE_SOURCE_DIR}/src/link/Elf/ZigModule.zig"
|
||||
"${CMAKE_SOURCE_DIR}/src/link/Elf/eh_frame.zig"
|
||||
|
||||
649
src/link/Elf.zig
649
src/link/Elf.zig
@@ -14,6 +14,7 @@ files: std.MultiArrayList(File.Entry) = .{},
|
||||
zig_module_index: ?File.Index = null,
|
||||
linker_defined_index: ?File.Index = null,
|
||||
objects: std.ArrayListUnmanaged(File.Index) = .{},
|
||||
shared_objects: std.ArrayListUnmanaged(File.Index) = .{},
|
||||
|
||||
/// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write.
|
||||
/// Same order as in the file.
|
||||
@@ -61,10 +62,34 @@ default_sym_version: elf.Elf64_Versym,
|
||||
shstrtab: StringTable(.strtab) = .{},
|
||||
/// .strtab buffer
|
||||
strtab: StringTable(.strtab) = .{},
|
||||
|
||||
/// Representation of the GOT table as committed to the file.
|
||||
/// Dynamic symbol table. Only populated and emitted when linking dynamically.
|
||||
dynsym: DynsymSection = .{},
|
||||
/// .dynstrtab buffer
|
||||
dynstrtab: StringTable(.dynstrtab) = .{},
|
||||
/// Version symbol table. Only populated and emitted when linking dynamically.
|
||||
versym: std.ArrayListUnmanaged(elf.Elf64_Versym) = .{},
|
||||
/// .verneed section
|
||||
verneed: VerneedSection = .{},
|
||||
/// .got section
|
||||
got: GotSection = .{},
|
||||
/// .rela.dyn section
|
||||
rela_dyn: std.ArrayListUnmanaged(elf.Elf64_Rela) = .{},
|
||||
/// .dynamic section
|
||||
dynamic: DynamicSection = .{},
|
||||
/// .hash section
|
||||
hash: HashSection = .{},
|
||||
/// .gnu.hash section
|
||||
gnu_hash: GnuHashSection = .{},
|
||||
/// .plt section
|
||||
plt: PltSection = .{},
|
||||
/// .got.plt section
|
||||
got_plt: GotPltSection = .{},
|
||||
/// .plt.got section
|
||||
plt_got: PltGotSection = .{},
|
||||
/// .copyrel section
|
||||
copy_rel: CopyRelSection = .{},
|
||||
/// .rela.plt section
|
||||
rela_plt: std.ArrayListUnmanaged(elf.Elf64_Rela) = .{},
|
||||
|
||||
/// Tracked section headers
|
||||
text_section_index: ?u16 = null,
|
||||
@@ -73,18 +98,30 @@ data_section_index: ?u16 = null,
|
||||
bss_section_index: ?u16 = null,
|
||||
tdata_section_index: ?u16 = null,
|
||||
tbss_section_index: ?u16 = null,
|
||||
eh_frame_section_index: ?u16 = null,
|
||||
eh_frame_hdr_section_index: ?u16 = null,
|
||||
dynamic_section_index: ?u16 = null,
|
||||
got_section_index: ?u16 = null,
|
||||
got_plt_section_index: ?u16 = null,
|
||||
plt_section_index: ?u16 = null,
|
||||
rela_dyn_section_index: ?u16 = null,
|
||||
debug_info_section_index: ?u16 = null,
|
||||
debug_abbrev_section_index: ?u16 = null,
|
||||
debug_str_section_index: ?u16 = null,
|
||||
debug_aranges_section_index: ?u16 = null,
|
||||
debug_line_section_index: ?u16 = null,
|
||||
|
||||
copy_rel_section_index: ?u16 = null,
|
||||
dynamic_section_index: ?u16 = null,
|
||||
dynstrtab_section_index: ?u16 = null,
|
||||
dynsymtab_section_index: ?u16 = null,
|
||||
eh_frame_section_index: ?u16 = null,
|
||||
eh_frame_hdr_section_index: ?u16 = null,
|
||||
hash_section_index: ?u16 = null,
|
||||
gnu_hash_section_index: ?u16 = null,
|
||||
got_section_index: ?u16 = null,
|
||||
got_plt_section_index: ?u16 = null,
|
||||
interp_section_index: ?u16 = null,
|
||||
plt_section_index: ?u16 = null,
|
||||
plt_got_section_index: ?u16 = null,
|
||||
rela_dyn_section_index: ?u16 = null,
|
||||
rela_plt_section_index: ?u16 = null,
|
||||
versym_section_index: ?u16 = null,
|
||||
verneed_section_index: ?u16 = null,
|
||||
|
||||
shstrtab_section_index: ?u16 = null,
|
||||
strtab_section_index: ?u16 = null,
|
||||
symtab_section_index: ?u16 = null,
|
||||
@@ -316,10 +353,11 @@ pub fn deinit(self: *Elf) void {
|
||||
.zig_module => data.zig_module.deinit(gpa),
|
||||
.linker_defined => data.linker_defined.deinit(gpa),
|
||||
.object => data.object.deinit(gpa),
|
||||
// .shared_object => data.shared_object.deinit(gpa),
|
||||
.shared_object => data.shared_object.deinit(gpa),
|
||||
};
|
||||
self.files.deinit(gpa);
|
||||
self.objects.deinit(gpa);
|
||||
self.shared_objects.deinit(gpa);
|
||||
|
||||
self.shdrs.deinit(gpa);
|
||||
self.phdr_to_shdr_table.deinit(gpa);
|
||||
@@ -333,7 +371,6 @@ pub fn deinit(self: *Elf) void {
|
||||
self.symbols.deinit(gpa);
|
||||
self.symbols_extra.deinit(gpa);
|
||||
self.symbols_free_list.deinit(gpa);
|
||||
self.got.deinit(gpa);
|
||||
self.resolver.deinit(gpa);
|
||||
self.start_stop_indexes.deinit(gpa);
|
||||
|
||||
@@ -369,7 +406,19 @@ pub fn deinit(self: *Elf) void {
|
||||
self.comdat_groups.deinit(gpa);
|
||||
self.comdat_groups_owners.deinit(gpa);
|
||||
self.comdat_groups_table.deinit(gpa);
|
||||
|
||||
self.got.deinit(gpa);
|
||||
self.plt.deinit(gpa);
|
||||
self.plt_got.deinit(gpa);
|
||||
self.dynsym.deinit(gpa);
|
||||
self.dynstrtab.deinit(gpa);
|
||||
self.dynamic.deinit(gpa);
|
||||
self.hash.deinit(gpa);
|
||||
self.versym.deinit(gpa);
|
||||
self.verneed.deinit(gpa);
|
||||
self.copy_rel.deinit(gpa);
|
||||
self.rela_dyn.deinit(gpa);
|
||||
self.rela_plt.deinit(gpa);
|
||||
}
|
||||
|
||||
pub fn getDeclVAddr(self: *Elf, decl_index: Module.Decl.Index, reloc_info: link.File.RelocInfo) !u64 {
|
||||
@@ -1268,6 +1317,24 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
|
||||
try dw.flushModule(self.base.options.module.?);
|
||||
}
|
||||
|
||||
// Dedup shared objects
|
||||
{
|
||||
var seen_dsos = std.StringHashMap(void).init(gpa);
|
||||
defer seen_dsos.deinit();
|
||||
try seen_dsos.ensureTotalCapacity(@as(u32, @intCast(self.shared_objects.items.len)));
|
||||
|
||||
var i: usize = 0;
|
||||
while (i < self.shared_objects.items.len) {
|
||||
const index = self.shared_objects.items[i];
|
||||
const shared_object = self.file(index).?.shared_object;
|
||||
const soname = shared_object.soname();
|
||||
const gop = seen_dsos.getOrPutAssumeCapacity(soname);
|
||||
if (gop.found_existing) {
|
||||
_ = self.shared_objects.orderedRemove(i);
|
||||
} else i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// If we haven't already, create a linker-generated input file comprising of
|
||||
// linker-defined synthetic symbols only such as `_DYNAMIC`, etc.
|
||||
if (self.linker_defined_index == null) {
|
||||
@@ -1677,6 +1744,7 @@ fn resolveSymbols(self: *Elf) void {
|
||||
if (self.zig_module_index) |index| self.file(index).?.resolveSymbols(self);
|
||||
// Resolve symbols on the set of all objects and shared objects (even if some are unneeded).
|
||||
for (self.objects.items) |index| self.file(index).?.resolveSymbols(self);
|
||||
for (self.shared_objects.items) |index| self.file(index).?.resolveSymbols(self);
|
||||
|
||||
// Mark live objects.
|
||||
self.markLive();
|
||||
@@ -1684,6 +1752,7 @@ fn resolveSymbols(self: *Elf) void {
|
||||
// Reset state of all globals after marking live objects.
|
||||
if (self.zig_module_index) |index| self.file(index).?.resetGlobals(self);
|
||||
for (self.objects.items) |index| self.file(index).?.resetGlobals(self);
|
||||
for (self.shared_objects.items) |index| self.file(index).?.resetGlobals(self);
|
||||
|
||||
// Prune dead objects and shared objects.
|
||||
var i: usize = 0;
|
||||
@@ -1693,6 +1762,13 @@ fn resolveSymbols(self: *Elf) void {
|
||||
_ = self.objects.orderedRemove(i);
|
||||
} else i += 1;
|
||||
}
|
||||
i = 0;
|
||||
while (i < self.shared_objects.items.len) {
|
||||
const index = self.shared_objects.items[i];
|
||||
if (!self.file(index).?.isAlive()) {
|
||||
_ = self.shared_objects.orderedRemove(i);
|
||||
} else i += 1;
|
||||
}
|
||||
|
||||
// Dedup comdat groups.
|
||||
for (self.objects.items) |index| {
|
||||
@@ -1728,6 +1804,7 @@ fn resolveSymbols(self: *Elf) void {
|
||||
// Re-resolve the symbols.
|
||||
if (self.zig_module_index) |index| self.file(index).?.resolveSymbols(self);
|
||||
for (self.objects.items) |index| self.file(index).?.resolveSymbols(self);
|
||||
for (self.shared_objects.items) |index| self.file(index).?.resolveSymbols(self);
|
||||
}
|
||||
|
||||
/// Traverses all objects and shared objects marking any object referenced by
|
||||
@@ -1740,6 +1817,10 @@ fn markLive(self: *Elf) void {
|
||||
const file_ptr = self.file(index).?;
|
||||
if (file_ptr.isAlive()) file_ptr.markLive(self);
|
||||
}
|
||||
for (self.shared_objects.items) |index| {
|
||||
const file_ptr = self.file(index).?;
|
||||
if (file_ptr.isAlive()) file_ptr.markLive(self);
|
||||
}
|
||||
}
|
||||
|
||||
fn markEhFrameAtomsDead(self: *Elf) void {
|
||||
@@ -1759,10 +1840,10 @@ fn markImportsExports(self: *Elf) void {
|
||||
const file_ptr = global.file(elf_file) orelse continue;
|
||||
const vis = @as(elf.STV, @enumFromInt(global.elfSym(elf_file).st_other));
|
||||
if (vis == .HIDDEN) continue;
|
||||
// if (file == .shared and !global.isAbs(self)) {
|
||||
// global.flags.import = true;
|
||||
// continue;
|
||||
// }
|
||||
if (file_ptr == .shared_object and !global.isAbs(elf_file)) {
|
||||
global.flags.import = true;
|
||||
continue;
|
||||
}
|
||||
if (file_ptr.index() == file_index) {
|
||||
global.flags.@"export" = true;
|
||||
if (elf_file.isDynLib() and vis != .PROTECTED) {
|
||||
@@ -1773,6 +1854,17 @@ fn markImportsExports(self: *Elf) void {
|
||||
}
|
||||
}.mark;
|
||||
|
||||
if (!self.isDynLib()) {
|
||||
for (self.shared_objects.items) |index| {
|
||||
for (self.file(index).?.globals()) |global_index| {
|
||||
const global = self.symbol(global_index);
|
||||
const file_ptr = global.file(self) orelse continue;
|
||||
const vis = @as(elf.STV, @enumFromInt(global.elfSym(self).st_other));
|
||||
if (file_ptr != .shared_object and vis != .HIDDEN) global.flags.@"export" = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (self.zig_module_index) |index| {
|
||||
mark(self, index);
|
||||
}
|
||||
@@ -1820,12 +1912,51 @@ fn scanRelocs(self: *Elf) !void {
|
||||
|
||||
try self.reportUndefined(&undefs);
|
||||
|
||||
for (self.symbols.items, 0..) |*sym, sym_index| {
|
||||
for (self.symbols.items, 0..) |*sym, i| {
|
||||
const index = @as(u32, @intCast(i));
|
||||
if (!sym.isLocal() and !sym.flags.has_dynamic) {
|
||||
log.debug("'{s}' is non-local", .{sym.name(self)});
|
||||
try self.dynsym.addSymbol(index, self);
|
||||
}
|
||||
if (sym.flags.needs_got) {
|
||||
log.debug("'{s}' needs GOT", .{sym.name(self)});
|
||||
_ = try self.got.addGotSymbol(@intCast(sym_index), self);
|
||||
sym.flags.has_got = true;
|
||||
_ = try self.got.addGotSymbol(index, self);
|
||||
}
|
||||
if (sym.flags.needs_plt) {
|
||||
if (sym.flags.is_canonical) {
|
||||
log.debug("'{s}' needs CPLT", .{sym.name(self)});
|
||||
sym.flags.@"export" = true;
|
||||
try self.plt.addSymbol(index, self);
|
||||
} else if (sym.flags.needs_got) {
|
||||
log.debug("'{s}' needs PLTGOT", .{sym.name(self)});
|
||||
try self.plt_got.addSymbol(index, self);
|
||||
} else {
|
||||
log.debug("'{s}' needs PLT", .{sym.name(self)});
|
||||
try self.plt.addSymbol(index, self);
|
||||
}
|
||||
}
|
||||
if (sym.flags.needs_copy_rel and !sym.flags.has_copy_rel) {
|
||||
log.debug("'{s}' needs COPYREL", .{sym.name(self)});
|
||||
try self.copy_rel.addSymbol(index, self);
|
||||
}
|
||||
if (sym.flags.needs_tlsgd) {
|
||||
log.debug("'{s}' needs TLSGD", .{sym.name(self)});
|
||||
try self.got.addTlsGdSymbol(index, self);
|
||||
}
|
||||
if (sym.flags.needs_gottp) {
|
||||
log.debug("'{s}' needs GOTTP", .{sym.name(self)});
|
||||
try self.got.addGotTpSymbol(index, self);
|
||||
}
|
||||
if (sym.flags.needs_tlsdesc) {
|
||||
log.debug("'{s}' needs TLSDESC", .{sym.name(self)});
|
||||
try self.dynsym.addSymbol(index, self);
|
||||
try self.got.addTlsDescSymbol(index, self);
|
||||
}
|
||||
}
|
||||
|
||||
if (self.got.flags.needs_tlsld) {
|
||||
log.debug("program needs TLSLD", .{});
|
||||
try self.got.addTlsLdSymbol(self);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2567,12 +2698,12 @@ fn writeHeader(self: *Elf) !void {
|
||||
|
||||
assert(index == 16);
|
||||
|
||||
const elf_type = switch (self.base.options.effectiveOutputMode()) {
|
||||
.Exe => elf.ET.EXEC,
|
||||
.Obj => elf.ET.REL,
|
||||
const elf_type: elf.ET = switch (self.base.options.effectiveOutputMode()) {
|
||||
.Exe => if (self.base.options.pic) .DYN else .EXEC,
|
||||
.Obj => .REL,
|
||||
.Lib => switch (self.base.options.link_mode) {
|
||||
.Static => elf.ET.REL,
|
||||
.Dynamic => elf.ET.DYN,
|
||||
.Static => @as(elf.ET, .REL),
|
||||
.Dynamic => .DYN,
|
||||
},
|
||||
};
|
||||
mem.writeInt(u16, hdr_buf[index..][0..2], @intFromEnum(elf_type), endian);
|
||||
@@ -2819,8 +2950,8 @@ fn updateDeclCode(
|
||||
esym.st_value = atom_ptr.value;
|
||||
|
||||
log.debug(" (writing new offset table entry)", .{});
|
||||
const extra = sym.extra(self).?;
|
||||
try self.got.writeEntry(self, extra.got);
|
||||
// const extra = sym.extra(self).?;
|
||||
// try self.got.writeEntry(self, extra.got);
|
||||
}
|
||||
} else if (code.len < old_size) {
|
||||
atom_ptr.shrink(self);
|
||||
@@ -2834,7 +2965,8 @@ fn updateDeclCode(
|
||||
|
||||
sym.flags.needs_got = true;
|
||||
const gop = try sym.getOrCreateGotEntry(sym_index, self);
|
||||
try self.got.writeEntry(self, gop.index);
|
||||
_ = gop;
|
||||
// try self.got.writeEntry(self, gop.index);
|
||||
}
|
||||
|
||||
if (self.base.child_pid) |pid| {
|
||||
@@ -3070,7 +3202,8 @@ fn updateLazySymbol(self: *Elf, sym: link.File.LazySymbol, symbol_index: Symbol.
|
||||
|
||||
local_sym.flags.needs_got = true;
|
||||
const gop = try local_sym.getOrCreateGotEntry(symbol_index, self);
|
||||
try self.got.writeEntry(self, gop.index);
|
||||
_ = gop;
|
||||
// try self.got.writeEntry(self, gop.index);
|
||||
|
||||
const section_offset = atom_ptr.value - self.phdrs.items[phdr_index].p_vaddr;
|
||||
const file_offset = self.shdrs.items[output_section_index].sh_offset + section_offset;
|
||||
@@ -3480,13 +3613,145 @@ fn initSections(self: *Elf) !void {
|
||||
}
|
||||
}
|
||||
|
||||
if (self.got.entries.items.len > 0 and self.got_section_index == null) {
|
||||
if (self.got.entries.items.len > 0) {
|
||||
self.got_section_index = try self.addSection(.{
|
||||
.name = ".got",
|
||||
.type = elf.SHT_PROGBITS,
|
||||
.flags = elf.SHF_ALLOC | elf.SHF_WRITE,
|
||||
.addralign = ptr_size,
|
||||
});
|
||||
self.got_plt_section_index = try self.addSection(.{
|
||||
.name = ".got.plt",
|
||||
.type = elf.SHT_PROGBITS,
|
||||
.flags = elf.SHF_ALLOC | elf.SHF_WRITE,
|
||||
.addralign = @alignOf(u64),
|
||||
});
|
||||
}
|
||||
|
||||
const needs_rela_dyn = blk: {
|
||||
if (self.got.flags.needs_rela or self.got.flags.needs_tlsld or
|
||||
self.copy_rel.symbols.items.len > 0) break :blk true;
|
||||
for (self.objects.items) |index| {
|
||||
if (self.file(index).?.object.num_dynrelocs > 0) break :blk true;
|
||||
}
|
||||
break :blk false;
|
||||
};
|
||||
if (needs_rela_dyn) {
|
||||
self.rela_dyn_section_index = try self.addSection(.{
|
||||
.name = ".rela.dyn",
|
||||
.type = elf.SHT_RELA,
|
||||
.flags = elf.SHF_ALLOC,
|
||||
.addralign = @alignOf(elf.Elf64_Rela),
|
||||
.entsize = @sizeOf(elf.Elf64_Rela),
|
||||
});
|
||||
}
|
||||
|
||||
if (self.plt.symbols.items.len > 0) {
|
||||
self.plt_section_index = try self.addSection(.{
|
||||
.name = ".plt",
|
||||
.type = elf.SHT_PROGBITS,
|
||||
.flags = elf.SHF_ALLOC | elf.SHF_EXECINSTR,
|
||||
.addralign = 16,
|
||||
});
|
||||
self.rela_plt_section_index = try self.addSection(.{
|
||||
.name = ".rela.plt",
|
||||
.type = elf.SHT_RELA,
|
||||
.flags = elf.SHF_ALLOC,
|
||||
.addralign = @alignOf(elf.Elf64_Rela),
|
||||
.entsize = @sizeOf(elf.Elf64_Rela),
|
||||
});
|
||||
}
|
||||
|
||||
if (self.plt_got.symbols.items.len > 0) {
|
||||
self.plt_got_section_index = try self.addSection(.{
|
||||
.name = ".plt.got",
|
||||
.type = elf.SHT_PROGBITS,
|
||||
.flags = elf.SHF_ALLOC | elf.SHF_EXECINSTR,
|
||||
.addralign = 16,
|
||||
});
|
||||
}
|
||||
|
||||
if (self.copy_rel.symbols.items.len > 0) {
|
||||
self.copy_rel_section_index = try self.addSection(.{
|
||||
.name = ".copyrel",
|
||||
.type = elf.SHT_NOBITS,
|
||||
.flags = elf.SHF_ALLOC | elf.SHF_WRITE,
|
||||
});
|
||||
}
|
||||
|
||||
const needs_interp = blk: {
|
||||
// On Ubuntu with musl-gcc, we get a weird combo of options looking like this:
|
||||
// -dynamic-linker=<path> -static
|
||||
// In this case, if we do generate .interp section and segment, we will get
|
||||
// a segfault in the dynamic linker trying to load a binary that is static
|
||||
// and doesn't contain .dynamic section.
|
||||
if (self.isStatic() and !self.base.options.pie) break :blk false;
|
||||
break :blk self.base.options.dynamic_linker != null;
|
||||
};
|
||||
if (needs_interp) {
|
||||
self.interp_section_index = try self.addSection(.{
|
||||
.name = ".interp",
|
||||
.type = elf.SHT_PROGBITS,
|
||||
.flags = elf.SHF_ALLOC,
|
||||
.addralign = 1,
|
||||
});
|
||||
}
|
||||
|
||||
if (self.isDynLib() or self.shared_objects.items.len > 0 or self.base.options.pie) {
|
||||
self.dynstrtab_section_index = try self.addSection(.{
|
||||
.name = ".dynstr",
|
||||
.flags = elf.SHF_ALLOC,
|
||||
.type = elf.SHT_STRTAB,
|
||||
.entsize = 1,
|
||||
.addralign = 1,
|
||||
});
|
||||
self.dynamic_section_index = try self.addSection(.{
|
||||
.name = ".dynamic",
|
||||
.flags = elf.SHF_ALLOC | elf.SHF_WRITE,
|
||||
.type = elf.SHT_DYNAMIC,
|
||||
.entsize = @sizeOf(elf.Elf64_Dyn),
|
||||
.addralign = @alignOf(elf.Elf64_Dyn),
|
||||
});
|
||||
self.dynsymtab_section_index = try self.addSection(.{
|
||||
.name = ".dynsym",
|
||||
.flags = elf.SHF_ALLOC,
|
||||
.type = elf.SHT_DYNSYM,
|
||||
.addralign = @alignOf(elf.Elf64_Sym),
|
||||
.entsize = @sizeOf(elf.Elf64_Sym),
|
||||
});
|
||||
self.hash_section_index = try self.addSection(.{
|
||||
.name = ".hash",
|
||||
.flags = elf.SHF_ALLOC,
|
||||
.type = elf.SHT_HASH,
|
||||
.addralign = 4,
|
||||
.entsize = 4,
|
||||
});
|
||||
self.gnu_hash_section_index = try self.addSection(.{
|
||||
.name = ".gnu.hash",
|
||||
.flags = elf.SHF_ALLOC,
|
||||
.type = elf.SHT_GNU_HASH,
|
||||
.addralign = 8,
|
||||
});
|
||||
|
||||
const needs_versions = for (self.dynsym.entries.items) |entry| {
|
||||
const sym = self.symbol(entry.symbol_index);
|
||||
if (sym.flags.import and sym.version_index & elf.VERSYM_VERSION > elf.VER_NDX_GLOBAL) break true;
|
||||
} else false;
|
||||
if (needs_versions) {
|
||||
self.versym_section_index = try self.addSection(.{
|
||||
.name = ".gnu.version",
|
||||
.flags = elf.SHF_ALLOC,
|
||||
.type = elf.SHT_GNU_VERSYM,
|
||||
.addralign = @alignOf(elf.Elf64_Versym),
|
||||
.entsize = @sizeOf(elf.Elf64_Versym),
|
||||
});
|
||||
self.verneed_section_index = try self.addSection(.{
|
||||
.name = ".gnu.version_r",
|
||||
.flags = elf.SHF_ALLOC,
|
||||
.type = elf.SHT_GNU_VERNEED,
|
||||
.addralign = @alignOf(elf.Elf64_Verneed),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (self.symtab_section_index == null) {
|
||||
@@ -3665,6 +3930,20 @@ fn sortSections(self: *Elf) !void {
|
||||
&self.symtab_section_index,
|
||||
&self.strtab_section_index,
|
||||
&self.shstrtab_section_index,
|
||||
&self.interp_section_index,
|
||||
&self.dynamic_section_index,
|
||||
&self.dynsymtab_section_index,
|
||||
&self.dynstrtab_section_index,
|
||||
&self.hash_section_index,
|
||||
&self.gnu_hash_section_index,
|
||||
&self.plt_section_index,
|
||||
&self.got_plt_section_index,
|
||||
&self.plt_got_section_index,
|
||||
&self.rela_dyn_section_index,
|
||||
&self.rela_plt_section_index,
|
||||
&self.copy_rel_section_index,
|
||||
&self.versym_section_index,
|
||||
&self.verneed_section_index,
|
||||
}) |maybe_index| {
|
||||
if (maybe_index.*) |*index| {
|
||||
index.* = backlinks[index.*];
|
||||
@@ -3675,6 +3954,47 @@ fn sortSections(self: *Elf) !void {
|
||||
const shdr = &self.shdrs.items[index];
|
||||
shdr.sh_link = self.strtab_section_index.?;
|
||||
}
|
||||
|
||||
if (self.dynamic_section_index) |index| {
|
||||
const shdr = &self.shdrs.items[index];
|
||||
shdr.sh_link = self.dynstrtab_section_index.?;
|
||||
}
|
||||
|
||||
if (self.dynsymtab_section_index) |index| {
|
||||
const shdr = &self.shdrs.items[index];
|
||||
shdr.sh_link = self.dynstrtab_section_index.?;
|
||||
}
|
||||
|
||||
if (self.hash_section_index) |index| {
|
||||
const shdr = &self.shdrs.items[index];
|
||||
shdr.sh_link = self.dynsymtab_section_index.?;
|
||||
}
|
||||
|
||||
if (self.gnu_hash_section_index) |index| {
|
||||
const shdr = &self.shdrs.items[index];
|
||||
shdr.sh_link = self.dynsymtab_section_index.?;
|
||||
}
|
||||
|
||||
if (self.versym_section_index) |index| {
|
||||
const shdr = &self.shdrs.items[index];
|
||||
shdr.sh_link = self.dynsymtab_section_index.?;
|
||||
}
|
||||
|
||||
if (self.verneed_section_index) |index| {
|
||||
const shdr = &self.shdrs.items[index];
|
||||
shdr.sh_link = self.dynstrtab_section_index.?;
|
||||
}
|
||||
|
||||
if (self.rela_dyn_section_index) |index| {
|
||||
const shdr = &self.shdrs.items[index];
|
||||
shdr.sh_link = self.dynsymtab_section_index orelse 0;
|
||||
}
|
||||
|
||||
if (self.rela_plt_section_index) |index| {
|
||||
const shdr = &self.shdrs.items[index];
|
||||
shdr.sh_link = self.dynsymtab_section_index.?;
|
||||
shdr.sh_info = self.plt_section_index.?;
|
||||
}
|
||||
}
|
||||
|
||||
fn updateSectionSizes(self: *Elf) !void {
|
||||
@@ -3683,21 +4003,77 @@ fn updateSectionSizes(self: *Elf) !void {
|
||||
}
|
||||
|
||||
if (self.eh_frame_section_index) |index| {
|
||||
const shdr = &self.shdrs.items[index];
|
||||
shdr.sh_size = try eh_frame.calcEhFrameSize(self);
|
||||
shdr.sh_addralign = @alignOf(u64);
|
||||
self.shdrs.items[index].sh_size = try eh_frame.calcEhFrameSize(self);
|
||||
}
|
||||
|
||||
if (self.eh_frame_hdr_section_index) |index| {
|
||||
const shdr = &self.shdrs.items[index];
|
||||
shdr.sh_size = eh_frame.calcEhFrameHdrSize(self);
|
||||
shdr.sh_addralign = @alignOf(u32);
|
||||
self.shdrs.items[index].sh_size = eh_frame.calcEhFrameHdrSize(self);
|
||||
}
|
||||
|
||||
if (self.got_section_index) |index| {
|
||||
self.shdrs.items[index].sh_size = self.got.size(self);
|
||||
}
|
||||
|
||||
if (self.plt_section_index) |index| {
|
||||
self.shdrs.items[index].sh_size = self.plt.size();
|
||||
}
|
||||
|
||||
if (self.got_plt_section_index) |index| {
|
||||
self.shdrs.items[index].sh_size = self.got_plt.size(self);
|
||||
}
|
||||
|
||||
if (self.plt_got_section_index) |index| {
|
||||
self.shdrs.items[index].sh_size = self.plt_got.size();
|
||||
}
|
||||
|
||||
if (self.rela_dyn_section_index) |shndx| {
|
||||
var num = self.got.numRela(self) + self.copy_rel.numRela();
|
||||
for (self.objects.items) |index| {
|
||||
num += self.file(index).?.object.num_dynrelocs;
|
||||
}
|
||||
self.shdrs.items[shndx].sh_size = num * @sizeOf(elf.Elf64_Rela);
|
||||
}
|
||||
|
||||
if (self.rela_plt_section_index) |index| {
|
||||
self.shdrs.items[index].sh_size = self.plt.numRela() * @sizeOf(elf.Elf64_Rela);
|
||||
}
|
||||
|
||||
if (self.copy_rel_section_index) |index| {
|
||||
try self.copy_rel.updateSectionSize(index, self);
|
||||
}
|
||||
|
||||
if (self.interp_section_index) |index| {
|
||||
self.shdrs.items[index].sh_size = self.base.options.dynamic_linker.?.len + 1;
|
||||
}
|
||||
|
||||
if (self.hash_section_index) |index| {
|
||||
self.shdrs.items[index].sh_size = self.hash.size();
|
||||
}
|
||||
|
||||
if (self.gnu_hash_section_index) |index| {
|
||||
self.shdrs.items[index].sh_size = self.gnu_hash.size();
|
||||
}
|
||||
|
||||
if (self.dynamic_section_index) |index| {
|
||||
self.shdrs.items[index].sh_size = self.dynamic.size(self);
|
||||
}
|
||||
|
||||
if (self.dynsymtab_section_index) |index| {
|
||||
self.shdrs.items[index].sh_size = self.dynsym.size();
|
||||
}
|
||||
|
||||
if (self.dynstrtab_section_index) |index| {
|
||||
self.shdrs.items[index].sh_size = self.dynstrtab.buffer.items.len;
|
||||
}
|
||||
|
||||
if (self.versym_section_index) |index| {
|
||||
self.shdrs.items[index].sh_size = self.versym.items.len * @sizeOf(elf.Elf64_Versym);
|
||||
}
|
||||
|
||||
if (self.verneed_section_index) |index| {
|
||||
self.shdrs.items[index].sh_size = self.verneed.size();
|
||||
}
|
||||
|
||||
if (self.symtab_section_index != null) {
|
||||
try self.updateSymtabSize();
|
||||
}
|
||||
@@ -3708,13 +4084,17 @@ fn updateSectionSizes(self: *Elf) !void {
|
||||
if (self.got_section_index) |_| {
|
||||
try self.got.updateStrtab(self);
|
||||
}
|
||||
if (self.plt_section_index) |_| {
|
||||
try self.plt.updateStrtab(self);
|
||||
}
|
||||
if (self.plt_got_section_index) |_| {
|
||||
try self.plt_got.updateStrtab(self);
|
||||
}
|
||||
self.shdrs.items[index].sh_size = self.strtab.buffer.items.len;
|
||||
// try self.growNonAllocSection(index, self.strtab.buffer.items.len, 1, false);
|
||||
}
|
||||
|
||||
if (self.shstrtab_section_index) |index| {
|
||||
self.shdrs.items[index].sh_size = self.shstrtab.buffer.items.len;
|
||||
// try self.growNonAllocSection(index, self.shstrtab.buffer.items.len, 1, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3729,18 +4109,18 @@ fn initPhdrs(self: *Elf) !void {
|
||||
});
|
||||
|
||||
// Add INTERP phdr if required
|
||||
// if (self.interp_sect_index) |index| {
|
||||
// const shdr = self.sections.items(.shdr)[index];
|
||||
// _ = try self.addPhdr(.{
|
||||
// .type = elf.PT_INTERP,
|
||||
// .flags = elf.PF_R,
|
||||
// .@"align" = 1,
|
||||
// .offset = shdr.sh_offset,
|
||||
// .addr = shdr.sh_addr,
|
||||
// .filesz = shdr.sh_size,
|
||||
// .memsz = shdr.sh_size,
|
||||
// });
|
||||
// }
|
||||
if (self.interp_section_index) |index| {
|
||||
const shdr = self.shdrs.items[index];
|
||||
_ = try self.addPhdr(.{
|
||||
.type = elf.PT_INTERP,
|
||||
.flags = elf.PF_R,
|
||||
.@"align" = 1,
|
||||
.offset = shdr.sh_offset,
|
||||
.addr = shdr.sh_addr,
|
||||
.filesz = shdr.sh_size,
|
||||
.memsz = shdr.sh_size,
|
||||
});
|
||||
}
|
||||
|
||||
// Add LOAD phdrs
|
||||
const slice = self.shdrs.items;
|
||||
@@ -3806,18 +4186,18 @@ fn initPhdrs(self: *Elf) !void {
|
||||
}
|
||||
|
||||
// Add DYNAMIC phdr
|
||||
// if (self.dynamic_sect_index) |index| {
|
||||
// const shdr = self.sections.items(.shdr)[index];
|
||||
// _ = try self.addPhdr(.{
|
||||
// .type = elf.PT_DYNAMIC,
|
||||
// .flags = elf.PF_R | elf.PF_W,
|
||||
// .@"align" = shdr.sh_addralign,
|
||||
// .offset = shdr.sh_offset,
|
||||
// .addr = shdr.sh_addr,
|
||||
// .memsz = shdr.sh_size,
|
||||
// .filesz = shdr.sh_size,
|
||||
// });
|
||||
// }
|
||||
if (self.dynamic_section_index) |index| {
|
||||
const shdr = self.shdrs.items[index];
|
||||
_ = try self.addPhdr(.{
|
||||
.type = elf.PT_DYNAMIC,
|
||||
.flags = elf.PF_R | elf.PF_W,
|
||||
.@"align" = shdr.sh_addralign,
|
||||
.offset = shdr.sh_offset,
|
||||
.addr = shdr.sh_addr,
|
||||
.memsz = shdr.sh_size,
|
||||
.filesz = shdr.sh_size,
|
||||
});
|
||||
}
|
||||
|
||||
// Add PT_GNU_EH_FRAME phdr if required.
|
||||
if (self.eh_frame_hdr_section_index) |index| {
|
||||
@@ -4113,6 +4493,16 @@ fn updateSymtabSize(self: *Elf) !void {
|
||||
sizes.nlocals += self.got.output_symtab_size.nlocals;
|
||||
}
|
||||
|
||||
if (self.plt_section_index) |_| {
|
||||
self.plt.updateSymtabSize(self);
|
||||
sizes.nlocals += self.plt.output_symtab_size.nlocals;
|
||||
}
|
||||
|
||||
if (self.plt_got_section_index) |_| {
|
||||
self.plt_got.updateSymtabSize(self);
|
||||
sizes.nlocals += self.plt_got.output_symtab_size.nlocals;
|
||||
}
|
||||
|
||||
if (self.linker_defined_index) |index| {
|
||||
const linker_defined = self.file(index).?.linker_defined;
|
||||
linker_defined.updateSymtabSize(self);
|
||||
@@ -4127,18 +4517,70 @@ fn updateSymtabSize(self: *Elf) !void {
|
||||
.p32 => @sizeOf(elf.Elf32_Sym),
|
||||
.p64 => @sizeOf(elf.Elf64_Sym),
|
||||
};
|
||||
// const sym_align: u16 = switch (self.ptr_width) {
|
||||
// .p32 => @alignOf(elf.Elf32_Sym),
|
||||
// .p64 => @alignOf(elf.Elf64_Sym),
|
||||
// };
|
||||
const needed_size = (sizes.nlocals + sizes.nglobals + 1) * sym_size;
|
||||
shdr.sh_size = needed_size;
|
||||
// try self.growNonAllocSection(self.symtab_section_index.?, needed_size, sym_align, false);
|
||||
}
|
||||
|
||||
fn writeSyntheticSections(self: *Elf) !void {
|
||||
const gpa = self.base.allocator;
|
||||
|
||||
if (self.interp_section_index) |shndx| {
|
||||
const shdr = self.shdrs.items[shndx];
|
||||
var buffer = try gpa.alloc(u8, shdr.sh_size);
|
||||
defer gpa.free(buffer);
|
||||
const dylinker = self.base.options.dynamic_linker.?;
|
||||
@memcpy(buffer[0..dylinker.len], dylinker);
|
||||
buffer[dylinker.len] = 0;
|
||||
try self.base.file.?.pwriteAll(buffer, shdr.sh_offset);
|
||||
}
|
||||
|
||||
if (self.hash_section_index) |shndx| {
|
||||
const shdr = self.shdrs.items[shndx];
|
||||
try self.base.file.?.pwriteAll(self.hash.buffer.items, shdr.sh_offset);
|
||||
}
|
||||
|
||||
if (self.gnu_hash_section_index) |shndx| {
|
||||
const shdr = self.shdrs.items[shndx];
|
||||
var buffer = try std.ArrayList(u8).initCapacity(gpa, self.gnu_hash.size());
|
||||
defer buffer.deinit();
|
||||
try self.gnu_hash.write(self, buffer.writer());
|
||||
try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset);
|
||||
}
|
||||
|
||||
if (self.versym_section_index) |shndx| {
|
||||
const shdr = self.shdrs.items[shndx];
|
||||
try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.versym.items), shdr.sh_offset);
|
||||
}
|
||||
|
||||
if (self.verneed_section_index) |shndx| {
|
||||
const shdr = self.shdrs.items[shndx];
|
||||
var buffer = try std.ArrayList(u8).initCapacity(gpa, self.verneed.size());
|
||||
defer buffer.deinit();
|
||||
try self.verneed.write(buffer.writer());
|
||||
try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset);
|
||||
}
|
||||
|
||||
if (self.dynamic_section_index) |shndx| {
|
||||
const shdr = self.shdrs.items[shndx];
|
||||
var buffer = try std.ArrayList(u8).initCapacity(gpa, self.dynamic.size(self));
|
||||
defer buffer.deinit();
|
||||
try self.dynamic.write(self, buffer.writer());
|
||||
try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset);
|
||||
}
|
||||
|
||||
if (self.dynsymtab_section_index) |shndx| {
|
||||
const shdr = self.shdrs.items[shndx];
|
||||
var buffer = try std.ArrayList(u8).initCapacity(gpa, self.dynsym.size());
|
||||
defer buffer.deinit();
|
||||
try self.dynsym.write(self, buffer.writer());
|
||||
try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset);
|
||||
}
|
||||
|
||||
if (self.dynstrtab_section_index) |shndx| {
|
||||
const shdr = self.shdrs.items[shndx];
|
||||
try self.base.file.?.pwriteAll(self.dynstrtab.buffer.items, shdr.sh_offset);
|
||||
}
|
||||
|
||||
if (self.eh_frame_section_index) |shndx| {
|
||||
const shdr = self.shdrs.items[shndx];
|
||||
var buffer = try std.ArrayList(u8).initCapacity(gpa, shdr.sh_size);
|
||||
@@ -4163,6 +4605,44 @@ fn writeSyntheticSections(self: *Elf) !void {
|
||||
try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset);
|
||||
}
|
||||
|
||||
if (self.rela_dyn_section_index) |shndx| {
|
||||
const shdr = self.shdrs.items[shndx];
|
||||
try self.got.addRela(self);
|
||||
try self.copy_rel.addRela(self);
|
||||
self.sortRelaDyn();
|
||||
try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.rela_dyn.items), shdr.sh_offset);
|
||||
}
|
||||
|
||||
if (self.plt_section_index) |shndx| {
|
||||
const shdr = self.shdrs.items[shndx];
|
||||
var buffer = try std.ArrayList(u8).initCapacity(gpa, self.plt.size());
|
||||
defer buffer.deinit();
|
||||
try self.plt.write(self, buffer.writer());
|
||||
try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset);
|
||||
}
|
||||
|
||||
if (self.got_plt_section_index) |shndx| {
|
||||
const shdr = self.shdrs.items[shndx];
|
||||
var buffer = try std.ArrayList(u8).initCapacity(gpa, self.got_plt.size(self));
|
||||
defer buffer.deinit();
|
||||
try self.got_plt.write(self, buffer.writer());
|
||||
try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset);
|
||||
}
|
||||
|
||||
if (self.plt_got_section_index) |shndx| {
|
||||
const shdr = self.shdrs.items[shndx];
|
||||
var buffer = try std.ArrayList(u8).initCapacity(gpa, self.plt_got.size());
|
||||
defer buffer.deinit();
|
||||
try self.plt_got.write(self, buffer.writer());
|
||||
try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset);
|
||||
}
|
||||
|
||||
if (self.rela_plt_section_index) |shndx| {
|
||||
const shdr = self.shdrs.items[shndx];
|
||||
try self.plt.addRela(self);
|
||||
try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.rela_plt.items), shdr.sh_offset);
|
||||
}
|
||||
|
||||
if (self.shstrtab_section_index) |index| {
|
||||
const shdr = self.shdrs.items[index];
|
||||
try self.base.file.?.pwriteAll(self.shstrtab.buffer.items, shdr.sh_offset);
|
||||
@@ -4213,11 +4693,27 @@ fn writeSymtab(self: *Elf) !void {
|
||||
ctx.iglobal += object.output_symtab_size.nglobals;
|
||||
}
|
||||
|
||||
for (self.shared_objects.items) |index| {
|
||||
const shared_object = self.file(index).?.shared_object;
|
||||
shared_object.writeSymtab(self, ctx);
|
||||
ctx.iglobal += shared_object.output_symtab_size.nglobals;
|
||||
}
|
||||
|
||||
if (self.got_section_index) |_| {
|
||||
try self.got.writeSymtab(self, ctx);
|
||||
ctx.ilocal += self.got.output_symtab_size.nlocals;
|
||||
}
|
||||
|
||||
if (self.plt_section_index) |_| {
|
||||
try self.plt.writeSymtab(self, ctx);
|
||||
ctx.ilocal += self.plt.output_symtab_size.nlocals;
|
||||
}
|
||||
|
||||
if (self.plt_got_section_index) |_| {
|
||||
try self.plt_got.writeSymtab(self, ctx);
|
||||
ctx.ilocal += self.plt_got.output_symtab_size.nlocals;
|
||||
}
|
||||
|
||||
if (self.linker_defined_index) |index| {
|
||||
const linker_defined = self.file(index).?.linker_defined;
|
||||
linker_defined.writeSymtab(self, ctx);
|
||||
@@ -4576,7 +5072,7 @@ pub fn isStatic(self: Elf) bool {
|
||||
}
|
||||
|
||||
pub fn isDynLib(self: Elf) bool {
|
||||
return self.base.options.output_mode == .Lib and self.base.options.link_mode == .Dynamic;
|
||||
return self.base.options.effectiveOutputMode() == .Lib and self.base.options.link_mode == .Dynamic;
|
||||
}
|
||||
|
||||
fn addPhdr(self: *Elf, opts: struct {
|
||||
@@ -4723,6 +5219,7 @@ pub fn file(self: *Elf, index: File.Index) ?File {
|
||||
.linker_defined => .{ .linker_defined = &self.files.items(.data)[index].linker_defined },
|
||||
.zig_module => .{ .zig_module = &self.files.items(.data)[index].zig_module },
|
||||
.object => .{ .object = &self.files.items(.data)[index].object },
|
||||
.shared_object => .{ .shared_object = &self.files.items(.data)[index].shared_object },
|
||||
};
|
||||
}
|
||||
|
||||
@@ -5077,6 +5574,16 @@ fn fmtDumpState(
|
||||
});
|
||||
}
|
||||
|
||||
for (self.shared_objects.items) |index| {
|
||||
const shared_object = self.file(index).?.shared_object;
|
||||
try writer.print("shared_object({d}) : ", .{index});
|
||||
try writer.print("{s}", .{shared_object.path});
|
||||
try writer.print(" : needed({})", .{shared_object.needed});
|
||||
if (!shared_object.alive) try writer.writeAll(" : [*]");
|
||||
try writer.writeByte('\n');
|
||||
try writer.print("{}\n", .{shared_object.fmtSymtab(self)});
|
||||
}
|
||||
|
||||
if (self.linker_defined_index) |index| {
|
||||
const linker_defined = self.file(index).?.linker_defined;
|
||||
try writer.print("linker_defined({d}) : (linker defined)\n", .{index});
|
||||
@@ -5227,10 +5734,16 @@ const Archive = @import("Elf/Archive.zig");
|
||||
pub const Atom = @import("Elf/Atom.zig");
|
||||
const Cache = std.Build.Cache;
|
||||
const Compilation = @import("../Compilation.zig");
|
||||
const CopyRelSection = synthetic_sections.CopyRelSection;
|
||||
const DynamicSection = synthetic_sections.DynamicSection;
|
||||
const DynsymSection = synthetic_sections.DynsymSection;
|
||||
const Dwarf = @import("Dwarf.zig");
|
||||
const Elf = @This();
|
||||
const File = @import("Elf/file.zig").File;
|
||||
const GnuHashSection = synthetic_sections.GnuHashSection;
|
||||
const GotSection = synthetic_sections.GotSection;
|
||||
const GotPltSection = synthetic_sections.GotPltSection;
|
||||
const HashSection = synthetic_sections.HashSection;
|
||||
const LinkerDefined = @import("Elf/LinkerDefined.zig");
|
||||
const Liveness = @import("../Liveness.zig");
|
||||
const LlvmObject = @import("../codegen/llvm.zig").Object;
|
||||
@@ -5238,10 +5751,14 @@ const Module = @import("../Module.zig");
|
||||
const Object = @import("Elf/Object.zig");
|
||||
const InternPool = @import("../InternPool.zig");
|
||||
const Package = @import("../Package.zig");
|
||||
const PltSection = synthetic_sections.PltSection;
|
||||
const PltGotSection = synthetic_sections.PltGotSection;
|
||||
const SharedObject = @import("Elf/SharedObject.zig");
|
||||
const Symbol = @import("Elf/Symbol.zig");
|
||||
const StringTable = @import("strtab.zig").StringTable;
|
||||
const TableSection = @import("table_section.zig").TableSection;
|
||||
const Type = @import("../type.zig").Type;
|
||||
const TypedValue = @import("../TypedValue.zig");
|
||||
const Value = @import("../value.zig").Value;
|
||||
const VerneedSection = synthetic_sections.VerneedSection;
|
||||
const ZigModule = @import("Elf/ZigModule.zig");
|
||||
|
||||
361
src/link/Elf/SharedObject.zig
Normal file
361
src/link/Elf/SharedObject.zig
Normal file
@@ -0,0 +1,361 @@
|
||||
path: []const u8,
|
||||
data: []const u8,
|
||||
index: File.Index,
|
||||
|
||||
header: ?elf.Elf64_Ehdr = null,
|
||||
shdrs: std.ArrayListUnmanaged(ElfShdr) = .{},
|
||||
symtab: []align(1) const elf.Elf64_Sym = &[0]elf.Elf64_Sym{},
|
||||
strtab: []const u8 = &[0]u8{},
|
||||
/// Version symtab contains version strings of the symbols if present.
|
||||
versyms: std.ArrayListUnmanaged(elf.Elf64_Versym) = .{},
|
||||
verstrings: std.ArrayListUnmanaged(u32) = .{},
|
||||
|
||||
dynamic_sect_index: ?u16 = null,
|
||||
versym_sect_index: ?u16 = null,
|
||||
verdef_sect_index: ?u16 = null,
|
||||
|
||||
symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
|
||||
aliases: ?std.ArrayListUnmanaged(u32) = null,
|
||||
|
||||
needed: bool,
|
||||
alive: bool,
|
||||
|
||||
output_symtab_size: Elf.SymtabSize = .{},
|
||||
|
||||
pub fn isSharedObject(file: std.fs.File) bool {
|
||||
const reader = file.reader();
|
||||
const header = reader.readStruct(elf.Elf64_Ehdr) catch return false;
|
||||
defer file.seekTo(0) catch {};
|
||||
if (!mem.eql(u8, header.e_ident[0..4], "\x7fELF")) return false;
|
||||
if (header.e_ident[elf.EI_VERSION] != 1) return false;
|
||||
if (header.e_type != elf.ET.DYN) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
pub fn deinit(self: *SharedObject, allocator: Allocator) void {
|
||||
self.versyms.deinit(allocator);
|
||||
self.verstrings.deinit(allocator);
|
||||
self.symbols.deinit(allocator);
|
||||
if (self.aliases) |*aliases| aliases.deinit(allocator);
|
||||
self.shdrs.deinit(allocator);
|
||||
}
|
||||
|
||||
pub fn parse(self: *SharedObject, elf_file: *Elf) !void {
|
||||
const gpa = elf_file.base.allocator;
|
||||
var stream = std.io.fixedBufferStream(self.data);
|
||||
const reader = stream.reader();
|
||||
|
||||
self.header = try reader.readStruct(elf.Elf64_Ehdr);
|
||||
|
||||
var dynsym_index: ?u16 = null;
|
||||
const shdrs = @as(
|
||||
[*]align(1) const elf.Elf64_Shdr,
|
||||
@ptrCast(self.data.ptr + self.header.?.e_shoff),
|
||||
)[0..self.header.?.e_shnum];
|
||||
try self.shdrs.ensureTotalCapacityPrecise(gpa, shdrs.len);
|
||||
|
||||
for (shdrs, 0..) |shdr, i| {
|
||||
self.shdrs.appendAssumeCapacity(try ElfShdr.fromElf64Shdr(shdr));
|
||||
switch (shdr.sh_type) {
|
||||
elf.SHT_DYNSYM => dynsym_index = @as(u16, @intCast(i)),
|
||||
elf.SHT_DYNAMIC => self.dynamic_sect_index = @as(u16, @intCast(i)),
|
||||
elf.SHT_GNU_VERSYM => self.versym_sect_index = @as(u16, @intCast(i)),
|
||||
elf.SHT_GNU_VERDEF => self.verdef_sect_index = @as(u16, @intCast(i)),
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
|
||||
if (dynsym_index) |index| {
|
||||
const shdr = self.shdrs.items[index];
|
||||
const symtab = self.shdrContents(index);
|
||||
const nsyms = @divExact(symtab.len, @sizeOf(elf.Elf64_Sym));
|
||||
self.symtab = @as([*]align(1) const elf.Elf64_Sym, @ptrCast(symtab.ptr))[0..nsyms];
|
||||
self.strtab = self.shdrContents(@as(u16, @intCast(shdr.sh_link)));
|
||||
}
|
||||
|
||||
try self.parseVersions(elf_file);
|
||||
try self.initSymtab(elf_file);
|
||||
}
|
||||
|
||||
fn parseVersions(self: *SharedObject, elf_file: *Elf) !void {
|
||||
const gpa = elf_file.base.allocator;
|
||||
|
||||
try self.verstrings.resize(gpa, 2);
|
||||
self.verstrings.items[elf.VER_NDX_LOCAL] = 0;
|
||||
self.verstrings.items[elf.VER_NDX_GLOBAL] = 0;
|
||||
|
||||
if (self.verdef_sect_index) |shndx| {
|
||||
const verdefs = self.shdrContents(shndx);
|
||||
const nverdefs = self.verdefNum();
|
||||
try self.verstrings.resize(gpa, self.verstrings.items.len + nverdefs);
|
||||
|
||||
var i: u32 = 0;
|
||||
var offset: u32 = 0;
|
||||
while (i < nverdefs) : (i += 1) {
|
||||
const verdef = @as(*align(1) const elf.Elf64_Verdef, @ptrCast(verdefs.ptr + offset)).*;
|
||||
defer offset += verdef.vd_next;
|
||||
if (verdef.vd_flags == elf.VER_FLG_BASE) continue; // Skip BASE entry
|
||||
const vda_name = if (verdef.vd_cnt > 0)
|
||||
@as(*align(1) const elf.Elf64_Verdaux, @ptrCast(verdefs.ptr + offset + verdef.vd_aux)).vda_name
|
||||
else
|
||||
0;
|
||||
self.verstrings.items[verdef.vd_ndx] = vda_name;
|
||||
}
|
||||
}
|
||||
|
||||
try self.versyms.ensureTotalCapacityPrecise(gpa, self.symtab.len);
|
||||
|
||||
if (self.versym_sect_index) |shndx| {
|
||||
const versyms_raw = self.shdrContents(shndx);
|
||||
const nversyms = @divExact(versyms_raw.len, @sizeOf(elf.Elf64_Versym));
|
||||
const versyms = @as([*]align(1) const elf.Elf64_Versym, @ptrCast(versyms_raw.ptr))[0..nversyms];
|
||||
for (versyms) |ver| {
|
||||
const normalized_ver = if (ver & elf.VERSYM_VERSION >= self.verstrings.items.len - 1)
|
||||
elf.VER_NDX_GLOBAL
|
||||
else
|
||||
ver;
|
||||
self.versyms.appendAssumeCapacity(normalized_ver);
|
||||
}
|
||||
} else for (0..self.symtab.len) |_| {
|
||||
self.versyms.appendAssumeCapacity(elf.VER_NDX_GLOBAL);
|
||||
}
|
||||
}
|
||||
|
||||
fn initSymtab(self: *SharedObject, elf_file: *Elf) !void {
|
||||
const gpa = elf_file.base.allocator;
|
||||
|
||||
try self.symbols.ensureTotalCapacityPrecise(gpa, self.symtab.len);
|
||||
|
||||
for (self.symtab, 0..) |sym, i| {
|
||||
const hidden = self.versyms.items[i] & elf.VERSYM_HIDDEN != 0;
|
||||
const name = self.getString(sym.st_name);
|
||||
// We need to garble up the name so that we don't pick this symbol
|
||||
// during symbol resolution. Thank you GNU!
|
||||
const off = if (hidden) blk: {
|
||||
const full_name = try std.fmt.allocPrint(gpa, "{s}@{s}", .{
|
||||
name,
|
||||
self.versionString(self.versyms.items[i]),
|
||||
});
|
||||
defer gpa.free(full_name);
|
||||
break :blk try elf_file.strtab.insert(gpa, full_name);
|
||||
} else try elf_file.strtab.insert(gpa, name);
|
||||
const gop = try elf_file.getOrCreateGlobal(off);
|
||||
self.symbols.addOneAssumeCapacity().* = gop.index;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn resolveSymbols(self: *SharedObject, elf_file: *Elf) void {
|
||||
for (self.globals(), 0..) |index, i| {
|
||||
const esym_index = @as(u32, @intCast(i));
|
||||
const this_sym = self.symtab[esym_index];
|
||||
|
||||
if (this_sym.st_shndx == elf.SHN_UNDEF) continue;
|
||||
|
||||
const global = elf_file.symbol(index);
|
||||
if (self.asFile().symbolRank(this_sym, false) < global.symbolRank(elf_file)) {
|
||||
global.value = this_sym.st_value;
|
||||
global.atom_index = 0;
|
||||
global.esym_index = esym_index;
|
||||
global.version_index = self.versyms.items[esym_index];
|
||||
global.file_index = self.index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn resetGlobals(self: *SharedObject, elf_file: *Elf) void {
|
||||
for (self.globals()) |index| {
|
||||
const global = elf_file.symbol(index);
|
||||
const off = global.name_offset;
|
||||
global.* = .{};
|
||||
global.name_offset = off;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn markLive(self: *SharedObject, elf_file: *Elf) void {
|
||||
for (self.globals(), 0..) |index, i| {
|
||||
const sym = self.symtab[i];
|
||||
if (sym.st_shndx != elf.SHN_UNDEF) continue;
|
||||
|
||||
const global = elf_file.symbol(index);
|
||||
const file = global.file(elf_file) orelse continue;
|
||||
const should_drop = switch (file) {
|
||||
.shared_object => |sh| !sh.needed and sym.st_bind() == elf.STB_WEAK,
|
||||
else => false,
|
||||
};
|
||||
if (!should_drop and !file.isAlive()) {
|
||||
file.setAlive();
|
||||
file.markLive(elf_file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn updateSymtabSize(self: *SharedObject, elf_file: *Elf) void {
|
||||
for (self.globals()) |global_index| {
|
||||
const global = elf_file.symbol(global_index);
|
||||
if (global.file(elf_file)) |file| if (file.index() != self.index) continue;
|
||||
if (global.isLocal()) continue;
|
||||
global.flags.output_symtab = true;
|
||||
self.output_symtab_size.nglobals += 1;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn writeSymtab(self: *SharedObject, elf_file: *Elf, ctx: anytype) void {
|
||||
var iglobal = ctx.iglobal;
|
||||
for (self.globals()) |global_index| {
|
||||
const global = elf_file.symbol(global_index);
|
||||
if (global.file(elf_file)) |file| if (file.index() != self.index) continue;
|
||||
if (!global.flags.output_symtab) continue;
|
||||
global.setOutputSym(elf_file, &ctx.symtab[iglobal]);
|
||||
iglobal += 1;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn globals(self: SharedObject) []const Symbol.Index {
|
||||
return self.symbols.items;
|
||||
}
|
||||
|
||||
pub fn shdrContents(self: SharedObject, index: u16) []const u8 {
|
||||
const shdr = self.shdrs.items[index];
|
||||
return self.data[shdr.sh_offset..][0..shdr.sh_size];
|
||||
}
|
||||
|
||||
pub fn getString(self: SharedObject, off: u32) [:0]const u8 {
|
||||
assert(off < self.strtab.len);
|
||||
return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.strtab.ptr + off)), 0);
|
||||
}
|
||||
|
||||
pub fn versionString(self: SharedObject, index: elf.Elf64_Versym) [:0]const u8 {
|
||||
const off = self.verstrings.items[index & elf.VERSYM_VERSION];
|
||||
return self.getString(off);
|
||||
}
|
||||
|
||||
pub fn asFile(self: *SharedObject) File {
|
||||
return .{ .shared_object = self };
|
||||
}
|
||||
|
||||
fn dynamicTable(self: *SharedObject) []align(1) const elf.Elf64_Dyn {
|
||||
const shndx = self.dynamic_sect_index orelse return &[0]elf.Elf64_Dyn{};
|
||||
const raw = self.shdrContents(shndx);
|
||||
const num = @divExact(raw.len, @sizeOf(elf.Elf64_Dyn));
|
||||
return @as([*]align(1) const elf.Elf64_Dyn, @ptrCast(raw.ptr))[0..num];
|
||||
}
|
||||
|
||||
fn verdefNum(self: *SharedObject) u32 {
|
||||
const entries = self.dynamicTable();
|
||||
for (entries) |entry| switch (entry.d_tag) {
|
||||
elf.DT_VERDEFNUM => return @as(u32, @intCast(entry.d_val)),
|
||||
else => {},
|
||||
};
|
||||
return 0;
|
||||
}
|
||||
|
||||
pub fn soname(self: *SharedObject) []const u8 {
|
||||
const entries = self.dynamicTable();
|
||||
for (entries) |entry| switch (entry.d_tag) {
|
||||
elf.DT_SONAME => return self.getString(@as(u32, @intCast(entry.d_val))),
|
||||
else => {},
|
||||
};
|
||||
return std.fs.path.basename(self.path);
|
||||
}
|
||||
|
||||
pub fn initSymbolAliases(self: *SharedObject, elf_file: *Elf) !void {
|
||||
assert(self.aliases == null);
|
||||
|
||||
const SortAlias = struct {
|
||||
pub fn lessThan(ctx: *Elf, lhs: Symbol.Index, rhs: Symbol.Index) bool {
|
||||
const lhs_sym = ctx.symbol(lhs).elfSym(ctx);
|
||||
const rhs_sym = ctx.symbol(rhs).elfSym(ctx);
|
||||
return lhs_sym.st_value < rhs_sym.st_value;
|
||||
}
|
||||
};
|
||||
|
||||
const gpa = elf_file.base.allocator;
|
||||
var aliases = std.ArrayList(Symbol.Index).init(gpa);
|
||||
defer aliases.deinit();
|
||||
try aliases.ensureTotalCapacityPrecise(self.globals().len);
|
||||
|
||||
for (self.globals()) |index| {
|
||||
const global = elf_file.symbol(index);
|
||||
const global_file = global.file(elf_file) orelse continue;
|
||||
if (global_file.index() != self.index) continue;
|
||||
aliases.appendAssumeCapacity(index);
|
||||
}
|
||||
|
||||
std.mem.sort(u32, aliases.items, elf_file, SortAlias.lessThan);
|
||||
|
||||
self.aliases = aliases.moveToUnmanaged();
|
||||
}
|
||||
|
||||
pub fn symbolAliases(self: *SharedObject, index: u32, elf_file: *Elf) []const u32 {
|
||||
assert(self.aliases != null);
|
||||
|
||||
const symbol = elf_file.symbol(index).elfSym(elf_file);
|
||||
const aliases = self.aliases.?;
|
||||
|
||||
const start = for (aliases.items, 0..) |alias, i| {
|
||||
const alias_sym = elf_file.symbol(alias).elfSym(elf_file);
|
||||
if (symbol.st_value == alias_sym.st_value) break i;
|
||||
} else aliases.items.len;
|
||||
|
||||
const end = for (aliases.items[start..], 0..) |alias, i| {
|
||||
const alias_sym = elf_file.symbol(alias).elfSym(elf_file);
|
||||
if (symbol.st_value < alias_sym.st_value) break i + start;
|
||||
} else aliases.items.len;
|
||||
|
||||
return aliases.items[start..end];
|
||||
}
|
||||
|
||||
pub fn format(
|
||||
self: SharedObject,
|
||||
comptime unused_fmt_string: []const u8,
|
||||
options: std.fmt.FormatOptions,
|
||||
writer: anytype,
|
||||
) !void {
|
||||
_ = self;
|
||||
_ = unused_fmt_string;
|
||||
_ = options;
|
||||
_ = writer;
|
||||
@compileError("do not format shared objects directly");
|
||||
}
|
||||
|
||||
pub fn fmtSymtab(self: SharedObject, elf_file: *Elf) std.fmt.Formatter(formatSymtab) {
|
||||
return .{ .data = .{
|
||||
.shared = self,
|
||||
.elf_file = elf_file,
|
||||
} };
|
||||
}
|
||||
|
||||
const FormatContext = struct {
|
||||
shared: SharedObject,
|
||||
elf_file: *Elf,
|
||||
};
|
||||
|
||||
fn formatSymtab(
|
||||
ctx: FormatContext,
|
||||
comptime unused_fmt_string: []const u8,
|
||||
options: std.fmt.FormatOptions,
|
||||
writer: anytype,
|
||||
) !void {
|
||||
_ = unused_fmt_string;
|
||||
_ = options;
|
||||
const shared = ctx.shared;
|
||||
try writer.writeAll(" globals\n");
|
||||
for (shared.symbols.items) |index| {
|
||||
const global = ctx.elf_file.symbol(index);
|
||||
try writer.print(" {}\n", .{global.fmt(ctx.elf_file)});
|
||||
}
|
||||
}
|
||||
|
||||
const SharedObject = @This();
|
||||
|
||||
const std = @import("std");
|
||||
const assert = std.debug.assert;
|
||||
const elf = std.elf;
|
||||
const log = std.log.scoped(.elf);
|
||||
const mem = std.mem;
|
||||
|
||||
const Allocator = mem.Allocator;
|
||||
const Elf = @import("../Elf.zig");
|
||||
const ElfShdr = @import("Object.zig").ElfShdr;
|
||||
const File = @import("file.zig").File;
|
||||
const Symbol = @import("Symbol.zig");
|
||||
@@ -32,7 +32,7 @@ extra_index: u32 = 0,
|
||||
|
||||
pub fn isAbs(symbol: Symbol, elf_file: *Elf) bool {
|
||||
const file_ptr = symbol.file(elf_file).?;
|
||||
// if (file_ptr == .shared) return symbol.sourceSymbol(elf_file).st_shndx == elf.SHN_ABS;
|
||||
if (file_ptr == .shared_object) return symbol.elfSym(elf_file).st_shndx == elf.SHN_ABS;
|
||||
return !symbol.flags.import and symbol.atom(elf_file) == null and symbol.outputShndx() == null and
|
||||
file_ptr != .linker_defined;
|
||||
}
|
||||
@@ -52,8 +52,8 @@ pub fn isIFunc(symbol: Symbol, elf_file: *Elf) bool {
|
||||
|
||||
pub fn @"type"(symbol: Symbol, elf_file: *Elf) u4 {
|
||||
const s_sym = symbol.elfSym(elf_file);
|
||||
// const file_ptr = symbol.file(elf_file).?;
|
||||
// if (s_sym.st_type() == elf.STT_GNU_IFUNC and file_ptr == .shared) return elf.STT_FUNC;
|
||||
const file_ptr = symbol.file(elf_file).?;
|
||||
if (s_sym.st_type() == elf.STT_GNU_IFUNC and file_ptr == .shared_object) return elf.STT_FUNC;
|
||||
return s_sym.st_type();
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ pub fn elfSym(symbol: Symbol, elf_file: *Elf) elf.Elf64_Sym {
|
||||
switch (file_ptr) {
|
||||
.zig_module => |x| return x.elfSym(symbol.esym_index).*,
|
||||
.linker_defined => |x| return x.symtab.items[symbol.esym_index],
|
||||
.object => |x| return x.symtab[symbol.esym_index],
|
||||
inline else => |x| return x.symtab[symbol.esym_index],
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,23 +88,18 @@ pub fn symbolRank(symbol: Symbol, elf_file: *Elf) u32 {
|
||||
return file_ptr.symbolRank(sym, in_archive);
|
||||
}
|
||||
|
||||
pub fn address(symbol: Symbol, opts: struct {
|
||||
plt: bool = true,
|
||||
}, elf_file: *Elf) u64 {
|
||||
_ = elf_file;
|
||||
_ = opts;
|
||||
// if (symbol.flags.copy_rel) {
|
||||
// return elf_file.sectionAddress(elf_file.copy_rel_sect_index.?) + symbol.value;
|
||||
// }
|
||||
// if (symbol.flags.plt and opts.plt) {
|
||||
// const extra = symbol.getExtra(elf_file).?;
|
||||
// if (!symbol.flags.is_canonical and symbol.flags.got) {
|
||||
// // We have a non-lazy bound function pointer, use that!
|
||||
// return elf_file.getPltGotEntryAddress(extra.plt_got);
|
||||
// }
|
||||
// // Lazy-bound function it is!
|
||||
// return elf_file.getPltEntryAddress(extra.plt);
|
||||
// }
|
||||
pub fn address(symbol: Symbol, opts: struct { plt: bool = true }, elf_file: *Elf) u64 {
|
||||
if (symbol.flags.has_copy_rel) {
|
||||
return symbol.copyRelAddress(elf_file);
|
||||
}
|
||||
if (symbol.flags.has_plt and opts.plt) {
|
||||
if (!symbol.flags.is_canonical and symbol.flags.has_got) {
|
||||
// We have a non-lazy bound function pointer, use that!
|
||||
return symbol.pltGotAddress(elf_file);
|
||||
}
|
||||
// Lazy-bound function it is!
|
||||
return symbol.pltAddress(elf_file);
|
||||
}
|
||||
return symbol.value;
|
||||
}
|
||||
|
||||
@@ -115,6 +110,33 @@ pub fn gotAddress(symbol: Symbol, elf_file: *Elf) u64 {
|
||||
return entry.address(elf_file);
|
||||
}
|
||||
|
||||
pub fn pltGotAddress(symbol: Symbol, elf_file: *Elf) u64 {
|
||||
if (!(symbol.flags.has_plt and symbol.flags.has_got and !symbol.flags.is_canonical)) return 0;
|
||||
const extras = symbol.extra(elf_file).?;
|
||||
const shdr = elf_file.shdrs.items[elf_file.plt_got_section_index.?];
|
||||
return shdr.sh_addr + extras.plt_got * 16;
|
||||
}
|
||||
|
||||
pub fn pltAddress(symbol: Symbol, elf_file: *Elf) u64 {
|
||||
if (!symbol.flags.has_plt) return 0;
|
||||
const extras = symbol.extra(elf_file).?;
|
||||
const shdr = elf_file.shdrs.items[elf_file.plt_section_index.?];
|
||||
return shdr.sh_addr + extras.plt * 16 + PltSection.preamble_size;
|
||||
}
|
||||
|
||||
pub fn gotPltAddress(symbol: Symbol, elf_file: *Elf) u64 {
|
||||
if (!symbol.flags.has_plt) return 0;
|
||||
const extras = symbol.extra(elf_file).?;
|
||||
const shdr = elf_file.shdrs.items[elf_file.got_plt_section_index.?];
|
||||
return shdr.sh_addr + extras.plt * 8 + GotPltSection.preamble_size;
|
||||
}
|
||||
|
||||
pub fn copyRelAddress(symbol: Symbol, elf_file: *Elf) u64 {
|
||||
if (!symbol.flags.has_copy_rel) return 0;
|
||||
const shdr = elf_file.shdrs.items[elf_file.copy_rel_section_index.?];
|
||||
return shdr.sh_addr + symbol.value;
|
||||
}
|
||||
|
||||
const GetOrCreateGotEntryResult = struct {
|
||||
found_existing: bool,
|
||||
index: GotSection.Index,
|
||||
@@ -149,17 +171,18 @@ pub fn tlsDescAddress(symbol: Symbol, elf_file: *Elf) u64 {
|
||||
return entry.address(elf_file);
|
||||
}
|
||||
|
||||
// pub fn alignment(symbol: Symbol, elf_file: *Elf) !u64 {
|
||||
// const file = symbol.getFile(elf_file) orelse return 0;
|
||||
// const shared = file.shared;
|
||||
// const s_sym = symbol.getSourceSymbol(elf_file);
|
||||
// const shdr = shared.getShdrs()[s_sym.st_shndx];
|
||||
// const alignment = @max(1, shdr.sh_addralign);
|
||||
// return if (s_sym.st_value == 0)
|
||||
// alignment
|
||||
// else
|
||||
// @min(alignment, try std.math.powi(u64, 2, @ctz(s_sym.st_value)));
|
||||
// }
|
||||
pub fn dsoAlignment(symbol: Symbol, elf_file: *Elf) !u64 {
|
||||
const file_ptr = symbol.file(elf_file) orelse return 0;
|
||||
assert(file_ptr == .shared_object);
|
||||
const shared_object = file_ptr.shared_object;
|
||||
const esym = symbol.elfSym(elf_file);
|
||||
const shdr = shared_object.shdrs.items[esym.st_shndx];
|
||||
const alignment = @max(1, shdr.sh_addralign);
|
||||
return if (esym.st_value == 0)
|
||||
alignment
|
||||
else
|
||||
@min(alignment, try std.math.powi(u64, 2, @ctz(esym.st_value)));
|
||||
}
|
||||
|
||||
pub fn addExtra(symbol: *Symbol, extras: Extra, elf_file: *Elf) !void {
|
||||
symbol.extra_index = try elf_file.addSymbolExtra(extras);
|
||||
@@ -183,22 +206,22 @@ pub fn setOutputSym(symbol: Symbol, elf_file: *Elf, out: *elf.Elf64_Sym) void {
|
||||
const st_bind: u8 = blk: {
|
||||
if (symbol.isLocal()) break :blk 0;
|
||||
if (symbol.flags.weak) break :blk elf.STB_WEAK;
|
||||
// if (file_ptr == .shared) break :blk elf.STB_GLOBAL;
|
||||
if (file_ptr == .shared_object) break :blk elf.STB_GLOBAL;
|
||||
break :blk esym.st_bind();
|
||||
};
|
||||
const st_shndx = blk: {
|
||||
// if (symbol.flags.copy_rel) break :blk elf_file.copy_rel_sect_index.?;
|
||||
// if (file_ptr == .shared or s_sym.st_shndx == elf.SHN_UNDEF) break :blk elf.SHN_UNDEF;
|
||||
if (symbol.flags.has_copy_rel) break :blk elf_file.copy_rel_section_index.?;
|
||||
if (file_ptr == .shared_object or esym.st_shndx == elf.SHN_UNDEF) break :blk elf.SHN_UNDEF;
|
||||
if (symbol.atom(elf_file) == null and file_ptr != .linker_defined)
|
||||
break :blk elf.SHN_ABS;
|
||||
break :blk symbol.outputShndx() orelse elf.SHN_UNDEF;
|
||||
};
|
||||
const st_value = blk: {
|
||||
// if (symbol.flags.copy_rel) break :blk symbol.address(.{}, elf_file);
|
||||
// if (file_ptr == .shared or s_sym.st_shndx == elf.SHN_UNDEF) {
|
||||
// if (symbol.flags.is_canonical) break :blk symbol.address(.{}, elf_file);
|
||||
// break :blk 0;
|
||||
// }
|
||||
if (symbol.flags.has_copy_rel) break :blk symbol.address(.{}, elf_file);
|
||||
if (file_ptr == .shared_object or esym.st_shndx == elf.SHN_UNDEF) {
|
||||
if (symbol.flags.is_canonical) break :blk symbol.address(.{}, elf_file);
|
||||
break :blk 0;
|
||||
}
|
||||
if (st_shndx == elf.SHN_ABS) break :blk symbol.value;
|
||||
const shdr = &elf_file.shdrs.items[st_shndx];
|
||||
if (shdr.sh_flags & elf.SHF_TLS != 0 and file_ptr != .linker_defined)
|
||||
@@ -254,9 +277,10 @@ fn formatName(
|
||||
switch (symbol.version_index & elf.VERSYM_VERSION) {
|
||||
elf.VER_NDX_LOCAL, elf.VER_NDX_GLOBAL => {},
|
||||
else => {
|
||||
unreachable;
|
||||
// const shared = symbol.getFile(elf_file).?.shared;
|
||||
// try writer.print("@{s}", .{shared.getVersionString(symbol.version_index)});
|
||||
const file_ptr = symbol.file(elf_file).?;
|
||||
assert(file_ptr == .shared_object);
|
||||
const shared_object = file_ptr.shared_object;
|
||||
try writer.print("@{s}", .{shared_object.versionString(symbol.version_index)});
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -312,9 +336,12 @@ pub const Flags = packed struct {
|
||||
/// Whether this symbol is weak.
|
||||
weak: bool = false,
|
||||
|
||||
/// Whether the symbol makes into the output symtab or not.
|
||||
/// Whether the symbol makes into the output symtab.
|
||||
output_symtab: bool = false,
|
||||
|
||||
/// Whether the symbol has entry in dynamic symbol table.
|
||||
has_dynamic: bool = false,
|
||||
|
||||
/// Whether the symbol contains GOT indirection.
|
||||
needs_got: bool = false,
|
||||
has_got: bool = false,
|
||||
@@ -328,7 +355,6 @@ pub const Flags = packed struct {
|
||||
/// Whether the symbol contains COPYREL directive.
|
||||
needs_copy_rel: bool = false,
|
||||
has_copy_rel: bool = false,
|
||||
has_dynamic: bool = false,
|
||||
|
||||
/// Whether the symbol contains TLSGD indirection.
|
||||
needs_tlsgd: bool = false,
|
||||
@@ -365,8 +391,10 @@ const Atom = @import("Atom.zig");
|
||||
const Elf = @import("../Elf.zig");
|
||||
const File = @import("file.zig").File;
|
||||
const GotSection = synthetic_sections.GotSection;
|
||||
const GotPltSection = synthetic_sections.GotPltSection;
|
||||
const LinkerDefined = @import("LinkerDefined.zig");
|
||||
// const Object = @import("Object.zig");
|
||||
// const SharedObject = @import("SharedObject.zig");
|
||||
const Object = @import("Object.zig");
|
||||
const PltSection = synthetic_sections.PltSection;
|
||||
const SharedObject = @import("SharedObject.zig");
|
||||
const Symbol = @This();
|
||||
const ZigModule = @import("ZigModule.zig");
|
||||
|
||||
@@ -2,7 +2,7 @@ pub const File = union(enum) {
|
||||
zig_module: *ZigModule,
|
||||
linker_defined: *LinkerDefined,
|
||||
object: *Object,
|
||||
// shared_object: *SharedObject,
|
||||
shared_object: *SharedObject,
|
||||
|
||||
pub fn index(file: File) Index {
|
||||
return switch (file) {
|
||||
@@ -26,7 +26,7 @@ pub const File = union(enum) {
|
||||
.zig_module => |x| try writer.print("{s}", .{x.path}),
|
||||
.linker_defined => try writer.writeAll("(linker defined)"),
|
||||
.object => |x| try writer.print("{}", .{x.fmtPath()}),
|
||||
// .shared_object => |x| try writer.writeAll(x.path),
|
||||
.shared_object => |x| try writer.writeAll(x.path),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,8 +49,7 @@ pub const File = union(enum) {
|
||||
pub fn symbolRank(file: File, sym: elf.Elf64_Sym, in_archive: bool) u32 {
|
||||
const base: u3 = blk: {
|
||||
if (sym.st_shndx == elf.SHN_COMMON) break :blk if (in_archive) 6 else 5;
|
||||
// if (file == .shared or in_archive) break :blk switch (sym.st_bind()) {
|
||||
if (in_archive) break :blk switch (sym.st_bind()) {
|
||||
if (file == .shared_object or in_archive) break :blk switch (sym.st_bind()) {
|
||||
elf.STB_GLOBAL => 3,
|
||||
else => 4,
|
||||
};
|
||||
@@ -92,6 +91,7 @@ pub const File = union(enum) {
|
||||
pub fn atoms(file: File) []const Atom.Index {
|
||||
return switch (file) {
|
||||
.linker_defined => unreachable,
|
||||
.shared_object => unreachable,
|
||||
.zig_module => |x| x.atoms.items,
|
||||
.object => |x| x.atoms.items,
|
||||
};
|
||||
@@ -100,6 +100,7 @@ pub const File = union(enum) {
|
||||
pub fn locals(file: File) []const Symbol.Index {
|
||||
return switch (file) {
|
||||
.linker_defined => unreachable,
|
||||
.shared_object => unreachable,
|
||||
inline else => |x| x.locals(),
|
||||
};
|
||||
}
|
||||
@@ -117,7 +118,7 @@ pub const File = union(enum) {
|
||||
zig_module: ZigModule,
|
||||
linker_defined: LinkerDefined,
|
||||
object: Object,
|
||||
// shared_object: SharedObject,
|
||||
shared_object: SharedObject,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -129,6 +130,6 @@ const Atom = @import("Atom.zig");
|
||||
const Elf = @import("../Elf.zig");
|
||||
const LinkerDefined = @import("LinkerDefined.zig");
|
||||
const Object = @import("Object.zig");
|
||||
// const SharedObject = @import("SharedObject.zig");
|
||||
const SharedObject = @import("SharedObject.zig");
|
||||
const Symbol = @import("Symbol.zig");
|
||||
const ZigModule = @import("ZigModule.zig");
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user