diff options
| author | Jakub Konka <kubkon@jakubkonka.com> | 2023-11-01 20:35:45 +0100 |
|---|---|---|
| committer | Jakub Konka <kubkon@jakubkonka.com> | 2023-11-04 09:09:35 +0100 |
| commit | 21853bc310fb6029f949bcf9aca59f69c768a664 (patch) | |
| tree | e77aba201e50d6f86925b615450c7fda6e596b34 /src | |
| parent | 0ee2ab413fd0370a8ced8d433c71d1d951dab41c (diff) | |
| download | zig-21853bc310fb6029f949bcf9aca59f69c768a664.tar.gz zig-21853bc310fb6029f949bcf9aca59f69c768a664.zip | |
elf: emit .rela shdrs for output sections
Diffstat (limited to 'src')
| -rw-r--r-- | src/link/Elf.zig | 155 |
1 files changed, 107 insertions, 48 deletions
diff --git a/src/link/Elf.zig b/src/link/Elf.zig index c4bd3d4c10..d62d786143 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -99,15 +99,20 @@ plt_got: PltGotSection = .{}, copy_rel: CopyRelSection = .{}, /// .rela.plt section rela_plt: std.ArrayListUnmanaged(elf.Elf64_Rela) = .{}, -/// .zig.got section +/// .got.zig section zig_got: ZigGotSection = .{}, -/// Tracked section headers with incremental updates to Zig object +/// Tracked section headers with incremental updates to Zig object. +/// .rela.* sections are only used when emitting a relocatable object file. zig_text_section_index: ?u16 = null, +zig_text_rela_section_index: ?u16 = null, zig_data_rel_ro_section_index: ?u16 = null, +zig_data_rel_ro_rela_section_index: ?u16 = null, zig_data_section_index: ?u16 = null, +zig_data_rela_section_index: ?u16 = null, zig_bss_section_index: ?u16 = null, zig_got_section_index: ?u16 = null, +zig_got_rela_section_index: ?u16 = null, debug_info_section_index: ?u16 = null, debug_abbrev_section_index: ?u16 = null, @@ -491,6 +496,21 @@ pub fn initMetadata(self: *Elf) !void { const ptr_bit_width = self.base.options.target.ptrBitWidth(); const is_linux = self.base.options.target.os.tag == .linux; + const fillSection = struct { + fn fillSection(elf_file: *Elf, shdr: *elf.Elf64_Shdr, size: u64, phndx: ?u16) void { + if (elf_file.isObject()) { + const off = elf_file.findFreeSpace(size, shdr.sh_addralign); + shdr.sh_offset = off; + shdr.sh_size = size; + } else { + const phdr = elf_file.phdrs.items[phndx.?]; + shdr.sh_addr = phdr.p_vaddr; + shdr.sh_offset = phdr.p_offset; + shdr.sh_size = phdr.p_memsz; + } + } + }.fillSection; + comptime assert(number_of_zig_segments == 5); if (!self.isObject()) { @@ -569,24 +589,25 @@ pub fn initMetadata(self: *Elf) !void { if (self.zig_text_section_index == null) { self.zig_text_section_index = try self.addSection(.{ - .name = ".zig.text", + .name = ".text.zig", .type = elf.SHT_PROGBITS, .flags = elf.SHF_ALLOC | elf.SHF_EXECINSTR, .addralign = 1, .offset = std.math.maxInt(u64), }); const shdr = &self.shdrs.items[self.zig_text_section_index.?]; - if (self.phdr_zig_load_re_index) |phndx| { - const phdr = self.phdrs.items[phndx]; - shdr.sh_addr = phdr.p_vaddr; - shdr.sh_offset = phdr.p_offset; - shdr.sh_size = phdr.p_memsz; - try self.phdr_to_shdr_table.putNoClobber(gpa, self.zig_text_section_index.?, phndx); + fillSection(self, shdr, self.base.options.program_code_size_hint, self.phdr_zig_load_re_index); + if (self.isObject()) { + self.zig_text_rela_section_index = try self.addRelaShdr( + ".rela.text.zig", + self.zig_text_section_index.?, + ); } else { - const size = self.base.options.program_code_size_hint; - const off = self.findFreeSpace(size, 1); - shdr.sh_offset = off; - shdr.sh_size = size; + try self.phdr_to_shdr_table.putNoClobber( + gpa, + self.zig_text_section_index.?, + self.phdr_zig_load_re_index.?, + ); } try self.last_atom_and_free_list_table.putNoClobber(gpa, self.zig_text_section_index.?, .{}); } @@ -594,78 +615,80 @@ pub fn initMetadata(self: *Elf) !void { if (self.zig_got_section_index == null) { // TODO we don't actually need this section in a relocatable object file self.zig_got_section_index = try self.addSection(.{ - .name = ".zig.got", + .name = ".got.zig", .type = elf.SHT_PROGBITS, .addralign = ptr_size, .flags = elf.SHF_ALLOC | elf.SHF_WRITE, .offset = std.math.maxInt(u64), }); const shdr = &self.shdrs.items[self.zig_got_section_index.?]; - if (self.phdr_zig_got_index) |phndx| { - const phdr = self.phdrs.items[phndx]; - shdr.sh_addr = phdr.p_vaddr; - shdr.sh_offset = phdr.p_offset; - shdr.sh_size = phdr.p_memsz; - try self.phdr_to_shdr_table.putNoClobber(gpa, self.zig_got_section_index.?, phndx); - } else { - const size = @as(u64, ptr_size) * self.base.options.symbol_count_hint; - const off = self.findFreeSpace(size, ptr_size); - shdr.sh_offset = off; - shdr.sh_size = size; + fillSection( + self, + shdr, + @as(u64, ptr_size) * self.base.options.symbol_count_hint, + self.phdr_zig_got_index, + ); + if (self.isObject()) { + self.zig_got_rela_section_index = try self.addRelaShdr( + ".rela.got.zig", + self.zig_got_section_index.?, + ); } } if (self.zig_data_rel_ro_section_index == null) { self.zig_data_rel_ro_section_index = try self.addSection(.{ - .name = ".zig.data.rel.ro", + .name = ".data.rel.ro.zig", .type = elf.SHT_PROGBITS, .addralign = 1, .flags = elf.SHF_ALLOC | elf.SHF_WRITE, // TODO rename this section to .data.rel.ro .offset = std.math.maxInt(u64), }); const shdr = &self.shdrs.items[self.zig_data_rel_ro_section_index.?]; - if (self.phdr_zig_load_ro_index) |phndx| { - const phdr = self.phdrs.items[phndx]; - shdr.sh_addr = phdr.p_vaddr; - shdr.sh_offset = phdr.p_offset; - shdr.sh_size = phdr.p_memsz; - try self.phdr_to_shdr_table.putNoClobber(gpa, self.zig_data_rel_ro_section_index.?, phndx); + fillSection(self, shdr, 1024, self.phdr_zig_load_ro_index); + if (self.isObject()) { + self.zig_data_rel_ro_rela_section_index = try self.addRelaShdr( + ".rela.data.rel.ro.zig", + self.zig_data_rel_ro_section_index.?, + ); } else { - const size: u64 = 1024; - const off = self.findFreeSpace(size, 1); - shdr.sh_offset = off; - shdr.sh_size = size; + try self.phdr_to_shdr_table.putNoClobber( + gpa, + self.zig_data_rel_ro_section_index.?, + self.phdr_zig_load_ro_index.?, + ); } try self.last_atom_and_free_list_table.putNoClobber(gpa, self.zig_data_rel_ro_section_index.?, .{}); } if (self.zig_data_section_index == null) { self.zig_data_section_index = try self.addSection(.{ - .name = ".zig.data", + .name = ".data.zig", .type = elf.SHT_PROGBITS, .addralign = ptr_size, .flags = elf.SHF_ALLOC | elf.SHF_WRITE, .offset = std.math.maxInt(u64), }); const shdr = &self.shdrs.items[self.zig_data_section_index.?]; - if (self.phdr_zig_load_rw_index) |phndx| { - const phdr = self.phdrs.items[phndx]; - shdr.sh_addr = phdr.p_vaddr; - shdr.sh_offset = phdr.p_offset; - shdr.sh_size = phdr.p_memsz; - try self.phdr_to_shdr_table.putNoClobber(gpa, self.zig_data_section_index.?, phndx); + fillSection(self, shdr, 1024, self.phdr_zig_load_rw_index); + if (self.isObject()) { + self.zig_data_rela_section_index = try self.addRelaShdr( + ".rela.data.zig", + self.zig_data_section_index.?, + ); } else { - const size: u64 = 1024; - const off = self.findFreeSpace(size, ptr_size); - shdr.sh_offset = off; - shdr.sh_size = size; + try self.phdr_to_shdr_table.putNoClobber( + gpa, + self.zig_data_section_index.?, + self.phdr_zig_load_rw_index.?, + ); } try self.last_atom_and_free_list_table.putNoClobber(gpa, self.zig_data_section_index.?, .{}); } if (self.zig_bss_section_index == null) { self.zig_bss_section_index = try self.addSection(.{ - .name = ".zig.bss", + .name = ".bss.zig", .type = elf.SHT_NOBITS, .addralign = ptr_size, .flags = elf.SHF_ALLOC | elf.SHF_WRITE, @@ -3676,9 +3699,13 @@ fn sortShdrs(self: *Elf) !void { &self.versym_section_index, &self.verneed_section_index, &self.zig_text_section_index, + &self.zig_text_rela_section_index, &self.zig_got_section_index, + &self.zig_got_rela_section_index, &self.zig_data_rel_ro_section_index, + &self.zig_data_rel_ro_rela_section_index, &self.zig_data_section_index, + &self.zig_data_rela_section_index, &self.zig_bss_section_index, &self.debug_str_section_index, &self.debug_info_section_index, @@ -3737,6 +3764,18 @@ fn sortShdrs(self: *Elf) !void { shdr.sh_info = self.plt_section_index.?; } + for (&[_]?u16{ + self.zig_text_rela_section_index, + self.zig_got_rela_section_index, + self.zig_data_rel_ro_rela_section_index, + self.zig_data_rela_section_index, + }) |maybe_index| { + const index = maybe_index orelse continue; + const shdr = &self.shdrs.items[index]; + shdr.sh_link = self.symtab_section_index.?; + shdr.sh_info = backlinks[shdr.sh_info]; + } + { var phdr_to_shdr_table = try self.phdr_to_shdr_table.clone(gpa); defer phdr_to_shdr_table.deinit(gpa); @@ -4955,6 +4994,26 @@ fn addPhdr(self: *Elf, opts: struct { return index; } +fn addRelaShdr(self: *Elf, name: [:0]const u8, shndx: u16) !u16 { + const entsize: u64 = switch (self.ptr_width) { + .p32 => @sizeOf(elf.Elf32_Rela), + .p64 => @sizeOf(elf.Elf64_Rela), + }; + const addralign: u64 = switch (self.ptr_width) { + .p32 => @alignOf(elf.Elf32_Rela), + .p64 => @alignOf(elf.Elf64_Rela), + }; + return self.addSection(.{ + .name = name, + .type = elf.SHT_RELA, + .flags = elf.SHF_INFO_LINK, + .entsize = entsize, + .info = shndx, + .addralign = addralign, + .offset = std.math.maxInt(u64), + }); +} + pub const AddSectionOpts = struct { name: [:0]const u8, type: u32 = elf.SHT_NULL, |
