mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 13:54:21 +00:00
elf: redo strings management in the linker
* atom names - are stored locally and pulled from defining object's strtab * local symbols - same * global symbols - in principle, we could store them locally, but for better debugging experience - when things go wrong - we store the offsets in a global strtab used by the symbol resolver
This commit is contained in:
parent
f6de3ec963
commit
25c53f08a6
17 changed files with 439 additions and 620 deletions
|
|
@ -624,7 +624,7 @@ set(ZIG_STAGE2_SOURCES
|
|||
"${CMAKE_SOURCE_DIR}/src/link/Plan9/aout.zig"
|
||||
"${CMAKE_SOURCE_DIR}/src/link/Wasm.zig"
|
||||
"${CMAKE_SOURCE_DIR}/src/link/msdos-stub.bin"
|
||||
"${CMAKE_SOURCE_DIR}/src/link/strtab.zig"
|
||||
"${CMAKE_SOURCE_DIR}/src/link/StringTable.zig"
|
||||
"${CMAKE_SOURCE_DIR}/src/link/tapi.zig"
|
||||
"${CMAKE_SOURCE_DIR}/src/link/tapi/Tokenizer.zig"
|
||||
"${CMAKE_SOURCE_DIR}/src/link/tapi/parse.zig"
|
||||
|
|
|
|||
|
|
@ -33,10 +33,10 @@ need_got_table: std.AutoHashMapUnmanaged(u32, void) = .{},
|
|||
locals_free_list: std.ArrayListUnmanaged(u32) = .{},
|
||||
globals_free_list: std.ArrayListUnmanaged(u32) = .{},
|
||||
|
||||
strtab: StringTable(.strtab) = .{},
|
||||
strtab: StringTable = .{},
|
||||
strtab_offset: ?u32 = null,
|
||||
|
||||
temp_strtab: StringTable(.temp_strtab) = .{},
|
||||
temp_strtab: StringTable = .{},
|
||||
|
||||
got_table: TableSection(SymbolWithLoc) = .{},
|
||||
|
||||
|
|
@ -418,7 +418,7 @@ fn populateMissingMetadata(self: *Coff) !void {
|
|||
}
|
||||
|
||||
if (self.strtab_offset == null) {
|
||||
const file_size = @as(u32, @intCast(self.strtab.len()));
|
||||
const file_size = @as(u32, @intCast(self.strtab.buffer.items.len));
|
||||
self.strtab_offset = self.findFreeSpace(file_size, @alignOf(u32)); // 4bytes aligned seems like a good idea here
|
||||
log.debug("found strtab free space 0x{x} to 0x{x}", .{ self.strtab_offset.?, self.strtab_offset.? + file_size });
|
||||
}
|
||||
|
|
@ -2142,7 +2142,7 @@ fn writeStrtab(self: *Coff) !void {
|
|||
if (self.strtab_offset == null) return;
|
||||
|
||||
const allocated_size = self.allocatedSize(self.strtab_offset.?);
|
||||
const needed_size = @as(u32, @intCast(self.strtab.len()));
|
||||
const needed_size = @as(u32, @intCast(self.strtab.buffer.items.len));
|
||||
|
||||
if (needed_size > allocated_size) {
|
||||
self.strtab_offset = null;
|
||||
|
|
@ -2154,10 +2154,10 @@ fn writeStrtab(self: *Coff) !void {
|
|||
var buffer = std.ArrayList(u8).init(self.base.allocator);
|
||||
defer buffer.deinit();
|
||||
try buffer.ensureTotalCapacityPrecise(needed_size);
|
||||
buffer.appendSliceAssumeCapacity(self.strtab.items());
|
||||
buffer.appendSliceAssumeCapacity(self.strtab.buffer.items);
|
||||
// Here, we do a trick in that we do not commit the size of the strtab to strtab buffer, instead
|
||||
// we write the length of the strtab to a temporary buffer that goes to file.
|
||||
mem.writeInt(u32, buffer.items[0..4], @as(u32, @intCast(self.strtab.len())), .little);
|
||||
mem.writeInt(u32, buffer.items[0..4], @as(u32, @intCast(self.strtab.buffer.items.len)), .little);
|
||||
|
||||
try self.base.file.?.pwriteAll(buffer.items, self.strtab_offset.?);
|
||||
}
|
||||
|
|
@ -2325,7 +2325,7 @@ fn detectAllocCollision(self: *Coff, start: u32, size: u32) ?u32 {
|
|||
const end = start + padToIdeal(size);
|
||||
|
||||
if (self.strtab_offset) |off| {
|
||||
const tight_size = @as(u32, @intCast(self.strtab.len()));
|
||||
const tight_size = @as(u32, @intCast(self.strtab.buffer.items.len));
|
||||
const increased_size = padToIdeal(tight_size);
|
||||
const test_end = off + increased_size;
|
||||
if (end > off and start < test_end) {
|
||||
|
|
@ -2666,7 +2666,7 @@ const InternPool = @import("../InternPool.zig");
|
|||
const Object = @import("Coff/Object.zig");
|
||||
const Relocation = @import("Coff/Relocation.zig");
|
||||
const TableSection = @import("table_section.zig").TableSection;
|
||||
const StringTable = @import("strtab.zig").StringTable;
|
||||
const StringTable = @import("StringTable.zig");
|
||||
const Type = @import("../type.zig").Type;
|
||||
const TypedValue = @import("../TypedValue.zig");
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ abbrev_table_offset: ?u64 = null,
|
|||
|
||||
/// TODO replace with InternPool
|
||||
/// Table of debug symbol names.
|
||||
strtab: StringTable(.strtab) = .{},
|
||||
strtab: StringTable = .{},
|
||||
|
||||
/// Quick lookup array of all defined source files referenced by at least one Decl.
|
||||
/// They will end up in the DWARF debug_line header as two lists:
|
||||
|
|
@ -2760,6 +2760,6 @@ const LinkFn = File.LinkFn;
|
|||
const LinkerLoad = @import("../codegen.zig").LinkerLoad;
|
||||
const Module = @import("../Module.zig");
|
||||
const InternPool = @import("../InternPool.zig");
|
||||
const StringTable = @import("strtab.zig").StringTable;
|
||||
const StringTable = @import("StringTable.zig");
|
||||
const Type = @import("../type.zig").Type;
|
||||
const Value = @import("../value.zig").Value;
|
||||
|
|
|
|||
243
src/link/Elf.zig
243
src/link/Elf.zig
|
|
@ -66,13 +66,15 @@ page_size: u32,
|
|||
default_sym_version: elf.Elf64_Versym,
|
||||
|
||||
/// .shstrtab buffer
|
||||
shstrtab: StringTable(.strtab) = .{},
|
||||
shstrtab: std.ArrayListUnmanaged(u8) = .{},
|
||||
/// .symtab buffer
|
||||
symtab: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{},
|
||||
/// .strtab buffer
|
||||
strtab: StringTable(.strtab) = .{},
|
||||
strtab: std.ArrayListUnmanaged(u8) = .{},
|
||||
/// Dynamic symbol table. Only populated and emitted when linking dynamically.
|
||||
dynsym: DynsymSection = .{},
|
||||
/// .dynstrtab buffer
|
||||
dynstrtab: StringTable(.dynstrtab) = .{},
|
||||
dynstrtab: std.ArrayListUnmanaged(u8) = .{},
|
||||
/// Version symbol table. Only populated and emitted when linking dynamically.
|
||||
versym: std.ArrayListUnmanaged(elf.Elf64_Versym) = .{},
|
||||
/// .verneed section
|
||||
|
|
@ -156,9 +158,10 @@ start_stop_indexes: std.ArrayListUnmanaged(u32) = .{},
|
|||
/// An array of symbols parsed across all input files.
|
||||
symbols: std.ArrayListUnmanaged(Symbol) = .{},
|
||||
symbols_extra: std.ArrayListUnmanaged(u32) = .{},
|
||||
resolver: std.AutoArrayHashMapUnmanaged(u32, Symbol.Index) = .{},
|
||||
symbols_free_list: std.ArrayListUnmanaged(Symbol.Index) = .{},
|
||||
|
||||
resolver: std.AutoArrayHashMapUnmanaged(u32, Symbol.Index) = .{},
|
||||
|
||||
has_text_reloc: bool = false,
|
||||
num_ifunc_dynrelocs: usize = 0,
|
||||
|
||||
|
|
@ -175,6 +178,10 @@ comdat_groups: std.ArrayListUnmanaged(ComdatGroup) = .{},
|
|||
comdat_groups_owners: std.ArrayListUnmanaged(ComdatGroupOwner) = .{},
|
||||
comdat_groups_table: std.AutoHashMapUnmanaged(u32, ComdatGroupOwner.Index) = .{},
|
||||
|
||||
/// Global string table used to provide quick access to global symbol resolvers
|
||||
/// such as `resolver` and `comdat_groups_table`.
|
||||
strings: StringTable = .{},
|
||||
|
||||
/// When allocating, the ideal_capacity is calculated by
|
||||
/// actual_capacity + (actual_capacity / ideal_factor)
|
||||
const ideal_factor = 3;
|
||||
|
|
@ -227,13 +234,15 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option
|
|||
// Append null file at index 0
|
||||
try self.files.append(allocator, .null);
|
||||
// Append null byte to string tables
|
||||
try self.shstrtab.buffer.append(allocator, 0);
|
||||
try self.strtab.buffer.append(allocator, 0);
|
||||
try self.shstrtab.append(allocator, 0);
|
||||
try self.strtab.append(allocator, 0);
|
||||
// There must always be a null shdr in index 0
|
||||
_ = try self.addSection(.{ .name = "" });
|
||||
// Append null symbol in output symtab
|
||||
try self.symtab.append(allocator, null_sym);
|
||||
|
||||
if (!is_obj_or_ar) {
|
||||
try self.dynstrtab.buffer.append(allocator, 0);
|
||||
try self.dynstrtab.append(allocator, 0);
|
||||
|
||||
// Initialize PT_PHDR program header
|
||||
const p_align: u16 = switch (self.ptr_width) {
|
||||
|
|
@ -347,6 +356,7 @@ pub fn deinit(self: *Elf) void {
|
|||
}
|
||||
self.output_sections.deinit(gpa);
|
||||
self.shstrtab.deinit(gpa);
|
||||
self.symtab.deinit(gpa);
|
||||
self.strtab.deinit(gpa);
|
||||
self.symbols.deinit(gpa);
|
||||
self.symbols_extra.deinit(gpa);
|
||||
|
|
@ -364,6 +374,7 @@ pub fn deinit(self: *Elf) void {
|
|||
self.comdat_groups.deinit(gpa);
|
||||
self.comdat_groups_owners.deinit(gpa);
|
||||
self.comdat_groups_table.deinit(gpa);
|
||||
self.strings.deinit(gpa);
|
||||
|
||||
self.got.deinit(gpa);
|
||||
self.plt.deinit(gpa);
|
||||
|
|
@ -747,7 +758,7 @@ pub fn growAllocSection(self: *Elf, shdr_index: u16, needed_size: u64) !void {
|
|||
const new_offset = self.findFreeSpace(needed_size, self.page_size);
|
||||
|
||||
log.debug("new '{s}' file offset 0x{x} to 0x{x}", .{
|
||||
self.shstrtab.getAssumeExists(shdr.sh_name),
|
||||
self.getShString(shdr.sh_name),
|
||||
new_offset,
|
||||
new_offset + existing_size,
|
||||
});
|
||||
|
|
@ -796,7 +807,7 @@ pub fn growNonAllocSection(
|
|||
const new_offset = self.findFreeSpace(needed_size, min_alignment);
|
||||
|
||||
log.debug("new '{s}' file offset 0x{x} to 0x{x}", .{
|
||||
self.shstrtab.getAssumeExists(shdr.sh_name),
|
||||
self.getShString(shdr.sh_name),
|
||||
new_offset,
|
||||
new_offset + existing_size,
|
||||
});
|
||||
|
|
@ -1696,7 +1707,7 @@ fn accessLibPath(
|
|||
/// 6. Re-run symbol resolution on pruned objects and shared objects sets.
|
||||
fn resolveSymbols(self: *Elf) void {
|
||||
// Resolve symbols in the ZigObject. For now, we assume that it's always live.
|
||||
if (self.zigObjectPtr()) |zig_object| zig_object.resolveSymbols(self);
|
||||
if (self.zigObjectPtr()) |zig_object| zig_object.asFile().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);
|
||||
|
|
@ -1705,7 +1716,7 @@ fn resolveSymbols(self: *Elf) void {
|
|||
self.markLive();
|
||||
|
||||
// Reset state of all globals after marking live objects.
|
||||
if (self.zigObjectPtr()) |zig_object| zig_object.resetGlobals(self);
|
||||
if (self.zigObjectPtr()) |zig_object| zig_object.asFile().resetGlobals(self);
|
||||
for (self.objects.items) |index| self.file(index).?.resetGlobals(self);
|
||||
for (self.shared_objects.items) |index| self.file(index).?.resetGlobals(self);
|
||||
|
||||
|
|
@ -1767,7 +1778,7 @@ fn resolveSymbols(self: *Elf) void {
|
|||
/// This routine will prune unneeded objects extracted from archives and
|
||||
/// unneeded shared objects.
|
||||
fn markLive(self: *Elf) void {
|
||||
if (self.zigObjectPtr()) |zig_object| zig_object.markLive(self);
|
||||
if (self.zigObjectPtr()) |zig_object| zig_object.asFile().markLive(self);
|
||||
for (self.objects.items) |index| {
|
||||
const file_ptr = self.file(index).?;
|
||||
if (file_ptr.isAlive()) file_ptr.markLive(self);
|
||||
|
|
@ -3358,7 +3369,7 @@ fn sortInitFini(self: *Elf) !void {
|
|||
elf.SHT_FINI_ARRAY,
|
||||
=> is_init_fini = true,
|
||||
else => {
|
||||
const name = self.shstrtab.getAssumeExists(shdr.sh_name);
|
||||
const name = self.getShString(shdr.sh_name);
|
||||
is_ctor_dtor = mem.indexOf(u8, name, ".ctors") != null or mem.indexOf(u8, name, ".dtors") != null;
|
||||
},
|
||||
}
|
||||
|
|
@ -3520,7 +3531,7 @@ fn sortPhdrs(self: *Elf) error{OutOfMemory}!void {
|
|||
|
||||
fn shdrRank(self: *Elf, shndx: u16) u8 {
|
||||
const shdr = self.shdrs.items[shndx];
|
||||
const name = self.shstrtab.getAssumeExists(shdr.sh_name);
|
||||
const name = self.getShString(shdr.sh_name);
|
||||
const flags = shdr.sh_flags;
|
||||
|
||||
switch (shdr.sh_type) {
|
||||
|
|
@ -3801,7 +3812,7 @@ fn updateSectionSizes(self: *Elf) !void {
|
|||
}
|
||||
|
||||
if (self.dynstrtab_section_index) |index| {
|
||||
self.shdrs.items[index].sh_size = self.dynstrtab.buffer.items.len;
|
||||
self.shdrs.items[index].sh_size = self.dynstrtab.items.len;
|
||||
}
|
||||
|
||||
if (self.versym_section_index) |index| {
|
||||
|
|
@ -3816,26 +3827,8 @@ fn updateSectionSizes(self: *Elf) !void {
|
|||
try self.updateSymtabSize();
|
||||
}
|
||||
|
||||
if (self.strtab_section_index) |index| {
|
||||
// TODO I don't really this here but we need it to add symbol names from GOT and other synthetic
|
||||
// sections into .strtab for easier debugging.
|
||||
if (self.zig_got_section_index) |_| {
|
||||
try self.zig_got.updateStrtab(self);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
if (self.shstrtab_section_index) |index| {
|
||||
self.shdrs.items[index].sh_size = self.shstrtab.buffer.items.len;
|
||||
self.shdrs.items[index].sh_size = self.shstrtab.items.len;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -4074,7 +4067,7 @@ fn allocateNonAllocSections(self: *Elf) !void {
|
|||
|
||||
if (self.isDebugSection(@intCast(shndx))) {
|
||||
log.debug("moving {s} from 0x{x} to 0x{x}", .{
|
||||
self.shstrtab.getAssumeExists(shdr.sh_name),
|
||||
self.getShString(shdr.sh_name),
|
||||
shdr.sh_offset,
|
||||
new_offset,
|
||||
});
|
||||
|
|
@ -4187,7 +4180,7 @@ fn writeAtoms(self: *Elf) !void {
|
|||
|
||||
const atom_list = self.output_sections.get(@intCast(shndx)) orelse continue;
|
||||
|
||||
log.debug("writing atoms in '{s}' section", .{self.shstrtab.getAssumeExists(shdr.sh_name)});
|
||||
log.debug("writing atoms in '{s}' section", .{self.getShString(shdr.sh_name)});
|
||||
|
||||
// TODO really, really handle debug section separately
|
||||
const base_offset = if (self.isDebugSection(@intCast(shndx))) blk: {
|
||||
|
|
@ -4256,60 +4249,61 @@ fn updateSymtabSize(self: *Elf) !void {
|
|||
var sizes = SymtabSize{};
|
||||
|
||||
if (self.zigObjectPtr()) |zig_object| {
|
||||
zig_object.updateSymtabSize(self);
|
||||
sizes.nlocals += zig_object.output_symtab_size.nlocals;
|
||||
sizes.nglobals += zig_object.output_symtab_size.nglobals;
|
||||
zig_object.asFile().updateSymtabSize(self);
|
||||
sizes.add(zig_object.output_symtab_size);
|
||||
}
|
||||
|
||||
for (self.objects.items) |index| {
|
||||
const object = self.file(index).?.object;
|
||||
object.updateSymtabSize(self);
|
||||
sizes.nlocals += object.output_symtab_size.nlocals;
|
||||
sizes.nglobals += object.output_symtab_size.nglobals;
|
||||
const file_ptr = self.file(index).?;
|
||||
file_ptr.updateSymtabSize(self);
|
||||
sizes.add(file_ptr.object.output_symtab_size);
|
||||
}
|
||||
|
||||
for (self.shared_objects.items) |index| {
|
||||
const shared_object = self.file(index).?.shared_object;
|
||||
shared_object.updateSymtabSize(self);
|
||||
sizes.nglobals += shared_object.output_symtab_size.nglobals;
|
||||
const file_ptr = self.file(index).?;
|
||||
file_ptr.updateSymtabSize(self);
|
||||
sizes.add(file_ptr.shared_object.output_symtab_size);
|
||||
}
|
||||
|
||||
if (self.zig_got_section_index) |_| {
|
||||
self.zig_got.updateSymtabSize(self);
|
||||
sizes.nlocals += self.zig_got.output_symtab_size.nlocals;
|
||||
sizes.add(self.zig_got.output_symtab_size);
|
||||
}
|
||||
|
||||
if (self.got_section_index) |_| {
|
||||
self.got.updateSymtabSize(self);
|
||||
sizes.nlocals += self.got.output_symtab_size.nlocals;
|
||||
sizes.add(self.got.output_symtab_size);
|
||||
}
|
||||
|
||||
if (self.plt_section_index) |_| {
|
||||
self.plt.updateSymtabSize(self);
|
||||
sizes.nlocals += self.plt.output_symtab_size.nlocals;
|
||||
sizes.add(self.plt.output_symtab_size);
|
||||
}
|
||||
|
||||
if (self.plt_got_section_index) |_| {
|
||||
self.plt_got.updateSymtabSize(self);
|
||||
sizes.nlocals += self.plt_got.output_symtab_size.nlocals;
|
||||
sizes.add(self.plt_got.output_symtab_size);
|
||||
}
|
||||
|
||||
if (self.linker_defined_index) |index| {
|
||||
const linker_defined = self.file(index).?.linker_defined;
|
||||
linker_defined.updateSymtabSize(self);
|
||||
sizes.nlocals += linker_defined.output_symtab_size.nlocals;
|
||||
const file_ptr = self.file(index).?;
|
||||
file_ptr.updateSymtabSize(self);
|
||||
sizes.add(file_ptr.linker_defined.output_symtab_size);
|
||||
}
|
||||
|
||||
const shdr = &self.shdrs.items[self.symtab_section_index.?];
|
||||
shdr.sh_info = sizes.nlocals + 1;
|
||||
shdr.sh_link = self.strtab_section_index.?;
|
||||
const symtab_shdr = &self.shdrs.items[self.symtab_section_index.?];
|
||||
symtab_shdr.sh_info = sizes.nlocals + 1;
|
||||
symtab_shdr.sh_link = self.strtab_section_index.?;
|
||||
|
||||
const sym_size: u64 = switch (self.ptr_width) {
|
||||
.p32 => @sizeOf(elf.Elf32_Sym),
|
||||
.p64 => @sizeOf(elf.Elf64_Sym),
|
||||
};
|
||||
const needed_size = (sizes.nlocals + sizes.nglobals + 1) * sym_size;
|
||||
shdr.sh_size = needed_size;
|
||||
symtab_shdr.sh_size = needed_size;
|
||||
|
||||
const strtab = &self.shdrs.items[self.strtab_section_index.?];
|
||||
strtab.sh_size = sizes.strsize + 1;
|
||||
}
|
||||
|
||||
fn writeSyntheticSections(self: *Elf) !void {
|
||||
|
|
@ -4370,7 +4364,7 @@ fn writeSyntheticSections(self: *Elf) !void {
|
|||
|
||||
if (self.dynstrtab_section_index) |shndx| {
|
||||
const shdr = self.shdrs.items[shndx];
|
||||
try self.base.file.?.pwriteAll(self.dynstrtab.buffer.items, shdr.sh_offset);
|
||||
try self.base.file.?.pwriteAll(self.dynstrtab.items, shdr.sh_offset);
|
||||
}
|
||||
|
||||
if (self.eh_frame_section_index) |shndx| {
|
||||
|
|
@ -4440,12 +4434,7 @@ fn writeSyntheticSections(self: *Elf) !void {
|
|||
|
||||
if (self.shstrtab_section_index) |index| {
|
||||
const shdr = self.shdrs.items[index];
|
||||
try self.base.file.?.pwriteAll(self.shstrtab.buffer.items, shdr.sh_offset);
|
||||
}
|
||||
|
||||
if (self.strtab_section_index) |index| {
|
||||
const shdr = self.shdrs.items[index];
|
||||
try self.base.file.?.pwriteAll(self.strtab.buffer.items, shdr.sh_offset);
|
||||
try self.base.file.?.pwriteAll(self.shstrtab.items, shdr.sh_offset);
|
||||
}
|
||||
|
||||
if (self.symtab_section_index) |_| {
|
||||
|
|
@ -4455,77 +4444,83 @@ fn writeSyntheticSections(self: *Elf) !void {
|
|||
|
||||
fn writeSymtab(self: *Elf) !void {
|
||||
const gpa = self.base.allocator;
|
||||
const shdr = &self.shdrs.items[self.symtab_section_index.?];
|
||||
const symtab_shdr = self.shdrs.items[self.symtab_section_index.?];
|
||||
const strtab_shdr = self.shdrs.items[self.strtab_section_index.?];
|
||||
const sym_size: u64 = switch (self.ptr_width) {
|
||||
.p32 => @sizeOf(elf.Elf32_Sym),
|
||||
.p64 => @sizeOf(elf.Elf64_Sym),
|
||||
};
|
||||
const nsyms = math.cast(usize, @divExact(shdr.sh_size, sym_size)) orelse return error.Overflow;
|
||||
const nsyms = math.cast(usize, @divExact(symtab_shdr.sh_size, sym_size)) orelse return error.Overflow;
|
||||
|
||||
log.debug("writing {d} symbols at 0x{x}", .{ nsyms, shdr.sh_offset });
|
||||
log.debug("writing {d} symbols at 0x{x}", .{ nsyms, symtab_shdr.sh_offset });
|
||||
|
||||
const symtab = try gpa.alloc(elf.Elf64_Sym, nsyms);
|
||||
defer gpa.free(symtab);
|
||||
symtab[0] = null_sym;
|
||||
try self.symtab.resize(gpa, nsyms);
|
||||
try self.strtab.ensureUnusedCapacity(gpa, strtab_shdr.sh_size - 1);
|
||||
|
||||
var ctx: struct { ilocal: usize, iglobal: usize, symtab: []elf.Elf64_Sym } = .{
|
||||
const Ctx = struct {
|
||||
ilocal: usize,
|
||||
iglobal: usize,
|
||||
|
||||
fn incr(this: *@This(), ss: SymtabSize) void {
|
||||
this.ilocal += ss.nlocals;
|
||||
this.iglobal += ss.nglobals;
|
||||
}
|
||||
};
|
||||
var ctx: Ctx = .{
|
||||
.ilocal = 1,
|
||||
.iglobal = shdr.sh_info,
|
||||
.symtab = symtab,
|
||||
.iglobal = symtab_shdr.sh_info,
|
||||
};
|
||||
|
||||
if (self.zigObjectPtr()) |zig_object| {
|
||||
zig_object.writeSymtab(self, ctx);
|
||||
ctx.ilocal += zig_object.output_symtab_size.nlocals;
|
||||
ctx.iglobal += zig_object.output_symtab_size.nglobals;
|
||||
zig_object.asFile().writeSymtab(self, ctx);
|
||||
ctx.incr(zig_object.output_symtab_size);
|
||||
}
|
||||
|
||||
for (self.objects.items) |index| {
|
||||
const object = self.file(index).?.object;
|
||||
object.writeSymtab(self, ctx);
|
||||
ctx.ilocal += object.output_symtab_size.nlocals;
|
||||
ctx.iglobal += object.output_symtab_size.nglobals;
|
||||
const file_ptr = self.file(index).?;
|
||||
file_ptr.writeSymtab(self, ctx);
|
||||
ctx.incr(file_ptr.object.output_symtab_size);
|
||||
}
|
||||
|
||||
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;
|
||||
const file_ptr = self.file(index).?;
|
||||
file_ptr.writeSymtab(self, ctx);
|
||||
ctx.incr(file_ptr.shared_object.output_symtab_size);
|
||||
}
|
||||
|
||||
if (self.zig_got_section_index) |_| {
|
||||
try self.zig_got.writeSymtab(self, ctx);
|
||||
ctx.ilocal += self.zig_got.output_symtab_size.nlocals;
|
||||
self.zig_got.writeSymtab(self, ctx);
|
||||
ctx.incr(self.zig_got.output_symtab_size);
|
||||
}
|
||||
|
||||
if (self.got_section_index) |_| {
|
||||
try self.got.writeSymtab(self, ctx);
|
||||
ctx.ilocal += self.got.output_symtab_size.nlocals;
|
||||
self.got.writeSymtab(self, ctx);
|
||||
ctx.incr(self.got.output_symtab_size);
|
||||
}
|
||||
|
||||
if (self.plt_section_index) |_| {
|
||||
try self.plt.writeSymtab(self, ctx);
|
||||
ctx.ilocal += self.plt.output_symtab_size.nlocals;
|
||||
self.plt.writeSymtab(self, ctx);
|
||||
ctx.incr(self.plt.output_symtab_size);
|
||||
}
|
||||
|
||||
if (self.plt_got_section_index) |_| {
|
||||
try self.plt_got.writeSymtab(self, ctx);
|
||||
ctx.ilocal += self.plt_got.output_symtab_size.nlocals;
|
||||
self.plt_got.writeSymtab(self, ctx);
|
||||
ctx.incr(self.plt_got.output_symtab_size);
|
||||
}
|
||||
|
||||
if (self.linker_defined_index) |index| {
|
||||
const linker_defined = self.file(index).?.linker_defined;
|
||||
linker_defined.writeSymtab(self, ctx);
|
||||
ctx.ilocal += linker_defined.output_symtab_size.nlocals;
|
||||
const file_ptr = self.file(index).?;
|
||||
file_ptr.writeSymtab(self, ctx);
|
||||
ctx.incr(file_ptr.linker_defined.output_symtab_size);
|
||||
}
|
||||
|
||||
const foreign_endian = self.base.options.target.cpu.arch.endian() != builtin.cpu.arch.endian();
|
||||
switch (self.ptr_width) {
|
||||
.p32 => {
|
||||
const buf = try gpa.alloc(elf.Elf32_Sym, symtab.len);
|
||||
const buf = try gpa.alloc(elf.Elf32_Sym, self.symtab.items.len);
|
||||
defer gpa.free(buf);
|
||||
|
||||
for (buf, symtab) |*out, sym| {
|
||||
for (buf, self.symtab.items) |*out, sym| {
|
||||
out.* = .{
|
||||
.st_name = sym.st_name,
|
||||
.st_info = sym.st_info,
|
||||
|
|
@ -4536,15 +4531,17 @@ fn writeSymtab(self: *Elf) !void {
|
|||
};
|
||||
if (foreign_endian) mem.byteSwapAllFields(elf.Elf32_Sym, out);
|
||||
}
|
||||
try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), shdr.sh_offset);
|
||||
try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), symtab_shdr.sh_offset);
|
||||
},
|
||||
.p64 => {
|
||||
if (foreign_endian) {
|
||||
for (symtab) |*sym| mem.byteSwapAllFields(elf.Elf64_Sym, sym);
|
||||
for (self.symtab.items) |*sym| mem.byteSwapAllFields(elf.Elf64_Sym, sym);
|
||||
}
|
||||
try self.base.file.?.pwriteAll(mem.sliceAsBytes(symtab), shdr.sh_offset);
|
||||
try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.symtab.items), symtab_shdr.sh_offset);
|
||||
},
|
||||
}
|
||||
|
||||
try self.base.file.?.pwriteAll(self.strtab.items, strtab_shdr.sh_offset);
|
||||
}
|
||||
|
||||
/// Always 4 or 8 depending on whether this is 32-bit ELF or 64-bit ELF.
|
||||
|
|
@ -4925,7 +4922,7 @@ pub fn addSection(self: *Elf, opts: AddSectionOpts) !u16 {
|
|||
const index = @as(u16, @intCast(self.shdrs.items.len));
|
||||
const shdr = try self.shdrs.addOne(gpa);
|
||||
shdr.* = .{
|
||||
.sh_name = try self.shstrtab.insert(gpa, opts.name),
|
||||
.sh_name = try self.insertShString(opts.name),
|
||||
.sh_type = opts.type,
|
||||
.sh_flags = opts.flags,
|
||||
.sh_addr = 0,
|
||||
|
|
@ -4941,7 +4938,7 @@ pub fn addSection(self: *Elf, opts: AddSectionOpts) !u16 {
|
|||
|
||||
pub fn sectionByName(self: *Elf, name: [:0]const u8) ?u16 {
|
||||
for (self.shdrs.items, 0..) |*shdr, i| {
|
||||
const this_name = self.shstrtab.getAssumeExists(shdr.sh_name);
|
||||
const this_name = self.getShString(shdr.sh_name);
|
||||
if (mem.eql(u8, this_name, name)) return @as(u16, @intCast(i));
|
||||
} else return null;
|
||||
}
|
||||
|
|
@ -5114,13 +5111,15 @@ const GetOrPutGlobalResult = struct {
|
|||
index: Symbol.Index,
|
||||
};
|
||||
|
||||
pub fn getOrPutGlobal(self: *Elf, name_off: u32) !GetOrPutGlobalResult {
|
||||
pub fn getOrPutGlobal(self: *Elf, name: []const u8) !GetOrPutGlobalResult {
|
||||
const gpa = self.base.allocator;
|
||||
const name_off = try self.strings.insert(gpa, name);
|
||||
const gop = try self.resolver.getOrPut(gpa, name_off);
|
||||
if (!gop.found_existing) {
|
||||
const index = try self.addSymbol();
|
||||
const global = self.symbol(index);
|
||||
global.name_offset = name_off;
|
||||
global.flags.global = true;
|
||||
gop.value_ptr.* = index;
|
||||
}
|
||||
return .{
|
||||
|
|
@ -5130,7 +5129,7 @@ pub fn getOrPutGlobal(self: *Elf, name_off: u32) !GetOrPutGlobalResult {
|
|||
}
|
||||
|
||||
pub fn globalByName(self: *Elf, name: []const u8) ?Symbol.Index {
|
||||
const name_off = self.strtab.getOffset(name) orelse return null;
|
||||
const name_off = self.strings.getOffset(name) orelse return null;
|
||||
return self.resolver.get(name_off);
|
||||
}
|
||||
|
||||
|
|
@ -5148,8 +5147,9 @@ const GetOrCreateComdatGroupOwnerResult = struct {
|
|||
index: ComdatGroupOwner.Index,
|
||||
};
|
||||
|
||||
pub fn getOrCreateComdatGroupOwner(self: *Elf, off: u32) !GetOrCreateComdatGroupOwnerResult {
|
||||
pub fn getOrCreateComdatGroupOwner(self: *Elf, name: [:0]const u8) !GetOrCreateComdatGroupOwnerResult {
|
||||
const gpa = self.base.allocator;
|
||||
const off = try self.strings.insert(gpa, name);
|
||||
const gop = try self.comdat_groups_table.getOrPut(gpa, off);
|
||||
if (!gop.found_existing) {
|
||||
const index = @as(ComdatGroupOwner.Index, @intCast(self.comdat_groups_owners.items.len));
|
||||
|
|
@ -5239,6 +5239,30 @@ fn addErrorWithNotesAssumeCapacity(self: *Elf, note_count: usize) error{OutOfMem
|
|||
return .{ .index = index };
|
||||
}
|
||||
|
||||
pub fn getShString(self: Elf, off: u32) [:0]const u8 {
|
||||
assert(off < self.shstrtab.items.len);
|
||||
return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.shstrtab.items.ptr + off)), 0);
|
||||
}
|
||||
|
||||
pub fn insertShString(self: *Elf, name: [:0]const u8) error{OutOfMemory}!u32 {
|
||||
const off = @as(u32, @intCast(self.shstrtab.items.len));
|
||||
try self.shstrtab.ensureUnusedCapacity(self.base.allocator, name.len + 1);
|
||||
self.shstrtab.writer(self.base.allocator).print("{s}\x00", .{name}) catch unreachable;
|
||||
return off;
|
||||
}
|
||||
|
||||
pub fn getDynString(self: Elf, off: u32) [:0]const u8 {
|
||||
assert(off < self.dynstrtab.items.len);
|
||||
return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.dynstrtab.items.ptr + off)), 0);
|
||||
}
|
||||
|
||||
pub fn insertDynString(self: *Elf, name: []const u8) error{OutOfMemory}!u32 {
|
||||
const off = @as(u32, @intCast(self.dynstrtab.items.len));
|
||||
try self.dynstrtab.ensureUnusedCapacity(self.base.allocator, name.len + 1);
|
||||
self.dynstrtab.writer(self.base.allocator).print("{s}\x00", .{name}) catch unreachable;
|
||||
return off;
|
||||
}
|
||||
|
||||
fn reportUndefined(self: *Elf, undefs: anytype) !void {
|
||||
const gpa = self.base.allocator;
|
||||
const max_notes = 4;
|
||||
|
|
@ -5340,7 +5364,7 @@ fn formatShdr(
|
|||
_ = unused_fmt_string;
|
||||
const shdr = ctx.shdr;
|
||||
try writer.print("{s} : @{x} ({x}) : align({x}) : size({x})", .{
|
||||
ctx.elf_file.shstrtab.getAssumeExists(shdr.sh_name), shdr.sh_offset,
|
||||
ctx.elf_file.getShString(shdr.sh_name), shdr.sh_offset,
|
||||
shdr.sh_addr, shdr.sh_addralign,
|
||||
shdr.sh_size,
|
||||
});
|
||||
|
|
@ -5516,6 +5540,13 @@ pub const ComdatGroup = struct {
|
|||
pub const SymtabSize = struct {
|
||||
nlocals: u32 = 0,
|
||||
nglobals: u32 = 0,
|
||||
strsize: u32 = 0,
|
||||
|
||||
fn add(ss: *SymtabSize, other: SymtabSize) void {
|
||||
ss.nlocals += other.nlocals;
|
||||
ss.nglobals += other.nglobals;
|
||||
ss.strsize += other.strsize;
|
||||
}
|
||||
};
|
||||
|
||||
pub const null_sym = elf.Elf64_Sym{
|
||||
|
|
@ -5621,7 +5652,7 @@ 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 StringTable = @import("StringTable.zig");
|
||||
const TypedValue = @import("../TypedValue.zig");
|
||||
const VerneedSection = synthetic_sections.VerneedSection;
|
||||
const ZigGotSection = synthetic_sections.ZigGotSection;
|
||||
|
|
|
|||
|
|
@ -42,7 +42,10 @@ next_index: Index = 0,
|
|||
pub const Alignment = @import("../../InternPool.zig").Alignment;
|
||||
|
||||
pub fn name(self: Atom, elf_file: *Elf) []const u8 {
|
||||
return elf_file.strtab.getAssumeExists(self.name_offset);
|
||||
const file_ptr = self.file(elf_file).?;
|
||||
return switch (file_ptr) {
|
||||
inline else => |x| x.getString(self.name_offset),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn file(self: Atom, elf_file: *Elf) ?File {
|
||||
|
|
@ -692,7 +695,7 @@ fn reportUndefined(
|
|||
) !void {
|
||||
const rel_esym = switch (self.file(elf_file).?) {
|
||||
.zig_object => |x| x.elfSym(rel.r_sym()).*,
|
||||
.object => |x| x.symtab[rel.r_sym()],
|
||||
.object => |x| x.symtab.items[rel.r_sym()],
|
||||
else => unreachable,
|
||||
};
|
||||
const esym = sym.elfSym(elf_file);
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
index: File.Index,
|
||||
symtab: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{},
|
||||
strtab: std.ArrayListUnmanaged(u8) = .{},
|
||||
symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
|
||||
|
||||
output_symtab_size: Elf.SymtabSize = .{},
|
||||
|
||||
pub fn deinit(self: *LinkerDefined, allocator: Allocator) void {
|
||||
self.symtab.deinit(allocator);
|
||||
self.strtab.deinit(allocator);
|
||||
self.symbols.deinit(allocator);
|
||||
}
|
||||
|
||||
|
|
@ -13,16 +15,17 @@ pub fn addGlobal(self: *LinkerDefined, name: [:0]const u8, elf_file: *Elf) !u32
|
|||
const gpa = elf_file.base.allocator;
|
||||
try self.symtab.ensureUnusedCapacity(gpa, 1);
|
||||
try self.symbols.ensureUnusedCapacity(gpa, 1);
|
||||
const name_off = @as(u32, @intCast(self.strtab.items.len));
|
||||
try self.strtab.writer(gpa).print("{s}\x00", .{name});
|
||||
self.symtab.appendAssumeCapacity(.{
|
||||
.st_name = try elf_file.strtab.insert(gpa, name),
|
||||
.st_name = name_off,
|
||||
.st_info = elf.STB_GLOBAL << 4,
|
||||
.st_other = @intFromEnum(elf.STV.HIDDEN),
|
||||
.st_shndx = elf.SHN_ABS,
|
||||
.st_value = 0,
|
||||
.st_size = 0,
|
||||
});
|
||||
const off = try elf_file.strtab.insert(gpa, name);
|
||||
const gop = try elf_file.getOrPutGlobal(off);
|
||||
const gop = try elf_file.getOrPutGlobal(name);
|
||||
self.symbols.addOneAssumeCapacity().* = gop.index;
|
||||
return gop.index;
|
||||
}
|
||||
|
|
@ -37,7 +40,6 @@ pub fn resolveSymbols(self: *LinkerDefined, elf_file: *Elf) void {
|
|||
const global = elf_file.symbol(index);
|
||||
if (self.asFile().symbolRank(this_sym, false) < global.symbolRank(elf_file)) {
|
||||
global.value = 0;
|
||||
global.name_offset = global.name_offset;
|
||||
global.atom_index = 0;
|
||||
global.file_index = self.index;
|
||||
global.esym_index = sym_idx;
|
||||
|
|
@ -46,26 +48,6 @@ pub fn resolveSymbols(self: *LinkerDefined, elf_file: *Elf) void {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn updateSymtabSize(self: *LinkerDefined, 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;
|
||||
global.flags.output_symtab = true;
|
||||
self.output_symtab_size.nlocals += 1;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn writeSymtab(self: *LinkerDefined, elf_file: *Elf, ctx: anytype) void {
|
||||
var ilocal = ctx.ilocal;
|
||||
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[ilocal]);
|
||||
ilocal += 1;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn globals(self: *LinkerDefined) []const Symbol.Index {
|
||||
return self.symbols.items;
|
||||
}
|
||||
|
|
@ -74,6 +56,11 @@ pub fn asFile(self: *LinkerDefined) File {
|
|||
return .{ .linker_defined = self };
|
||||
}
|
||||
|
||||
pub fn getString(self: LinkerDefined, off: u32) [:0]const u8 {
|
||||
assert(off < self.strtab.items.len);
|
||||
return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.strtab.items.ptr + off)), 0);
|
||||
}
|
||||
|
||||
pub fn fmtSymtab(self: *LinkerDefined, elf_file: *Elf) std.fmt.Formatter(formatSymtab) {
|
||||
return .{ .data = .{
|
||||
.self = self,
|
||||
|
|
@ -101,12 +88,13 @@ fn formatSymtab(
|
|||
}
|
||||
}
|
||||
|
||||
const std = @import("std");
|
||||
const assert = std.debug.assert;
|
||||
const elf = std.elf;
|
||||
const mem = std.mem;
|
||||
const std = @import("std");
|
||||
|
||||
const Allocator = std.mem.Allocator;
|
||||
const Allocator = mem.Allocator;
|
||||
const Elf = @import("../Elf.zig");
|
||||
const File = @import("file.zig").File;
|
||||
const LinkerDefined = @This();
|
||||
// const Object = @import("Object.zig");
|
||||
const Symbol = @import("Symbol.zig");
|
||||
|
|
|
|||
|
|
@ -5,11 +5,10 @@ index: File.Index,
|
|||
|
||||
header: ?elf.Elf64_Ehdr = null,
|
||||
shdrs: std.ArrayListUnmanaged(ElfShdr) = .{},
|
||||
strings: StringTable(.object_strings) = .{},
|
||||
symtab: []align(1) const elf.Elf64_Sym = &[0]elf.Elf64_Sym{},
|
||||
strtab: []const u8 = &[0]u8{},
|
||||
first_global: ?Symbol.Index = null,
|
||||
|
||||
symtab: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{},
|
||||
strtab: std.ArrayListUnmanaged(u8) = .{},
|
||||
first_global: ?Symbol.Index = null,
|
||||
symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
|
||||
atoms: std.ArrayListUnmanaged(Atom.Index) = .{},
|
||||
comdat_groups: std.ArrayListUnmanaged(Elf.ComdatGroup.Index) = .{},
|
||||
|
|
@ -39,7 +38,8 @@ pub fn deinit(self: *Object, allocator: Allocator) void {
|
|||
allocator.free(self.path);
|
||||
allocator.free(self.data);
|
||||
self.shdrs.deinit(allocator);
|
||||
self.strings.deinit(allocator);
|
||||
self.symtab.deinit(allocator);
|
||||
self.strtab.deinit(allocator);
|
||||
self.symbols.deinit(allocator);
|
||||
self.atoms.deinit(allocator);
|
||||
self.comdat_groups.deinit(allocator);
|
||||
|
|
@ -68,7 +68,7 @@ pub fn parse(self: *Object, elf_file: *Elf) !void {
|
|||
self.shdrs.appendAssumeCapacity(try ElfShdr.fromElf64Shdr(shdr));
|
||||
}
|
||||
|
||||
try self.strings.buffer.appendSlice(gpa, self.shdrContents(self.header.?.e_shstrndx));
|
||||
try self.strtab.appendSlice(gpa, self.shdrContents(self.header.?.e_shstrndx));
|
||||
|
||||
const symtab_index = for (self.shdrs.items, 0..) |shdr, i| switch (shdr.sh_type) {
|
||||
elf.SHT_SYMTAB => break @as(u16, @intCast(i)),
|
||||
|
|
@ -79,10 +79,22 @@ pub fn parse(self: *Object, elf_file: *Elf) !void {
|
|||
const shdr = shdrs[index];
|
||||
self.first_global = shdr.sh_info;
|
||||
|
||||
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)));
|
||||
const raw_symtab = self.shdrContents(index);
|
||||
const nsyms = @divExact(raw_symtab.len, @sizeOf(elf.Elf64_Sym));
|
||||
const symtab = @as([*]align(1) const elf.Elf64_Sym, @ptrCast(raw_symtab.ptr))[0..nsyms];
|
||||
|
||||
const strtab_bias = @as(u32, @intCast(self.strtab.items.len));
|
||||
try self.strtab.appendSlice(gpa, self.shdrContents(@as(u16, @intCast(shdr.sh_link))));
|
||||
|
||||
try self.symtab.ensureUnusedCapacity(gpa, symtab.len);
|
||||
for (symtab) |sym| {
|
||||
const out_sym = self.symtab.addOneAssumeCapacity();
|
||||
out_sym.* = sym;
|
||||
out_sym.st_name = if (sym.st_name == 0 and sym.st_type() == elf.STT_SECTION)
|
||||
shdrs[sym.st_shndx].sh_name
|
||||
else
|
||||
sym.st_name + strtab_bias;
|
||||
}
|
||||
}
|
||||
|
||||
try self.initAtoms(elf_file);
|
||||
|
|
@ -108,16 +120,16 @@ fn initAtoms(self: *Object, elf_file: *Elf) !void {
|
|||
|
||||
switch (shdr.sh_type) {
|
||||
elf.SHT_GROUP => {
|
||||
if (shdr.sh_info >= self.symtab.len) {
|
||||
if (shdr.sh_info >= self.symtab.items.len) {
|
||||
// TODO convert into an error
|
||||
log.debug("{}: invalid symbol index in sh_info", .{self.fmtPath()});
|
||||
continue;
|
||||
}
|
||||
const group_info_sym = self.symtab[shdr.sh_info];
|
||||
const group_info_sym = self.symtab.items[shdr.sh_info];
|
||||
const group_signature = blk: {
|
||||
if (group_info_sym.st_name == 0 and group_info_sym.st_type() == elf.STT_SECTION) {
|
||||
const sym_shdr = shdrs[group_info_sym.st_shndx];
|
||||
break :blk self.strings.getAssumeExists(sym_shdr.sh_name);
|
||||
break :blk self.getString(sym_shdr.sh_name);
|
||||
}
|
||||
break :blk self.getString(group_info_sym.st_name);
|
||||
};
|
||||
|
|
@ -133,11 +145,8 @@ fn initAtoms(self: *Object, elf_file: *Elf) !void {
|
|||
continue;
|
||||
}
|
||||
|
||||
// Note the assumption about a global strtab used here to disambiguate common
|
||||
// COMDAT owners.
|
||||
const gpa = elf_file.base.allocator;
|
||||
const group_signature_off = try elf_file.strtab.insert(gpa, group_signature);
|
||||
const gop = try elf_file.getOrCreateComdatGroupOwner(group_signature_off);
|
||||
const gop = try elf_file.getOrCreateComdatGroupOwner(group_signature);
|
||||
const comdat_group_index = try elf_file.addComdatGroup();
|
||||
const comdat_group = elf_file.comdatGroup(comdat_group_index);
|
||||
comdat_group.* = .{
|
||||
|
|
@ -157,10 +166,9 @@ fn initAtoms(self: *Object, elf_file: *Elf) !void {
|
|||
=> {},
|
||||
|
||||
else => {
|
||||
const name = self.strings.getAssumeExists(shdr.sh_name);
|
||||
const shndx = @as(u16, @intCast(i));
|
||||
if (self.skipShdr(shndx, elf_file)) continue;
|
||||
try self.addAtom(shdr, shndx, name, elf_file);
|
||||
try self.addAtom(shdr, shndx, elf_file);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
@ -177,17 +185,11 @@ fn initAtoms(self: *Object, elf_file: *Elf) !void {
|
|||
};
|
||||
}
|
||||
|
||||
fn addAtom(
|
||||
self: *Object,
|
||||
shdr: ElfShdr,
|
||||
shndx: u16,
|
||||
name: [:0]const u8,
|
||||
elf_file: *Elf,
|
||||
) error{OutOfMemory}!void {
|
||||
fn addAtom(self: *Object, shdr: ElfShdr, shndx: u16, elf_file: *Elf) error{OutOfMemory}!void {
|
||||
const atom_index = try elf_file.addAtom();
|
||||
const atom = elf_file.atom(atom_index).?;
|
||||
atom.atom_index = atom_index;
|
||||
atom.name_offset = try elf_file.strtab.insert(elf_file.base.allocator, name);
|
||||
atom.name_offset = shdr.sh_name;
|
||||
atom.file_index = self.index;
|
||||
atom.input_section_index = shndx;
|
||||
self.atoms.items[shndx] = atom_index;
|
||||
|
|
@ -205,7 +207,7 @@ fn addAtom(
|
|||
|
||||
fn initOutputSection(self: Object, elf_file: *Elf, shdr: ElfShdr) error{OutOfMemory}!u16 {
|
||||
const name = blk: {
|
||||
const name = self.strings.getAssumeExists(shdr.sh_name);
|
||||
const name = self.getString(shdr.sh_name);
|
||||
if (shdr.sh_flags & elf.SHF_MERGE != 0) break :blk name;
|
||||
const sh_name_prefixes: []const [:0]const u8 = &.{
|
||||
".text", ".data.rel.ro", ".data", ".rodata", ".bss.rel.ro", ".bss",
|
||||
|
|
@ -248,7 +250,7 @@ fn initOutputSection(self: Object, elf_file: *Elf, shdr: ElfShdr) error{OutOfMem
|
|||
|
||||
fn skipShdr(self: *Object, index: u16, elf_file: *Elf) bool {
|
||||
const shdr = self.shdrs.items[index];
|
||||
const name = self.strings.getAssumeExists(shdr.sh_name);
|
||||
const name = self.getString(shdr.sh_name);
|
||||
const ignore = blk: {
|
||||
if (mem.startsWith(u8, name, ".note")) break :blk true;
|
||||
if (mem.startsWith(u8, name, ".comment")) break :blk true;
|
||||
|
|
@ -262,33 +264,24 @@ fn skipShdr(self: *Object, index: u16, elf_file: *Elf) bool {
|
|||
|
||||
fn initSymtab(self: *Object, elf_file: *Elf) !void {
|
||||
const gpa = elf_file.base.allocator;
|
||||
const first_global = self.first_global orelse self.symtab.len;
|
||||
const shdrs = self.shdrs.items;
|
||||
const first_global = self.first_global orelse self.symtab.items.len;
|
||||
|
||||
try self.symbols.ensureTotalCapacityPrecise(gpa, self.symtab.len);
|
||||
try self.symbols.ensureTotalCapacityPrecise(gpa, self.symtab.items.len);
|
||||
|
||||
for (self.symtab[0..first_global], 0..) |sym, i| {
|
||||
for (self.symtab.items[0..first_global], 0..) |sym, i| {
|
||||
const index = try elf_file.addSymbol();
|
||||
self.symbols.appendAssumeCapacity(index);
|
||||
const sym_ptr = elf_file.symbol(index);
|
||||
const name = blk: {
|
||||
if (sym.st_name == 0 and sym.st_type() == elf.STT_SECTION) {
|
||||
const shdr = shdrs[sym.st_shndx];
|
||||
break :blk self.strings.getAssumeExists(shdr.sh_name);
|
||||
}
|
||||
break :blk self.getString(sym.st_name);
|
||||
};
|
||||
sym_ptr.value = sym.st_value;
|
||||
sym_ptr.name_offset = try elf_file.strtab.insert(gpa, name);
|
||||
sym_ptr.name_offset = sym.st_name;
|
||||
sym_ptr.esym_index = @as(u32, @intCast(i));
|
||||
sym_ptr.atom_index = if (sym.st_shndx == elf.SHN_ABS) 0 else self.atoms.items[sym.st_shndx];
|
||||
sym_ptr.file_index = self.index;
|
||||
}
|
||||
|
||||
for (self.symtab[first_global..]) |sym| {
|
||||
for (self.symtab.items[first_global..]) |sym| {
|
||||
const name = self.getString(sym.st_name);
|
||||
const off = try elf_file.strtab.insert(gpa, name);
|
||||
const gop = try elf_file.getOrPutGlobal(off);
|
||||
const gop = try elf_file.getOrPutGlobal(name);
|
||||
self.symbols.addOneAssumeCapacity().* = gop.index;
|
||||
}
|
||||
}
|
||||
|
|
@ -437,7 +430,7 @@ pub fn resolveSymbols(self: *Object, elf_file: *Elf) void {
|
|||
const first_global = self.first_global orelse return;
|
||||
for (self.globals(), 0..) |index, i| {
|
||||
const esym_index = @as(Symbol.Index, @intCast(first_global + i));
|
||||
const esym = self.symtab[esym_index];
|
||||
const esym = self.symtab.items[esym_index];
|
||||
|
||||
if (esym.st_shndx == elf.SHN_UNDEF) continue;
|
||||
|
||||
|
|
@ -467,7 +460,7 @@ pub fn claimUnresolved(self: *Object, elf_file: *Elf) void {
|
|||
const first_global = self.first_global orelse return;
|
||||
for (self.globals(), 0..) |index, i| {
|
||||
const esym_index = @as(u32, @intCast(first_global + i));
|
||||
const esym = self.symtab[esym_index];
|
||||
const esym = self.symtab.items[esym_index];
|
||||
if (esym.st_shndx != elf.SHN_UNDEF) continue;
|
||||
|
||||
const global = elf_file.symbol(index);
|
||||
|
|
@ -491,20 +484,11 @@ pub fn claimUnresolved(self: *Object, elf_file: *Elf) void {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn resetGlobals(self: *Object, 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: *Object, elf_file: *Elf) void {
|
||||
const first_global = self.first_global orelse return;
|
||||
for (self.globals(), 0..) |index, i| {
|
||||
const sym_idx = first_global + i;
|
||||
const sym = self.symtab[sym_idx];
|
||||
const sym = self.symtab.items[sym_idx];
|
||||
if (sym.st_bind() == elf.STB_WEAK) continue;
|
||||
|
||||
const global = elf_file.symbol(index);
|
||||
|
|
@ -531,7 +515,7 @@ pub fn checkDuplicates(self: *Object, elf_file: *Elf) void {
|
|||
const first_global = self.first_global orelse return;
|
||||
for (self.globals(), 0..) |index, i| {
|
||||
const sym_idx = @as(u32, @intCast(first_global + i));
|
||||
const this_sym = self.symtab[sym_idx];
|
||||
const this_sym = self.symtab.items[sym_idx];
|
||||
const global = elf_file.symbol(index);
|
||||
const global_file = global.getFile(elf_file) orelse continue;
|
||||
|
||||
|
|
@ -560,7 +544,7 @@ pub fn convertCommonSymbols(self: *Object, elf_file: *Elf) !void {
|
|||
const first_global = self.first_global orelse return;
|
||||
for (self.globals(), 0..) |index, i| {
|
||||
const sym_idx = @as(u32, @intCast(first_global + i));
|
||||
const this_sym = self.symtab[sym_idx];
|
||||
const this_sym = self.symtab.items[sym_idx];
|
||||
if (this_sym.st_shndx != elf.SHN_COMMON) continue;
|
||||
|
||||
const global = elf_file.symbol(index);
|
||||
|
|
@ -584,8 +568,10 @@ pub fn convertCommonSymbols(self: *Object, elf_file: *Elf) !void {
|
|||
const name = if (is_tls) ".tls_common" else ".common";
|
||||
|
||||
const atom = elf_file.atom(atom_index).?;
|
||||
const name_offset = @as(u32, @intCast(self.strtab.items.len));
|
||||
try self.strtab.writer(gpa).print("{s}\x00", .{name});
|
||||
atom.atom_index = atom_index;
|
||||
atom.name_offset = try elf_file.strtab.insert(gpa, name);
|
||||
atom.name_offset = name_offset;
|
||||
atom.file_index = self.index;
|
||||
atom.size = this_sym.st_size;
|
||||
const alignment = this_sym.st_value;
|
||||
|
|
@ -597,7 +583,7 @@ pub fn convertCommonSymbols(self: *Object, elf_file: *Elf) !void {
|
|||
const shdr = try self.shdrs.addOne(gpa);
|
||||
const sh_size = math.cast(usize, this_sym.st_size) orelse return error.Overflow;
|
||||
shdr.* = .{
|
||||
.sh_name = try self.strings.insert(gpa, name),
|
||||
.sh_name = name_offset,
|
||||
.sh_type = elf.SHT_NOBITS,
|
||||
.sh_flags = sh_flags,
|
||||
.sh_addr = 0,
|
||||
|
|
@ -665,56 +651,6 @@ pub fn allocateAtoms(self: Object, elf_file: *Elf) void {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn updateSymtabSize(self: *Object, elf_file: *Elf) void {
|
||||
for (self.locals()) |local_index| {
|
||||
const local = elf_file.symbol(local_index);
|
||||
if (local.atom(elf_file)) |atom| if (!atom.flags.alive) continue;
|
||||
const esym = local.elfSym(elf_file);
|
||||
switch (esym.st_type()) {
|
||||
elf.STT_SECTION, elf.STT_NOTYPE => continue,
|
||||
else => {},
|
||||
}
|
||||
local.flags.output_symtab = true;
|
||||
self.output_symtab_size.nlocals += 1;
|
||||
}
|
||||
|
||||
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.atom(elf_file)) |atom| if (!atom.flags.alive) continue;
|
||||
global.flags.output_symtab = true;
|
||||
if (global.isLocal()) {
|
||||
self.output_symtab_size.nlocals += 1;
|
||||
} else {
|
||||
self.output_symtab_size.nglobals += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn writeSymtab(self: *Object, elf_file: *Elf, ctx: anytype) void {
|
||||
var ilocal = ctx.ilocal;
|
||||
for (self.locals()) |local_index| {
|
||||
const local = elf_file.symbol(local_index);
|
||||
if (!local.flags.output_symtab) continue;
|
||||
local.setOutputSym(elf_file, &ctx.symtab[ilocal]);
|
||||
ilocal += 1;
|
||||
}
|
||||
|
||||
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;
|
||||
if (global.isLocal()) {
|
||||
global.setOutputSym(elf_file, &ctx.symtab[ilocal]);
|
||||
ilocal += 1;
|
||||
} else {
|
||||
global.setOutputSym(elf_file, &ctx.symtab[iglobal]);
|
||||
iglobal += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn locals(self: Object) []const Symbol.Index {
|
||||
const end = self.first_global orelse self.symbols.items.len;
|
||||
return self.symbols.items[0..end];
|
||||
|
|
@ -760,11 +696,6 @@ pub fn codeDecompressAlloc(self: Object, elf_file: *Elf, atom_index: Atom.Index)
|
|||
} else return gpa.dupe(u8, data);
|
||||
}
|
||||
|
||||
fn getString(self: *Object, 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 comdatGroupMembers(self: *Object, index: u16) []align(1) const u32 {
|
||||
const raw = self.shdrContents(index);
|
||||
const nmembers = @divExact(raw.len, @sizeOf(u32));
|
||||
|
|
@ -782,6 +713,11 @@ pub fn getRelocs(self: *Object, shndx: u32) []align(1) const elf.Elf64_Rela {
|
|||
return @as([*]align(1) const elf.Elf64_Rela, @ptrCast(raw.ptr))[0..num];
|
||||
}
|
||||
|
||||
pub fn getString(self: Object, off: u32) [:0]const u8 {
|
||||
assert(off < self.strtab.items.len);
|
||||
return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.strtab.items.ptr + off)), 0);
|
||||
}
|
||||
|
||||
pub fn format(
|
||||
self: *Object,
|
||||
comptime unused_fmt_string: []const u8,
|
||||
|
|
@ -991,6 +927,5 @@ const Cie = eh_frame.Cie;
|
|||
const Elf = @import("../Elf.zig");
|
||||
const Fde = eh_frame.Fde;
|
||||
const File = @import("file.zig").File;
|
||||
const StringTable = @import("../strtab.zig").StringTable;
|
||||
const Symbol = @import("Symbol.zig");
|
||||
const Alignment = Atom.Alignment;
|
||||
|
|
|
|||
|
|
@ -4,19 +4,20 @@ 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{},
|
||||
|
||||
symtab: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{},
|
||||
strtab: std.ArrayListUnmanaged(u8) = .{},
|
||||
/// Version symtab contains version strings of the symbols if present.
|
||||
versyms: std.ArrayListUnmanaged(elf.Elf64_Versym) = .{},
|
||||
verstrings: std.ArrayListUnmanaged(u32) = .{},
|
||||
symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
|
||||
aliases: ?std.ArrayListUnmanaged(u32) = null,
|
||||
|
||||
dynsym_sect_index: ?u16 = null,
|
||||
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,
|
||||
|
||||
|
|
@ -36,6 +37,8 @@ pub fn isSharedObject(path: []const u8) !bool {
|
|||
pub fn deinit(self: *SharedObject, allocator: Allocator) void {
|
||||
allocator.free(self.path);
|
||||
allocator.free(self.data);
|
||||
self.symtab.deinit(allocator);
|
||||
self.strtab.deinit(allocator);
|
||||
self.versyms.deinit(allocator);
|
||||
self.verstrings.deinit(allocator);
|
||||
self.symbols.deinit(allocator);
|
||||
|
|
@ -51,7 +54,6 @@ pub fn parse(self: *SharedObject, elf_file: *Elf) !void {
|
|||
self.header = try reader.readStruct(elf.Elf64_Ehdr);
|
||||
const shoff = std.math.cast(usize, self.header.?.e_shoff) orelse return error.Overflow;
|
||||
|
||||
var dynsym_index: ?u16 = null;
|
||||
const shdrs = @as(
|
||||
[*]align(1) const elf.Elf64_Shdr,
|
||||
@ptrCast(self.data.ptr + shoff),
|
||||
|
|
@ -61,7 +63,7 @@ pub fn parse(self: *SharedObject, elf_file: *Elf) !void {
|
|||
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_DYNSYM => self.dynsym_sect_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)),
|
||||
|
|
@ -69,20 +71,13 @@ pub fn parse(self: *SharedObject, elf_file: *Elf) !void {
|
|||
}
|
||||
}
|
||||
|
||||
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;
|
||||
const symtab = self.getSymtabRaw();
|
||||
|
||||
try self.verstrings.resize(gpa, 2);
|
||||
self.verstrings.items[elf.VER_NDX_LOCAL] = 0;
|
||||
|
|
@ -107,7 +102,7 @@ fn parseVersions(self: *SharedObject, elf_file: *Elf) !void {
|
|||
}
|
||||
}
|
||||
|
||||
try self.versyms.ensureTotalCapacityPrecise(gpa, self.symtab.len);
|
||||
try self.versyms.ensureTotalCapacityPrecise(gpa, symtab.len);
|
||||
|
||||
if (self.versym_sect_index) |shndx| {
|
||||
const versyms_raw = self.shdrContents(shndx);
|
||||
|
|
@ -120,30 +115,39 @@ fn parseVersions(self: *SharedObject, elf_file: *Elf) !void {
|
|||
ver;
|
||||
self.versyms.appendAssumeCapacity(normalized_ver);
|
||||
}
|
||||
} else for (0..self.symtab.len) |_| {
|
||||
} else for (0..symtab.len) |_| {
|
||||
self.versyms.appendAssumeCapacity(elf.VER_NDX_GLOBAL);
|
||||
}
|
||||
}
|
||||
|
||||
fn initSymtab(self: *SharedObject, elf_file: *Elf) !void {
|
||||
const gpa = elf_file.base.allocator;
|
||||
const symtab = self.getSymtabRaw();
|
||||
const strtab = self.getStrtabRaw();
|
||||
|
||||
try self.symbols.ensureTotalCapacityPrecise(gpa, self.symtab.len);
|
||||
try self.strtab.appendSlice(gpa, strtab);
|
||||
try self.symtab.ensureTotalCapacityPrecise(gpa, symtab.len);
|
||||
try self.symbols.ensureTotalCapacityPrecise(gpa, symtab.len);
|
||||
|
||||
for (self.symtab, 0..) |sym, i| {
|
||||
for (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}", .{
|
||||
const name_off = if (hidden) blk: {
|
||||
const mangled = 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.getOrPutGlobal(off);
|
||||
defer gpa.free(mangled);
|
||||
const name_off = @as(u32, @intCast(self.strtab.items.len));
|
||||
try self.strtab.writer(gpa).print("{s}\x00", .{mangled});
|
||||
break :blk name_off;
|
||||
} else sym.st_name;
|
||||
const out_sym = self.symtab.addOneAssumeCapacity();
|
||||
out_sym.* = sym;
|
||||
out_sym.st_name = name_off;
|
||||
const gop = try elf_file.getOrPutGlobal(self.getString(name_off));
|
||||
self.symbols.addOneAssumeCapacity().* = gop.index;
|
||||
}
|
||||
}
|
||||
|
|
@ -151,7 +155,7 @@ fn initSymtab(self: *SharedObject, elf_file: *Elf) !void {
|
|||
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];
|
||||
const this_sym = self.symtab.items[esym_index];
|
||||
|
||||
if (this_sym.st_shndx == elf.SHN_UNDEF) continue;
|
||||
|
||||
|
|
@ -166,18 +170,9 @@ pub fn resolveSymbols(self: *SharedObject, elf_file: *Elf) void {
|
|||
}
|
||||
}
|
||||
|
||||
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];
|
||||
const sym = self.symtab.items[i];
|
||||
if (sym.st_shndx != elf.SHN_UNDEF) continue;
|
||||
|
||||
const global = elf_file.symbol(index);
|
||||
|
|
@ -193,27 +188,6 @@ pub fn markLive(self: *SharedObject, elf_file: *Elf) void {
|
|||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
@ -223,11 +197,6 @@ pub fn shdrContents(self: SharedObject, index: u16) []const u8 {
|
|||
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);
|
||||
|
|
@ -309,6 +278,25 @@ pub fn symbolAliases(self: *SharedObject, index: u32, elf_file: *Elf) []const u3
|
|||
return aliases.items[start..end];
|
||||
}
|
||||
|
||||
pub fn getString(self: SharedObject, off: u32) [:0]const u8 {
|
||||
assert(off < self.strtab.items.len);
|
||||
return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.strtab.items.ptr + off)), 0);
|
||||
}
|
||||
|
||||
pub fn getSymtabRaw(self: SharedObject) []align(1) const elf.Elf64_Sym {
|
||||
const index = self.dynsym_sect_index orelse return &[0]elf.Elf64_Sym{};
|
||||
const raw_symtab = self.shdrContents(index);
|
||||
const nsyms = @divExact(raw_symtab.len, @sizeOf(elf.Elf64_Sym));
|
||||
const symtab = @as([*]align(1) const elf.Elf64_Sym, @ptrCast(raw_symtab.ptr))[0..nsyms];
|
||||
return symtab;
|
||||
}
|
||||
|
||||
pub fn getStrtabRaw(self: SharedObject) []const u8 {
|
||||
const index = self.dynsym_sect_index orelse return &[0]u8{};
|
||||
const shdr = self.shdrs.items[index];
|
||||
return self.shdrContents(@as(u16, @intCast(shdr.sh_link)));
|
||||
}
|
||||
|
||||
pub fn format(
|
||||
self: SharedObject,
|
||||
comptime unused_fmt_string: []const u8,
|
||||
|
|
|
|||
|
|
@ -58,7 +58,11 @@ pub fn @"type"(symbol: Symbol, elf_file: *Elf) u4 {
|
|||
}
|
||||
|
||||
pub fn name(symbol: Symbol, elf_file: *Elf) [:0]const u8 {
|
||||
return elf_file.strtab.getAssumeExists(symbol.name_offset);
|
||||
if (symbol.flags.global) return elf_file.strings.getAssumeExists(symbol.name_offset);
|
||||
const file_ptr = symbol.file(elf_file).?;
|
||||
return switch (file_ptr) {
|
||||
inline else => |x| x.getString(symbol.name_offset),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn atom(symbol: Symbol, elf_file: *Elf) ?*Atom {
|
||||
|
|
@ -71,11 +75,10 @@ pub fn file(symbol: Symbol, elf_file: *Elf) ?File {
|
|||
|
||||
pub fn elfSym(symbol: Symbol, elf_file: *Elf) elf.Elf64_Sym {
|
||||
const file_ptr = symbol.file(elf_file).?;
|
||||
switch (file_ptr) {
|
||||
.zig_object => |x| return x.elfSym(symbol.esym_index).*,
|
||||
.linker_defined => |x| return x.symtab.items[symbol.esym_index],
|
||||
inline else => |x| return x.symtab[symbol.esym_index],
|
||||
}
|
||||
return switch (file_ptr) {
|
||||
.zig_object => |x| x.elfSym(symbol.esym_index).*,
|
||||
inline else => |x| x.symtab.items[symbol.esym_index],
|
||||
};
|
||||
}
|
||||
|
||||
pub fn symbolRank(symbol: Symbol, elf_file: *Elf) u32 {
|
||||
|
|
@ -201,10 +204,7 @@ pub fn setExtra(symbol: Symbol, extras: Extra, elf_file: *Elf) void {
|
|||
}
|
||||
|
||||
pub fn setOutputSym(symbol: Symbol, elf_file: *Elf, out: *elf.Elf64_Sym) void {
|
||||
const file_ptr = symbol.file(elf_file) orelse {
|
||||
out.* = Elf.null_sym;
|
||||
return;
|
||||
};
|
||||
const file_ptr = symbol.file(elf_file).?;
|
||||
const esym = symbol.elfSym(elf_file);
|
||||
const st_type = symbol.type(elf_file);
|
||||
const st_bind: u8 = blk: {
|
||||
|
|
@ -232,14 +232,11 @@ pub fn setOutputSym(symbol: Symbol, elf_file: *Elf, out: *elf.Elf64_Sym) void {
|
|||
break :blk symbol.value - elf_file.tlsAddress();
|
||||
break :blk symbol.value;
|
||||
};
|
||||
out.* = .{
|
||||
.st_name = symbol.name_offset,
|
||||
.st_info = (st_bind << 4) | st_type,
|
||||
.st_other = esym.st_other,
|
||||
.st_shndx = st_shndx,
|
||||
.st_value = st_value,
|
||||
.st_size = esym.st_size,
|
||||
};
|
||||
out.st_info = (st_bind << 4) | st_type;
|
||||
out.st_other = esym.st_other;
|
||||
out.st_shndx = st_shndx;
|
||||
out.st_value = st_value;
|
||||
out.st_size = esym.st_size;
|
||||
}
|
||||
|
||||
pub fn format(
|
||||
|
|
@ -340,6 +337,12 @@ pub const Flags = packed struct {
|
|||
/// Whether this symbol is weak.
|
||||
weak: bool = false,
|
||||
|
||||
/// Whether the symbol has its name interned in global symbol
|
||||
/// resolver table.
|
||||
/// This happens for any symbol that is considered a global
|
||||
/// symbol, but is not necessarily an import or export.
|
||||
global: bool = false,
|
||||
|
||||
/// Whether the symbol makes into the output symtab.
|
||||
output_symtab: bool = false,
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ index: File.Index,
|
|||
|
||||
local_esyms: std.MultiArrayList(ElfSym) = .{},
|
||||
global_esyms: std.MultiArrayList(ElfSym) = .{},
|
||||
strtab: std.ArrayListUnmanaged(u8) = .{},
|
||||
local_symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
|
||||
global_symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
|
||||
globals_lookup: std.AutoHashMapUnmanaged(u32, Symbol.Index) = .{},
|
||||
|
|
@ -74,8 +75,9 @@ pub fn init(self: *ZigObject, elf_file: *Elf) !void {
|
|||
const gpa = elf_file.base.allocator;
|
||||
|
||||
try self.atoms.append(gpa, 0); // null input section
|
||||
try self.strtab.append(gpa, 0);
|
||||
|
||||
const name_off = try elf_file.strtab.insert(gpa, std.fs.path.stem(self.path));
|
||||
const name_off = try self.insertString(gpa, std.fs.path.stem(self.path));
|
||||
const symbol_index = try elf_file.addSymbol();
|
||||
try self.local_symbols.append(gpa, symbol_index);
|
||||
const symbol_ptr = elf_file.symbol(symbol_index);
|
||||
|
|
@ -97,6 +99,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf) !void {
|
|||
pub fn deinit(self: *ZigObject, allocator: Allocator) void {
|
||||
self.local_esyms.deinit(allocator);
|
||||
self.global_esyms.deinit(allocator);
|
||||
self.strtab.deinit(allocator);
|
||||
self.local_symbols.deinit(allocator);
|
||||
self.global_symbols.deinit(allocator);
|
||||
self.globals_lookup.deinit(allocator);
|
||||
|
|
@ -379,15 +382,6 @@ pub fn scanRelocs(self: *ZigObject, elf_file: *Elf, undefs: anytype) !void {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn resetGlobals(self: *ZigObject, 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: *ZigObject, elf_file: *Elf) void {
|
||||
for (self.globals(), 0..) |index, i| {
|
||||
const esym = self.global_esyms.items(.elf_sym)[i];
|
||||
|
|
@ -404,60 +398,6 @@ pub fn markLive(self: *ZigObject, elf_file: *Elf) void {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn updateSymtabSize(self: *ZigObject, elf_file: *Elf) void {
|
||||
for (self.locals()) |local_index| {
|
||||
const local = elf_file.symbol(local_index);
|
||||
const esym = local.elfSym(elf_file);
|
||||
switch (esym.st_type()) {
|
||||
elf.STT_SECTION, elf.STT_NOTYPE => {
|
||||
local.flags.output_symtab = false;
|
||||
continue;
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
local.flags.output_symtab = true;
|
||||
self.output_symtab_size.nlocals += 1;
|
||||
}
|
||||
|
||||
for (self.globals()) |global_index| {
|
||||
const global = elf_file.symbol(global_index);
|
||||
if (global.file(elf_file)) |file| if (file.index() != self.index) {
|
||||
global.flags.output_symtab = false;
|
||||
continue;
|
||||
};
|
||||
global.flags.output_symtab = true;
|
||||
if (global.isLocal()) {
|
||||
self.output_symtab_size.nlocals += 1;
|
||||
} else {
|
||||
self.output_symtab_size.nglobals += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn writeSymtab(self: *ZigObject, elf_file: *Elf, ctx: anytype) void {
|
||||
var ilocal = ctx.ilocal;
|
||||
for (self.locals()) |local_index| {
|
||||
const local = elf_file.symbol(local_index);
|
||||
if (!local.flags.output_symtab) continue;
|
||||
local.setOutputSym(elf_file, &ctx.symtab[ilocal]);
|
||||
ilocal += 1;
|
||||
}
|
||||
|
||||
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;
|
||||
if (global.isLocal()) {
|
||||
global.setOutputSym(elf_file, &ctx.symtab[ilocal]);
|
||||
ilocal += 1;
|
||||
} else {
|
||||
global.setOutputSym(elf_file, &ctx.symtab[iglobal]);
|
||||
iglobal += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn symbol(self: *ZigObject, index: Symbol.Index) Symbol.Index {
|
||||
const is_global = index & global_symbol_bit != 0;
|
||||
const actual_index = index & symbol_mask;
|
||||
|
|
@ -727,7 +667,7 @@ fn updateDeclCode(
|
|||
sym.output_section_index = shdr_index;
|
||||
atom_ptr.output_section_index = shdr_index;
|
||||
|
||||
sym.name_offset = try elf_file.strtab.insert(gpa, decl_name);
|
||||
sym.name_offset = try self.insertString(gpa, decl_name);
|
||||
atom_ptr.flags.alive = true;
|
||||
atom_ptr.name_offset = sym.name_offset;
|
||||
esym.st_name = sym.name_offset;
|
||||
|
|
@ -967,7 +907,7 @@ fn updateLazySymbol(
|
|||
sym.ty.fmt(mod),
|
||||
});
|
||||
defer gpa.free(name);
|
||||
break :blk try elf_file.strtab.insert(gpa, name);
|
||||
break :blk try self.insertString(gpa, name);
|
||||
};
|
||||
|
||||
const src = if (sym.ty.getOwnerDeclOrNull(mod)) |owner_decl|
|
||||
|
|
@ -1100,7 +1040,7 @@ fn lowerConst(
|
|||
|
||||
const phdr_index = elf_file.phdr_to_shdr_table.get(output_section_index).?;
|
||||
const local_sym = elf_file.symbol(sym_index);
|
||||
const name_str_index = try elf_file.strtab.insert(gpa, name);
|
||||
const name_str_index = try self.insertString(gpa, name);
|
||||
local_sym.name_offset = name_str_index;
|
||||
local_sym.output_section_index = output_section_index;
|
||||
const local_esym = &self.local_esyms.items(.elf_sym)[local_sym.esym_index];
|
||||
|
|
@ -1195,8 +1135,8 @@ pub fn updateExports(
|
|||
};
|
||||
const stt_bits: u8 = @as(u4, @truncate(esym.st_info));
|
||||
const exp_name = mod.intern_pool.stringToSlice(exp.opts.name);
|
||||
const name_off = try elf_file.strtab.insert(gpa, exp_name);
|
||||
const global_esym_index = if (metadata.@"export"(self, elf_file, exp_name)) |exp_index|
|
||||
const name_off = try self.insertString(gpa, exp_name);
|
||||
const global_esym_index = if (metadata.@"export"(self, exp_name)) |exp_index|
|
||||
exp_index.*
|
||||
else blk: {
|
||||
const global_esym_index = try self.addGlobalEsym(gpa);
|
||||
|
|
@ -1205,7 +1145,7 @@ pub fn updateExports(
|
|||
global_esym.st_name = name_off;
|
||||
lookup_gop.value_ptr.* = global_esym_index;
|
||||
try metadata.exports.append(gpa, global_esym_index);
|
||||
const gop = try elf_file.getOrPutGlobal(name_off);
|
||||
const gop = try elf_file.getOrPutGlobal(exp_name);
|
||||
try self.global_symbols.append(gpa, gop.index);
|
||||
break :blk global_esym_index;
|
||||
};
|
||||
|
|
@ -1248,7 +1188,7 @@ pub fn deleteDeclExport(
|
|||
const metadata = self.decls.getPtr(decl_index) orelse return;
|
||||
const mod = elf_file.base.options.module.?;
|
||||
const exp_name = mod.intern_pool.stringToSlice(name);
|
||||
const esym_index = metadata.@"export"(self, elf_file, exp_name) orelse return;
|
||||
const esym_index = metadata.@"export"(self, exp_name) orelse return;
|
||||
log.debug("deleting export '{s}'", .{exp_name});
|
||||
const esym = &self.global_esyms.items(.elf_sym)[esym_index.*];
|
||||
_ = self.globals_lookup.remove(esym.st_name);
|
||||
|
|
@ -1265,19 +1205,31 @@ pub fn deleteDeclExport(
|
|||
pub fn getGlobalSymbol(self: *ZigObject, elf_file: *Elf, name: []const u8, lib_name: ?[]const u8) !u32 {
|
||||
_ = lib_name;
|
||||
const gpa = elf_file.base.allocator;
|
||||
const off = try elf_file.strtab.insert(gpa, name);
|
||||
const off = try self.insertString(gpa, name);
|
||||
const lookup_gop = try self.globals_lookup.getOrPut(gpa, off);
|
||||
if (!lookup_gop.found_existing) {
|
||||
const esym_index = try self.addGlobalEsym(gpa);
|
||||
const esym = self.elfSym(esym_index);
|
||||
esym.st_name = off;
|
||||
lookup_gop.value_ptr.* = esym_index;
|
||||
const gop = try elf_file.getOrPutGlobal(off);
|
||||
const gop = try elf_file.getOrPutGlobal(name);
|
||||
try self.global_symbols.append(gpa, gop.index);
|
||||
}
|
||||
return lookup_gop.value_ptr.*;
|
||||
}
|
||||
|
||||
pub fn getString(self: ZigObject, off: u32) [:0]const u8 {
|
||||
assert(off < self.strtab.items.len);
|
||||
return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.strtab.items.ptr + off)), 0);
|
||||
}
|
||||
|
||||
pub fn insertString(self: *ZigObject, allocator: Allocator, name: []const u8) error{OutOfMemory}!u32 {
|
||||
const off = @as(u32, @intCast(self.strtab.items.len));
|
||||
try self.strtab.ensureUnusedCapacity(allocator, name.len + 1);
|
||||
self.strtab.writer(allocator).print("{s}\x00", .{name}) catch unreachable;
|
||||
return off;
|
||||
}
|
||||
|
||||
pub fn fmtSymtab(self: *ZigObject, elf_file: *Elf) std.fmt.Formatter(formatSymtab) {
|
||||
return .{ .data = .{
|
||||
.self = self,
|
||||
|
|
@ -1350,9 +1302,9 @@ const DeclMetadata = struct {
|
|||
/// A list of all exports aliases of this Decl.
|
||||
exports: std.ArrayListUnmanaged(Symbol.Index) = .{},
|
||||
|
||||
fn @"export"(m: DeclMetadata, zig_object: *ZigObject, elf_file: *Elf, name: []const u8) ?*u32 {
|
||||
fn @"export"(m: DeclMetadata, zig_object: *ZigObject, name: []const u8) ?*u32 {
|
||||
for (m.exports.items) |*exp| {
|
||||
const exp_name = elf_file.strtab.getAssumeExists(zig_object.elfSym(exp.*).st_name);
|
||||
const exp_name = zig_object.getString(zig_object.elfSym(exp.*).st_name);
|
||||
if (mem.eql(u8, name, exp_name)) return exp;
|
||||
}
|
||||
return null;
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ pub const Fde = struct {
|
|||
pub fn atom(fde: Fde, elf_file: *Elf) *Atom {
|
||||
const object = elf_file.file(fde.file_index).?.object;
|
||||
const rel = fde.relocs(elf_file)[0];
|
||||
const sym = object.symtab[rel.r_sym()];
|
||||
const sym = object.symtab.items[rel.r_sym()];
|
||||
const atom_index = object.atoms.items[sym.st_shndx];
|
||||
return elf_file.atom(atom_index).?;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,9 +68,12 @@ pub const File = union(enum) {
|
|||
}
|
||||
|
||||
pub fn resetGlobals(file: File, elf_file: *Elf) void {
|
||||
switch (file) {
|
||||
.linker_defined => unreachable,
|
||||
inline else => |x| x.resetGlobals(elf_file),
|
||||
for (file.globals()) |global_index| {
|
||||
const global = elf_file.symbol(global_index);
|
||||
const name_offset = global.name_offset;
|
||||
global.* = .{};
|
||||
global.name_offset = name_offset;
|
||||
global.flags.global = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -83,15 +86,14 @@ pub const File = union(enum) {
|
|||
|
||||
pub fn markLive(file: File, elf_file: *Elf) void {
|
||||
switch (file) {
|
||||
.linker_defined => unreachable,
|
||||
.linker_defined => {},
|
||||
inline else => |x| x.markLive(elf_file),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn atoms(file: File) []const Atom.Index {
|
||||
return switch (file) {
|
||||
.linker_defined => unreachable,
|
||||
.shared_object => unreachable,
|
||||
.linker_defined, .shared_object => &[0]Atom.Index{},
|
||||
.zig_object => |x| x.atoms.items,
|
||||
.object => |x| x.atoms.items,
|
||||
};
|
||||
|
|
@ -99,8 +101,7 @@ pub const File = union(enum) {
|
|||
|
||||
pub fn locals(file: File) []const Symbol.Index {
|
||||
return switch (file) {
|
||||
.linker_defined => unreachable,
|
||||
.shared_object => unreachable,
|
||||
.linker_defined, .shared_object => &[0]Symbol.Index{},
|
||||
inline else => |x| x.locals(),
|
||||
};
|
||||
}
|
||||
|
|
@ -111,6 +112,74 @@ pub const File = union(enum) {
|
|||
};
|
||||
}
|
||||
|
||||
pub fn updateSymtabSize(file: File, elf_file: *Elf) void {
|
||||
const output_symtab_size = switch (file) {
|
||||
inline else => |x| &x.output_symtab_size,
|
||||
};
|
||||
for (file.locals()) |local_index| {
|
||||
const local = elf_file.symbol(local_index);
|
||||
if (local.atom(elf_file)) |atom| if (!atom.flags.alive) continue;
|
||||
const esym = local.elfSym(elf_file);
|
||||
switch (esym.st_type()) {
|
||||
elf.STT_SECTION, elf.STT_NOTYPE => continue,
|
||||
else => {},
|
||||
}
|
||||
local.flags.output_symtab = true;
|
||||
output_symtab_size.nlocals += 1;
|
||||
output_symtab_size.strsize += @as(u32, @intCast(local.name(elf_file).len)) + 1;
|
||||
}
|
||||
|
||||
for (file.globals()) |global_index| {
|
||||
const global = elf_file.symbol(global_index);
|
||||
const file_ptr = global.file(elf_file) orelse continue;
|
||||
if (file_ptr.index() != file.index()) continue;
|
||||
if (global.atom(elf_file)) |atom| if (!atom.flags.alive) continue;
|
||||
global.flags.output_symtab = true;
|
||||
if (global.isLocal()) {
|
||||
output_symtab_size.nlocals += 1;
|
||||
} else {
|
||||
output_symtab_size.nglobals += 1;
|
||||
}
|
||||
output_symtab_size.strsize += @as(u32, @intCast(global.name(elf_file).len)) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn writeSymtab(file: File, elf_file: *Elf, ctx: anytype) void {
|
||||
var ilocal = ctx.ilocal;
|
||||
for (file.locals()) |local_index| {
|
||||
const local = elf_file.symbol(local_index);
|
||||
if (!local.flags.output_symtab) continue;
|
||||
const out_sym = &elf_file.symtab.items[ilocal];
|
||||
out_sym.st_name = @intCast(elf_file.strtab.items.len);
|
||||
elf_file.strtab.appendSliceAssumeCapacity(local.name(elf_file));
|
||||
elf_file.strtab.appendAssumeCapacity(0);
|
||||
local.setOutputSym(elf_file, out_sym);
|
||||
ilocal += 1;
|
||||
}
|
||||
|
||||
var iglobal = ctx.iglobal;
|
||||
for (file.globals()) |global_index| {
|
||||
const global = elf_file.symbol(global_index);
|
||||
const file_ptr = global.file(elf_file) orelse continue;
|
||||
if (file_ptr.index() != file.index()) continue;
|
||||
if (!global.flags.output_symtab) continue;
|
||||
const st_name = @as(u32, @intCast(elf_file.strtab.items.len));
|
||||
elf_file.strtab.appendSliceAssumeCapacity(global.name(elf_file));
|
||||
elf_file.strtab.appendAssumeCapacity(0);
|
||||
if (global.isLocal()) {
|
||||
const out_sym = &elf_file.symtab.items[ilocal];
|
||||
out_sym.st_name = st_name;
|
||||
global.setOutputSym(elf_file, out_sym);
|
||||
ilocal += 1;
|
||||
} else {
|
||||
const out_sym = &elf_file.symtab.items[iglobal];
|
||||
out_sym.st_name = st_name;
|
||||
global.setOutputSym(elf_file, out_sym);
|
||||
iglobal += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub const Index = u32;
|
||||
|
||||
pub const Entry = union(enum) {
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ pub const DynamicSection = struct {
|
|||
|
||||
pub fn addNeeded(dt: *DynamicSection, shared: *SharedObject, elf_file: *Elf) !void {
|
||||
const gpa = elf_file.base.allocator;
|
||||
const off = try elf_file.dynstrtab.insert(gpa, shared.soname());
|
||||
const off = try elf_file.insertDynString(shared.soname());
|
||||
try dt.needed.append(gpa, off);
|
||||
}
|
||||
|
||||
|
|
@ -22,11 +22,11 @@ pub const DynamicSection = struct {
|
|||
if (i > 0) try rpath.append(':');
|
||||
try rpath.appendSlice(path);
|
||||
}
|
||||
dt.rpath = try elf_file.dynstrtab.insert(gpa, rpath.items);
|
||||
dt.rpath = try elf_file.insertDynString(rpath.items);
|
||||
}
|
||||
|
||||
pub fn setSoname(dt: *DynamicSection, soname: []const u8, elf_file: *Elf) !void {
|
||||
dt.soname = try elf_file.dynstrtab.insert(elf_file.base.allocator, soname);
|
||||
dt.soname = try elf_file.insertDynString(soname);
|
||||
}
|
||||
|
||||
fn getFlags(dt: DynamicSection, elf_file: *Elf) ?u64 {
|
||||
|
|
@ -359,31 +359,24 @@ pub const ZigGotSection = struct {
|
|||
}
|
||||
|
||||
pub fn updateSymtabSize(zig_got: *ZigGotSection, elf_file: *Elf) void {
|
||||
_ = elf_file;
|
||||
zig_got.output_symtab_size.nlocals = @as(u32, @intCast(zig_got.entries.items.len));
|
||||
}
|
||||
|
||||
pub fn updateStrtab(zig_got: ZigGotSection, elf_file: *Elf) !void {
|
||||
const gpa = elf_file.base.allocator;
|
||||
for (zig_got.entries.items) |entry| {
|
||||
const symbol_name = elf_file.symbol(entry).name(elf_file);
|
||||
const name = try std.fmt.allocPrint(gpa, "{s}$ziggot", .{symbol_name});
|
||||
defer gpa.free(name);
|
||||
_ = try elf_file.strtab.insert(gpa, name);
|
||||
const name = elf_file.symbol(entry).name(elf_file);
|
||||
zig_got.output_symtab_size.strsize += @as(u32, @intCast(name.len + "$ziggot".len)) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn writeSymtab(zig_got: ZigGotSection, elf_file: *Elf, ctx: anytype) !void {
|
||||
const gpa = elf_file.base.allocator;
|
||||
pub fn writeSymtab(zig_got: ZigGotSection, elf_file: *Elf, ctx: anytype) void {
|
||||
for (zig_got.entries.items, ctx.ilocal.., 0..) |entry, ilocal, index| {
|
||||
const symbol = elf_file.symbol(entry);
|
||||
const symbol_name = symbol.name(elf_file);
|
||||
const name = try std.fmt.allocPrint(gpa, "{s}$ziggot", .{symbol_name});
|
||||
defer gpa.free(name);
|
||||
const st_name = try elf_file.strtab.insert(gpa, name);
|
||||
const st_name = @as(u32, @intCast(elf_file.strtab.items.len));
|
||||
elf_file.strtab.appendSliceAssumeCapacity(symbol_name);
|
||||
elf_file.strtab.appendSliceAssumeCapacity("$ziggot");
|
||||
elf_file.strtab.appendAssumeCapacity(0);
|
||||
const st_value = zig_got.entryAddress(@intCast(index), elf_file);
|
||||
const st_size = elf_file.archPtrWidthBytes();
|
||||
ctx.symtab[ilocal] = .{
|
||||
elf_file.symtab.items[ilocal] = .{
|
||||
.st_name = st_name,
|
||||
.st_info = elf.STT_OBJECT,
|
||||
.st_other = 0,
|
||||
|
|
@ -767,25 +760,17 @@ pub const GotSection = struct {
|
|||
}
|
||||
|
||||
pub fn updateSymtabSize(got: *GotSection, elf_file: *Elf) void {
|
||||
_ = elf_file;
|
||||
got.output_symtab_size.nlocals = @as(u32, @intCast(got.entries.items.len));
|
||||
}
|
||||
|
||||
pub fn updateStrtab(got: GotSection, elf_file: *Elf) !void {
|
||||
const gpa = elf_file.base.allocator;
|
||||
for (got.entries.items) |entry| {
|
||||
const symbol_name = switch (entry.tag) {
|
||||
.tlsld => "",
|
||||
inline else => elf_file.symbol(entry.symbol_index).name(elf_file),
|
||||
};
|
||||
const name = try std.fmt.allocPrint(gpa, "{s}${s}", .{ symbol_name, @tagName(entry.tag) });
|
||||
defer gpa.free(name);
|
||||
_ = try elf_file.strtab.insert(gpa, name);
|
||||
got.output_symtab_size.strsize += @as(u32, @intCast(symbol_name.len + @tagName(entry.tag).len)) + 1 + 1;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn writeSymtab(got: GotSection, elf_file: *Elf, ctx: anytype) !void {
|
||||
const gpa = elf_file.base.allocator;
|
||||
pub fn writeSymtab(got: GotSection, elf_file: *Elf, ctx: anytype) void {
|
||||
for (got.entries.items, ctx.ilocal..) |entry, ilocal| {
|
||||
const symbol = switch (entry.tag) {
|
||||
.tlsld => null,
|
||||
|
|
@ -795,12 +780,14 @@ pub const GotSection = struct {
|
|||
.tlsld => "",
|
||||
inline else => symbol.?.name(elf_file),
|
||||
};
|
||||
const name = try std.fmt.allocPrint(gpa, "{s}${s}", .{ symbol_name, @tagName(entry.tag) });
|
||||
defer gpa.free(name);
|
||||
const st_name = try elf_file.strtab.insert(gpa, name);
|
||||
const st_name = @as(u32, @intCast(elf_file.strtab.items.len));
|
||||
elf_file.strtab.appendSliceAssumeCapacity(symbol_name);
|
||||
elf_file.strtab.appendAssumeCapacity('$');
|
||||
elf_file.strtab.appendSliceAssumeCapacity(@tagName(entry.tag));
|
||||
elf_file.strtab.appendAssumeCapacity(0);
|
||||
const st_value = entry.address(elf_file);
|
||||
const st_size: u64 = entry.len() * elf_file.archPtrWidthBytes();
|
||||
ctx.symtab[ilocal] = .{
|
||||
elf_file.symtab.items[ilocal] = .{
|
||||
.st_name = st_name,
|
||||
.st_info = elf.STT_OBJECT,
|
||||
.st_other = 0,
|
||||
|
|
@ -922,30 +909,22 @@ pub const PltSection = struct {
|
|||
}
|
||||
|
||||
pub fn updateSymtabSize(plt: *PltSection, elf_file: *Elf) void {
|
||||
_ = elf_file;
|
||||
plt.output_symtab_size.nlocals = @as(u32, @intCast(plt.symbols.items.len));
|
||||
}
|
||||
|
||||
pub fn updateStrtab(plt: PltSection, elf_file: *Elf) !void {
|
||||
const gpa = elf_file.base.allocator;
|
||||
for (plt.symbols.items) |sym_index| {
|
||||
const sym = elf_file.symbol(sym_index);
|
||||
const name = try std.fmt.allocPrint(gpa, "{s}$plt", .{sym.name(elf_file)});
|
||||
defer gpa.free(name);
|
||||
_ = try elf_file.strtab.insert(gpa, name);
|
||||
const name = elf_file.symbol(sym_index).name(elf_file);
|
||||
plt.output_symtab_size.strsize += @as(u32, @intCast(name.len + "$plt".len)) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn writeSymtab(plt: PltSection, elf_file: *Elf, ctx: anytype) !void {
|
||||
const gpa = elf_file.base.allocator;
|
||||
|
||||
pub fn writeSymtab(plt: PltSection, elf_file: *Elf, ctx: anytype) void {
|
||||
var ilocal = ctx.ilocal;
|
||||
for (plt.symbols.items) |sym_index| {
|
||||
const sym = elf_file.symbol(sym_index);
|
||||
const name = try std.fmt.allocPrint(gpa, "{s}$plt", .{sym.name(elf_file)});
|
||||
defer gpa.free(name);
|
||||
const st_name = try elf_file.strtab.insert(gpa, name);
|
||||
ctx.symtab[ilocal] = .{
|
||||
const st_name = @as(u32, @intCast(elf_file.strtab.items.len));
|
||||
elf_file.strtab.appendSliceAssumeCapacity(sym.name(elf_file));
|
||||
elf_file.strtab.appendSliceAssumeCapacity("$plt");
|
||||
elf_file.strtab.appendAssumeCapacity(0);
|
||||
elf_file.symtab.items[ilocal] = .{
|
||||
.st_name = st_name,
|
||||
.st_info = elf.STT_FUNC,
|
||||
.st_other = 0,
|
||||
|
|
@ -1029,29 +1008,22 @@ pub const PltGotSection = struct {
|
|||
}
|
||||
|
||||
pub fn updateSymtabSize(plt_got: *PltGotSection, elf_file: *Elf) void {
|
||||
_ = elf_file;
|
||||
plt_got.output_symtab_size.nlocals = @as(u32, @intCast(plt_got.symbols.items.len));
|
||||
}
|
||||
|
||||
pub fn updateStrtab(plt_got: PltGotSection, elf_file: *Elf) !void {
|
||||
const gpa = elf_file.base.allocator;
|
||||
for (plt_got.symbols.items) |sym_index| {
|
||||
const sym = elf_file.symbol(sym_index);
|
||||
const name = try std.fmt.allocPrint(gpa, "{s}$pltgot", .{sym.name(elf_file)});
|
||||
defer gpa.free(name);
|
||||
_ = try elf_file.strtab.insert(gpa, name);
|
||||
const name = elf_file.symbol(sym_index).name(elf_file);
|
||||
plt_got.output_symtab_size.strsize += @as(u32, @intCast(name.len + "$pltgot".len)) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn writeSymtab(plt_got: PltGotSection, elf_file: *Elf, ctx: anytype) !void {
|
||||
const gpa = elf_file.base.allocator;
|
||||
pub fn writeSymtab(plt_got: PltGotSection, elf_file: *Elf, ctx: anytype) void {
|
||||
var ilocal = ctx.ilocal;
|
||||
for (plt_got.symbols.items) |sym_index| {
|
||||
const sym = elf_file.symbol(sym_index);
|
||||
const name = try std.fmt.allocPrint(gpa, "{s}$pltgot", .{sym.name(elf_file)});
|
||||
defer gpa.free(name);
|
||||
const st_name = try elf_file.strtab.insert(gpa, name);
|
||||
ctx.symtab[ilocal] = .{
|
||||
const st_name = @as(u32, @intCast(elf_file.strtab.items.len));
|
||||
elf_file.strtab.appendSliceAssumeCapacity(sym.name(elf_file));
|
||||
elf_file.strtab.appendSliceAssumeCapacity("$pltgot");
|
||||
elf_file.strtab.appendAssumeCapacity(0);
|
||||
elf_file.symtab.items[ilocal] = .{
|
||||
.st_name = st_name,
|
||||
.st_info = elf.STT_FUNC,
|
||||
.st_other = 0,
|
||||
|
|
@ -1166,7 +1138,7 @@ pub const DynsymSection = struct {
|
|||
new_extra.dynamic = index;
|
||||
sym.setExtra(new_extra, elf_file);
|
||||
} else try sym.addExtra(.{ .dynamic = index }, elf_file);
|
||||
const off = try elf_file.dynstrtab.insert(gpa, sym.name(elf_file));
|
||||
const off = try elf_file.insertDynString(sym.name(elf_file));
|
||||
try dynsym.entries.append(gpa, .{ .symbol_index = sym_index, .off = off });
|
||||
}
|
||||
|
||||
|
|
@ -1251,7 +1223,7 @@ pub const HashSection = struct {
|
|||
@memset(chains, 0);
|
||||
|
||||
for (elf_file.dynsym.entries.items, 1..) |entry, i| {
|
||||
const name = elf_file.dynstrtab.getAssumeExists(entry.off);
|
||||
const name = elf_file.getDynString(entry.off);
|
||||
const hash = hasher(name) % buckets.len;
|
||||
chains[@as(u32, @intCast(i))] = buckets[hash];
|
||||
buckets[hash] = @as(u32, @intCast(i));
|
||||
|
|
@ -1490,7 +1462,7 @@ pub const VerneedSection = struct {
|
|||
sym.* = .{
|
||||
.vn_version = 1,
|
||||
.vn_cnt = 0,
|
||||
.vn_file = try elf_file.dynstrtab.insert(gpa, soname),
|
||||
.vn_file = try elf_file.insertDynString(soname),
|
||||
.vn_aux = 0,
|
||||
.vn_next = 0,
|
||||
};
|
||||
|
|
@ -1509,7 +1481,7 @@ pub const VerneedSection = struct {
|
|||
.vna_hash = HashSection.hasher(version),
|
||||
.vna_flags = 0,
|
||||
.vna_other = vern.index,
|
||||
.vna_name = try elf_file.dynstrtab.insert(gpa, version),
|
||||
.vna_name = try elf_file.insertDynString(version),
|
||||
.vna_next = 0,
|
||||
};
|
||||
verneed_sym.vn_cnt += 1;
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ globals_free_list: std.ArrayListUnmanaged(u32) = .{},
|
|||
dyld_stub_binder_index: ?u32 = null,
|
||||
dyld_private_atom_index: ?Atom.Index = null,
|
||||
|
||||
strtab: StringTable(.strtab) = .{},
|
||||
strtab: StringTable = .{},
|
||||
|
||||
got_table: TableSection(SymbolWithLoc) = .{},
|
||||
stub_table: TableSection(SymbolWithLoc) = .{},
|
||||
|
|
@ -5643,7 +5643,7 @@ const Module = @import("../Module.zig");
|
|||
const InternPool = @import("../InternPool.zig");
|
||||
const Platform = load_commands.Platform;
|
||||
const Relocation = @import("MachO/Relocation.zig");
|
||||
const StringTable = @import("strtab.zig").StringTable;
|
||||
const StringTable = @import("StringTable.zig");
|
||||
const TableSection = @import("table_section.zig").TableSection;
|
||||
const Trie = @import("MachO/Trie.zig");
|
||||
const Type = @import("../type.zig").Type;
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ debug_aranges_section_dirty: bool = false,
|
|||
debug_info_header_dirty: bool = false,
|
||||
debug_line_header_dirty: bool = false,
|
||||
|
||||
strtab: StringTable(.strtab) = .{},
|
||||
strtab: StringTable = .{},
|
||||
relocs: std.ArrayListUnmanaged(Reloc) = .{},
|
||||
|
||||
pub const Reloc = struct {
|
||||
|
|
@ -567,5 +567,5 @@ const Allocator = mem.Allocator;
|
|||
const Dwarf = @import("../Dwarf.zig");
|
||||
const MachO = @import("../MachO.zig");
|
||||
const Module = @import("../../Module.zig");
|
||||
const StringTable = @import("../strtab.zig").StringTable;
|
||||
const StringTable = @import("../StringTable.zig");
|
||||
const Type = @import("../../type.zig").Type;
|
||||
|
|
|
|||
|
|
@ -1227,7 +1227,6 @@ const LibStub = @import("../tapi.zig").LibStub;
|
|||
const Object = @import("Object.zig");
|
||||
const Platform = load_commands.Platform;
|
||||
const Section = MachO.Section;
|
||||
const StringTable = @import("../strtab.zig").StringTable;
|
||||
const SymbolWithLoc = MachO.SymbolWithLoc;
|
||||
const TableSection = @import("../table_section.zig").TableSection;
|
||||
const Trie = @import("Trie.zig");
|
||||
|
|
|
|||
|
|
@ -1,121 +0,0 @@
|
|||
const std = @import("std");
|
||||
const mem = std.mem;
|
||||
|
||||
const Allocator = mem.Allocator;
|
||||
const StringIndexAdapter = std.hash_map.StringIndexAdapter;
|
||||
const StringIndexContext = std.hash_map.StringIndexContext;
|
||||
|
||||
pub fn StringTable(comptime log_scope: @Type(.EnumLiteral)) type {
|
||||
return struct {
|
||||
const Self = @This();
|
||||
|
||||
const log = std.log.scoped(log_scope);
|
||||
|
||||
buffer: std.ArrayListUnmanaged(u8) = .{},
|
||||
table: std.HashMapUnmanaged(u32, bool, StringIndexContext, std.hash_map.default_max_load_percentage) = .{},
|
||||
|
||||
pub fn deinit(self: *Self, gpa: Allocator) void {
|
||||
self.buffer.deinit(gpa);
|
||||
self.table.deinit(gpa);
|
||||
}
|
||||
|
||||
pub fn toOwnedSlice(self: *Self, gpa: Allocator) []const u8 {
|
||||
const result = self.buffer.toOwnedSlice(gpa);
|
||||
self.table.clearRetainingCapacity();
|
||||
return result;
|
||||
}
|
||||
|
||||
pub const PrunedResult = struct {
|
||||
buffer: []const u8,
|
||||
idx_map: std.AutoHashMap(u32, u32),
|
||||
};
|
||||
|
||||
pub fn toPrunedResult(self: *Self, gpa: Allocator) !PrunedResult {
|
||||
var buffer = std.ArrayList(u8).init(gpa);
|
||||
defer buffer.deinit();
|
||||
try buffer.ensureTotalCapacity(self.buffer.items.len);
|
||||
buffer.appendAssumeCapacity(0);
|
||||
|
||||
var idx_map = std.AutoHashMap(u32, u32).init(gpa);
|
||||
errdefer idx_map.deinit();
|
||||
try idx_map.ensureTotalCapacity(self.table.count());
|
||||
|
||||
var it = self.table.iterator();
|
||||
while (it.next()) |entry| {
|
||||
const off = entry.key_ptr.*;
|
||||
const save = entry.value_ptr.*;
|
||||
if (!save) continue;
|
||||
const new_off = @as(u32, @intCast(buffer.items.len));
|
||||
buffer.appendSliceAssumeCapacity(self.getAssumeExists(off));
|
||||
idx_map.putAssumeCapacityNoClobber(off, new_off);
|
||||
}
|
||||
|
||||
self.buffer.clearRetainingCapacity();
|
||||
self.table.clearRetainingCapacity();
|
||||
|
||||
return PrunedResult{
|
||||
.buffer = buffer.toOwnedSlice(),
|
||||
.idx_map = idx_map,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn insert(self: *Self, gpa: Allocator, string: []const u8) !u32 {
|
||||
const gop = try self.table.getOrPutContextAdapted(gpa, @as([]const u8, string), StringIndexAdapter{
|
||||
.bytes = &self.buffer,
|
||||
}, StringIndexContext{
|
||||
.bytes = &self.buffer,
|
||||
});
|
||||
if (gop.found_existing) {
|
||||
const off = gop.key_ptr.*;
|
||||
gop.value_ptr.* = true;
|
||||
log.debug("reusing string '{s}' at offset 0x{x}", .{ string, off });
|
||||
return off;
|
||||
}
|
||||
|
||||
try self.buffer.ensureUnusedCapacity(gpa, string.len + 1);
|
||||
const new_off = @as(u32, @intCast(self.buffer.items.len));
|
||||
|
||||
log.debug("writing new string '{s}' at offset 0x{x}", .{ string, new_off });
|
||||
|
||||
self.buffer.appendSliceAssumeCapacity(string);
|
||||
self.buffer.appendAssumeCapacity(0);
|
||||
|
||||
gop.key_ptr.* = new_off;
|
||||
gop.value_ptr.* = true;
|
||||
|
||||
return new_off;
|
||||
}
|
||||
|
||||
pub fn delete(self: *Self, string: []const u8) void {
|
||||
const value_ptr = self.table.getPtrAdapted(@as([]const u8, string), StringIndexAdapter{
|
||||
.bytes = &self.buffer,
|
||||
}) orelse return;
|
||||
value_ptr.* = false;
|
||||
log.debug("marked '{s}' for deletion", .{string});
|
||||
}
|
||||
|
||||
pub fn getOffset(self: *Self, string: []const u8) ?u32 {
|
||||
return self.table.getKeyAdapted(string, StringIndexAdapter{
|
||||
.bytes = &self.buffer,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn get(self: Self, off: u32) ?[:0]const u8 {
|
||||
log.debug("getting string at 0x{x}", .{off});
|
||||
if (off >= self.buffer.items.len) return null;
|
||||
return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.buffer.items.ptr + off)), 0);
|
||||
}
|
||||
|
||||
pub fn getAssumeExists(self: Self, off: u32) [:0]const u8 {
|
||||
return self.get(off) orelse unreachable;
|
||||
}
|
||||
|
||||
pub fn items(self: Self) []const u8 {
|
||||
return self.buffer.items;
|
||||
}
|
||||
|
||||
pub fn len(self: Self) usize {
|
||||
return self.buffer.items.len;
|
||||
}
|
||||
};
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue