elf: allocate linker defined symbols

This commit is contained in:
Jakub Konka 2023-09-10 11:10:16 +02:00
parent 1c3fd16c37
commit a3ce011408

View File

@ -47,8 +47,13 @@ got: GotSection = .{},
text_section_index: ?u16 = null,
rodata_section_index: ?u16 = null,
got_section_index: ?u16 = null,
data_section_index: ?u16 = null,
dynamic_section_index: ?u16 = null,
got_section_index: ?u16 = null,
got_plt_section_index: ?u16 = null,
plt_section_index: ?u16 = null,
eh_frame_hdr_section_index: ?u16 = null,
rela_dyn_section_index: ?u16 = null,
debug_info_section_index: ?u16 = null,
debug_abbrev_section_index: ?u16 = null,
debug_str_section_index: ?u16 = null,
@ -74,6 +79,7 @@ gnu_eh_frame_hdr_index: ?Symbol.Index = null,
dso_handle_index: ?Symbol.Index = null,
rela_iplt_start_index: ?Symbol.Index = null,
rela_iplt_end_index: ?Symbol.Index = null,
start_stop_indexes: std.ArrayListUnmanaged(u32) = .{},
symbols: std.ArrayListUnmanaged(Symbol) = .{},
symbols_extra: std.ArrayListUnmanaged(u32) = .{},
@ -264,6 +270,7 @@ pub fn deinit(self: *Elf) void {
self.got.deinit(gpa);
self.resolver.deinit(gpa);
self.unresolved.deinit(gpa);
self.start_stop_indexes.deinit(gpa);
{
var it = self.decls.iterator();
@ -385,6 +392,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
.p64 => false,
};
const ptr_size: u8 = self.ptrWidthBytes();
const image_base = self.calcImageBase();
if (self.phdr_table_index == null) {
self.phdr_table_index = @as(u16, @intCast(self.phdrs.items.len));
@ -396,8 +404,8 @@ pub fn populateMissingMetadata(self: *Elf) !void {
.p_type = elf.PT_PHDR,
.p_offset = 0,
.p_filesz = 0,
.p_vaddr = 0,
.p_paddr = 0,
.p_vaddr = image_base,
.p_paddr = image_base,
.p_memsz = 0,
.p_align = p_align,
.p_flags = elf.PF_R,
@ -408,16 +416,14 @@ pub fn populateMissingMetadata(self: *Elf) !void {
if (self.phdr_table_load_index == null) {
self.phdr_table_load_index = @as(u16, @intCast(self.phdrs.items.len));
// TODO Same as for GOT
const phdr_addr: u64 = if (self.base.options.target.ptrBitWidth() >= 32) 0x1000000 else 0x1000;
const p_align = self.page_size;
try self.phdrs.append(gpa, .{
.p_type = elf.PT_LOAD,
.p_offset = 0,
.p_filesz = 0,
.p_vaddr = phdr_addr,
.p_paddr = phdr_addr,
.p_vaddr = image_base,
.p_paddr = image_base,
.p_memsz = 0,
.p_align = p_align,
.p_align = self.page_size,
.p_flags = elf.PF_R,
});
self.phdr_table_dirty = true;
@ -429,7 +435,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
const p_align = self.page_size;
const off = self.findFreeSpace(file_size, p_align);
log.debug("found PT_LOAD RE free space 0x{x} to 0x{x}", .{ off, off + file_size });
const entry_addr: u64 = self.entry_addr orelse if (self.base.options.target.cpu.arch == .spu_2) @as(u64, 0) else default_entry_addr;
const entry_addr = self.defaultEntryAddress();
try self.phdrs.append(gpa, .{
.p_type = elf.PT_LOAD,
.p_offset = off,
@ -1055,6 +1061,8 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
try self.addLinkerDefinedSymbols();
self.allocateLinkerDefinedSymbols();
// Beyond this point, everything has been allocated a virtual address and we can resolve
// the relocations.
{
@ -2764,6 +2772,129 @@ fn addLinkerDefinedSymbols(self: *Elf) !void {
linker_defined.resolveSymbols(self);
}
fn allocateLinkerDefinedSymbols(self: *Elf) void {
// _DYNAMIC
if (self.dynamic_section_index) |shndx| {
const shdr = self.sections.items(.shdr)[shndx];
const symbol_ptr = self.symbol(self.dynamic_index.?);
symbol_ptr.value = shdr.sh_addr;
symbol_ptr.output_section_index = shndx;
}
// __ehdr_start
{
const symbol_ptr = self.symbol(self.ehdr_start_index.?);
symbol_ptr.value = self.calcImageBase();
symbol_ptr.output_section_index = 1;
}
// __init_array_start, __init_array_end
if (self.sectionByName(".init_array")) |shndx| {
const start_sym = self.symbol(self.init_array_start_index.?);
const end_sym = self.symbol(self.init_array_end_index.?);
const shdr = &self.sections.items(.shdr)[shndx];
start_sym.output_section_index = shndx;
start_sym.value = shdr.sh_addr;
end_sym.output_section_index = shndx;
end_sym.value = shdr.sh_addr + shdr.sh_size;
}
// __fini_array_start, __fini_array_end
if (self.sectionByName(".fini_array")) |shndx| {
const start_sym = self.symbol(self.fini_array_start_index.?);
const end_sym = self.symbol(self.fini_array_end_index.?);
const shdr = &self.sections.items(.shdr)[shndx];
start_sym.output_section_index = shndx;
start_sym.value = shdr.sh_addr;
end_sym.output_section_index = shndx;
end_sym.value = shdr.sh_addr + shdr.sh_size;
}
// __preinit_array_start, __preinit_array_end
if (self.sectionByName(".preinit_array")) |shndx| {
const start_sym = self.symbol(self.preinit_array_start_index.?);
const end_sym = self.symbol(self.preinit_array_end_index.?);
const shdr = &self.sections.items(.shdr)[shndx];
start_sym.output_section_index = shndx;
start_sym.value = shdr.sh_addr;
end_sym.output_section_index = shndx;
end_sym.value = shdr.sh_addr + shdr.sh_size;
}
// _GLOBAL_OFFSET_TABLE_
if (self.got_plt_section_index) |shndx| {
const shdr = &self.sections.items(.shdr)[shndx];
const symbol_ptr = self.symbol(self.got_index.?);
symbol_ptr.value = shdr.sh_addr;
symbol_ptr.output_section_index = shndx;
}
// _PROCEDURE_LINKAGE_TABLE_
if (self.plt_section_index) |shndx| {
const shdr = &self.sections.items(.shdr)[shndx];
const symbol_ptr = self.symbol(self.plt_index.?);
symbol_ptr.value = shdr.sh_addr;
symbol_ptr.output_section_index = shndx;
}
// __dso_handle
if (self.dso_handle_index) |index| {
const shdr = &self.sections.items(.shdr)[1];
const symbol_ptr = self.symbol(index);
symbol_ptr.value = shdr.sh_addr;
symbol_ptr.output_section_index = 0;
}
// __GNU_EH_FRAME_HDR
if (self.eh_frame_hdr_section_index) |shndx| {
const shdr = &self.sections.items(.shdr)[shndx];
const symbol_ptr = self.symbol(self.gnu_eh_frame_hdr_index.?);
symbol_ptr.value = shdr.sh_addr;
symbol_ptr.output_section_index = shndx;
}
// __rela_iplt_start, __rela_iplt_end
if (self.rela_dyn_section_index) |shndx| blk: {
if (self.base.options.link_mode != .Static or self.base.options.pie) break :blk;
const shdr = &self.sections.items(.shdr)[shndx];
const end_addr = shdr.sh_addr + shdr.sh_size;
const start_addr = end_addr - self.calcNumIRelativeRelocs() * @sizeOf(elf.Elf64_Rela);
const start_sym = self.symbol(self.rela_iplt_start_index.?);
const end_sym = self.symbol(self.rela_iplt_end_index.?);
start_sym.value = start_addr;
start_sym.output_section_index = shndx;
end_sym.value = end_addr;
end_sym.output_section_index = shndx;
}
// _end
{
const end_symbol = self.symbol(self.end_index.?);
for (self.sections.items(.shdr), 0..) |shdr, shndx| {
if (shdr.sh_flags & elf.SHF_ALLOC != 0) {
end_symbol.value = shdr.sh_addr + shdr.sh_size;
end_symbol.output_section_index = @intCast(shndx);
}
}
}
// __start_*, __stop_*
{
var index: usize = 0;
while (index < self.start_stop_indexes.items.len) : (index += 2) {
const start = self.symbol(self.start_stop_indexes.items[index]);
const name = start.name(self);
const stop = self.symbol(self.start_stop_indexes.items[index + 1]);
const shndx = self.sectionByName(name["__start_".len..]).?;
const shdr = self.sections.items(.shdr)[shndx];
start.value = shdr.sh_addr;
start.output_section_index = shndx;
stop.value = shdr.sh_addr + shdr.sh_size;
stop.output_section_index = shndx;
}
}
}
fn updateSymtabSize(self: *Elf) !void {
var sizes = SymtabSize{};
@ -2774,17 +2905,17 @@ fn updateSymtabSize(self: *Elf) !void {
sizes.nglobals += zig_module.output_symtab_size.nglobals;
}
if (self.got_section_index) |_| {
self.got.updateSymtabSize(self);
sizes.nlocals += self.got.output_symtab_size.nlocals;
}
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;
}
if (self.got_section_index) |_| {
self.got.updateSymtabSize(self);
sizes.nlocals += self.got.output_symtab_size.nlocals;
}
const shdr = &self.sections.items(.shdr)[self.symtab_section_index.?];
shdr.sh_info = sizes.nlocals + 1;
self.markDirty(self.symtab_section_index.?, null);
@ -2829,17 +2960,17 @@ fn writeSymtab(self: *Elf) !void {
ctx.iglobal += zig_module.output_symtab_size.nglobals;
}
if (self.got_section_index) |_| {
try self.got.writeSymtab(self, ctx);
ctx.ilocal += self.got.output_symtab_size.nlocals;
}
if (self.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;
}
if (self.got_section_index) |_| {
try self.got.writeSymtab(self, ctx);
ctx.ilocal += self.got.output_symtab_size.nlocals;
}
const foreign_endian = self.base.options.target.cpu.arch.endian() != builtin.cpu.arch.endian();
switch (self.ptr_width) {
.p32 => {
@ -3179,6 +3310,34 @@ const CsuObjects = struct {
}
};
pub fn calcImageBase(self: Elf) u64 {
if (self.base.options.pic) return 0; // TODO flag an error if PIC and image_base_override
return self.base.options.image_base_override orelse switch (self.ptr_width) {
.p32 => 0x1000,
.p64 => 0x1000000,
};
}
pub fn defaultEntryAddress(self: Elf) u64 {
if (self.entry_addr) |addr| return addr;
return switch (self.base.options.target.cpu.arch) {
.spu_2 => 0,
else => default_entry_addr,
};
}
pub fn sectionByName(self: *Elf, name: [:0]const u8) ?u16 {
for (self.sections.items(.shdr), 0..) |shdr, i| {
const this_name = self.shstrtab.getAssumeExists(shdr.sh_name);
if (mem.eql(u8, this_name, name)) return @as(u16, @intCast(i));
} else return null;
}
pub fn calcNumIRelativeRelocs(self: *Elf) u64 {
_ = self;
unreachable; // TODO
}
pub fn atom(self: *Elf, atom_index: Atom.Index) ?*Atom {
if (atom_index == 0) return null;
assert(atom_index < self.atoms.items.len);