authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-11-08 10:57:34+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-11-08 10:57:34+01:00
loge87c751558ec1b81bab09f40959a58d250a35a41
treea916252df242cef1e948d7f25964acb2547e5fd6
parent5e78600f0f5e790c0429817d8249020fd65b49f8

elf: reference .rela sections via output section index


3 files changed, 67 insertions(+), 23 deletions(-)

src/link/Elf.zig+60-17
...@@ -18,13 +18,13 @@ shared_objects: std.ArrayListUnmanaged(File.Index) = .{},...@@ -18,13 +18,13 @@ shared_objects: std.ArrayListUnmanaged(File.Index) = .{},
18/// Same order as in the file.18/// Same order as in the file.
19shdrs: std.ArrayListUnmanaged(elf.Elf64_Shdr) = .{},19shdrs: std.ArrayListUnmanaged(elf.Elf64_Shdr) = .{},
20/// Given index to a section, pulls index of containing phdr if any.20/// Given index to a section, pulls index of containing phdr if any.
21phdr_to_shdr_table: std.AutoHashMapUnmanaged(u16, u16) = .{},21phdr_to_shdr_table: std.AutoHashMapUnmanaged(u32, u32) = .{},
22/// File offset into the shdr table.22/// File offset into the shdr table.
23shdr_table_offset: ?u64 = null,23shdr_table_offset: ?u64 = null,
24/// Table of lists of atoms per output section.24/// Table of lists of atoms per output section.
25/// This table is not used to track incrementally generated atoms.25/// This table is not used to track incrementally generated atoms.
26output_sections: std.AutoArrayHashMapUnmanaged(u16, std.ArrayListUnmanaged(Atom.Index)) = .{},26output_sections: std.AutoArrayHashMapUnmanaged(u32, std.ArrayListUnmanaged(Atom.Index)) = .{},
27output_rela_sections: std.AutoArrayHashMapUnmanaged(u16, std.ArrayListUnmanaged(Atom.Index)) = .{},27output_rela_sections: std.AutoArrayHashMapUnmanaged(u32, RelaSection) = .{},
2828
29/// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write.29/// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write.
30/// Same order as in the file.30/// Same order as in the file.
...@@ -355,8 +355,8 @@ pub fn deinit(self: *Elf) void {...@@ -355,8 +355,8 @@ pub fn deinit(self: *Elf) void {
355 list.deinit(gpa);355 list.deinit(gpa);
356 }356 }
357 self.output_sections.deinit(gpa);357 self.output_sections.deinit(gpa);
358 for (self.output_rela_sections.values()) |*list| {358 for (self.output_rela_sections.values()) |*sec| {
359 list.deinit(gpa);359 sec.atom_list.deinit(gpa);
360 }360 }
361 self.output_rela_sections.deinit(gpa);361 self.output_rela_sections.deinit(gpa);
362 self.shstrtab.deinit(gpa);362 self.shstrtab.deinit(gpa);
...@@ -600,7 +600,9 @@ pub fn initMetadata(self: *Elf) !void {...@@ -600,7 +600,9 @@ pub fn initMetadata(self: *Elf) !void {
600 fillSection(self, shdr, self.base.options.program_code_size_hint, self.phdr_zig_load_re_index);600 fillSection(self, shdr, self.base.options.program_code_size_hint, self.phdr_zig_load_re_index);
601 if (self.isRelocatable()) {601 if (self.isRelocatable()) {
602 const rela_shndx = try self.addRelaShdr(".rela.text.zig", self.zig_text_section_index.?);602 const rela_shndx = try self.addRelaShdr(".rela.text.zig", self.zig_text_section_index.?);
603 try self.output_rela_sections.putNoClobber(gpa, rela_shndx, .{});603 try self.output_rela_sections.putNoClobber(gpa, self.zig_text_section_index.?, .{
604 .shndx = rela_shndx,
605 });
604 } else {606 } else {
605 try self.phdr_to_shdr_table.putNoClobber(607 try self.phdr_to_shdr_table.putNoClobber(
606 gpa,608 gpa,
...@@ -648,7 +650,9 @@ pub fn initMetadata(self: *Elf) !void {...@@ -648,7 +650,9 @@ pub fn initMetadata(self: *Elf) !void {
648 ".rela.data.rel.ro.zig",650 ".rela.data.rel.ro.zig",
649 self.zig_data_rel_ro_section_index.?,651 self.zig_data_rel_ro_section_index.?,
650 );652 );
651 try self.output_rela_sections.putNoClobber(gpa, rela_shndx, .{});653 try self.output_rela_sections.putNoClobber(gpa, self.zig_data_rel_ro_section_index.?, .{
654 .shndx = rela_shndx,
655 });
652 } else {656 } else {
653 try self.phdr_to_shdr_table.putNoClobber(657 try self.phdr_to_shdr_table.putNoClobber(
654 gpa,658 gpa,
...@@ -675,7 +679,9 @@ pub fn initMetadata(self: *Elf) !void {...@@ -675,7 +679,9 @@ pub fn initMetadata(self: *Elf) !void {
675 ".rela.data.zig",679 ".rela.data.zig",
676 self.zig_data_section_index.?,680 self.zig_data_section_index.?,
677 );681 );
678 try self.output_rela_sections.putNoClobber(gpa, rela_shndx, .{});682 try self.output_rela_sections.putNoClobber(gpa, self.zig_data_section_index.?, .{
683 .shndx = rela_shndx,
684 });
679 } else {685 } else {
680 try self.phdr_to_shdr_table.putNoClobber(686 try self.phdr_to_shdr_table.putNoClobber(
681 gpa,687 gpa,
...@@ -793,6 +799,14 @@ pub fn initMetadata(self: *Elf) !void {...@@ -793,6 +799,14 @@ pub fn initMetadata(self: *Elf) !void {
793 try self.output_sections.putNoClobber(gpa, self.debug_line_section_index.?, .{});799 try self.output_sections.putNoClobber(gpa, self.debug_line_section_index.?, .{});
794 }800 }
795 }801 }
802
803 // We need to find current max assumed file offset, and actually write to file to make it a reality.
804 var end_pos: u64 = 0;
805 for (self.shdrs.items) |shdr| {
806 if (shdr.sh_offset == std.math.maxInt(u64)) continue;
807 end_pos = @max(end_pos, shdr.sh_offset + shdr.sh_size);
808 }
809 try self.base.file.?.pwriteAll(&[1]u8{0}, end_pos);
796}810}
797811
798pub fn growAllocSection(self: *Elf, shdr_index: u16, needed_size: u64) !void {812pub fn growAllocSection(self: *Elf, shdr_index: u16, needed_size: u64) !void {
...@@ -1521,8 +1535,12 @@ pub fn flushStaticLib(self: *Elf) link.File.FlushError!void {...@@ -1521,8 +1535,12 @@ pub fn flushStaticLib(self: *Elf) link.File.FlushError!void {
15211535
1522 try self.allocateNonAllocSections();1536 try self.allocateNonAllocSections();
15231537
1524 try self.writeShdrTable();1538 if (build_options.enable_logging) {
1539 state_log.debug("{}", .{self.dumpState()});
1540 }
1541
1525 try self.writeSyntheticSectionsObject();1542 try self.writeSyntheticSectionsObject();
1543 try self.writeShdrTable();
1526 try self.writeElfHeader();1544 try self.writeElfHeader();
1527 }1545 }
15281546
...@@ -1618,6 +1636,9 @@ pub fn flushObject(self: *Elf) link.File.FlushError!void {...@@ -1618,6 +1636,9 @@ pub fn flushObject(self: *Elf) link.File.FlushError!void {
16181636
1619 try self.initSectionsObject();1637 try self.initSectionsObject();
1620 try self.sortShdrs();1638 try self.sortShdrs();
1639 if (self.zigObjectPtr()) |zig_object| {
1640 try zig_object.addAtomsToRelaSections(self);
1641 }
1621 for (self.objects.items) |index| {1642 for (self.objects.items) |index| {
1622 const object = self.file(index).?.object;1643 const object = self.file(index).?.object;
1623 try object.addAtomsToOutputSections(self);1644 try object.addAtomsToOutputSections(self);
...@@ -3924,6 +3945,21 @@ fn sortShdrs(self: *Elf) !void {...@@ -3924,6 +3945,21 @@ fn sortShdrs(self: *Elf) !void {
3924 }3945 }
3925 }3946 }
39263947
3948 {
3949 var output_rela_sections = try self.output_rela_sections.clone(gpa);
3950 defer output_rela_sections.deinit(gpa);
3951
3952 self.output_rela_sections.clearRetainingCapacity();
3953
3954 var it = output_rela_sections.iterator();
3955 while (it.next()) |entry| {
3956 const shndx = entry.key_ptr.*;
3957 var meta = entry.value_ptr.*;
3958 meta.shndx = backlinks[meta.shndx];
3959 self.output_rela_sections.putAssumeCapacityNoClobber(backlinks[shndx], meta);
3960 }
3961 }
3962
3927 {3963 {
3928 var last_atom_and_free_list_table = try self.last_atom_and_free_list_table.clone(gpa);3964 var last_atom_and_free_list_table = try self.last_atom_and_free_list_table.clone(gpa);
3929 defer last_atom_and_free_list_table.deinit(gpa);3965 defer last_atom_and_free_list_table.deinit(gpa);
...@@ -4082,14 +4118,16 @@ fn updateSectionSizesObject(self: *Elf) !void {...@@ -4082,14 +4118,16 @@ fn updateSectionSizesObject(self: *Elf) !void {
4082 }4118 }
4083 }4119 }
40844120
4085 for (self.output_rela_sections.keys(), self.output_rela_sections.values()) |shndx, atom_list| {4121 for (self.output_rela_sections.values()) |sec| {
4086 const shdr = &self.shdrs.items[shndx];4122 const shdr = &self.shdrs.items[sec.shndx];
4087 for (atom_list.items) |atom_index| {4123 for (sec.atom_list.items) |atom_index| {
4088 const atom_ptr = self.atom(atom_index) orelse continue;4124 const atom_ptr = self.atom(atom_index) orelse continue;
4089 if (!atom_ptr.flags.alive) continue;4125 if (!atom_ptr.flags.alive) continue;
4090 const relocs = atom_ptr.relocs(self);4126 const relocs = atom_ptr.relocs(self);
4091 shdr.sh_size += shdr.sh_entsize * relocs.len;4127 shdr.sh_size += shdr.sh_entsize * relocs.len;
4092 }4128 }
4129
4130 if (shdr.sh_size == 0) shdr.sh_offset = 0;
4093 }4131 }
40944132
4095 if (self.eh_frame_section_index) |index| {4133 if (self.eh_frame_section_index) |index| {
...@@ -4849,16 +4887,16 @@ fn writeSyntheticSections(self: *Elf) !void {...@@ -4849,16 +4887,16 @@ fn writeSyntheticSections(self: *Elf) !void {
4849fn writeSyntheticSectionsObject(self: *Elf) !void {4887fn writeSyntheticSectionsObject(self: *Elf) !void {
4850 const gpa = self.base.allocator;4888 const gpa = self.base.allocator;
48514889
4852 for (self.output_rela_sections.keys(), self.output_rela_sections.values()) |shndx, atom_list| {4890 for (self.output_rela_sections.values()) |sec| {
4853 if (atom_list.items.len == 0) continue;4891 if (sec.atom_list.items.len == 0) continue;
48544892
4855 const shdr = self.shdrs.items[shndx];4893 const shdr = self.shdrs.items[sec.shndx];
48564894
4857 const num_relocs = @divExact(shdr.sh_size, shdr.sh_entsize);4895 const num_relocs = @divExact(shdr.sh_size, shdr.sh_entsize);
4858 var relocs = try std.ArrayList(elf.Elf64_Rela).initCapacity(gpa, num_relocs);4896 var relocs = try std.ArrayList(elf.Elf64_Rela).initCapacity(gpa, num_relocs);
4859 defer relocs.deinit();4897 defer relocs.deinit();
48604898
4861 for (atom_list.items) |atom_index| {4899 for (sec.atom_list.items) |atom_index| {
4862 const atom_ptr = self.atom(atom_index) orelse continue;4900 const atom_ptr = self.atom(atom_index) orelse continue;
4863 if (!atom_ptr.flags.alive) continue;4901 if (!atom_ptr.flags.alive) continue;
4864 try atom_ptr.writeRelocs(self, &relocs);4902 try atom_ptr.writeRelocs(self, &relocs);
...@@ -6127,8 +6165,13 @@ const LastAtomAndFreeList = struct {...@@ -6127,8 +6165,13 @@ const LastAtomAndFreeList = struct {
6127 /// by 1 byte. It will then have -1 overcapacity.6165 /// by 1 byte. It will then have -1 overcapacity.
6128 free_list: std.ArrayListUnmanaged(Atom.Index) = .{},6166 free_list: std.ArrayListUnmanaged(Atom.Index) = .{},
6129};6167};
6168const LastAtomAndFreeListTable = std.AutoArrayHashMapUnmanaged(u32, LastAtomAndFreeList);
61306169
6131const LastAtomAndFreeListTable = std.AutoArrayHashMapUnmanaged(u16, LastAtomAndFreeList);6170const RelaSection = struct {
6171 shndx: u32,
6172 atom_list: std.ArrayListUnmanaged(Atom.Index) = .{},
6173};
6174const RelaSectionTable = std.AutoArrayHashMapUnmanaged(u32, RelaSection);
61326175
6133pub const R_X86_64_ZIG_GOT32 = elf.R_X86_64_NUM + 1;6176pub const R_X86_64_ZIG_GOT32 = elf.R_X86_64_NUM + 1;
6134pub const R_X86_64_ZIG_GOTPCREL = elf.R_X86_64_NUM + 2;6177pub const R_X86_64_ZIG_GOTPCREL = elf.R_X86_64_NUM + 2;
src/link/Elf/Object.zig+5-3
...@@ -681,9 +681,9 @@ pub fn addAtomsToRelaSections(self: Object, elf_file: *Elf) !void {...@@ -681,9 +681,9 @@ pub fn addAtomsToRelaSections(self: Object, elf_file: *Elf) !void {
681 const out_shndx = self.initOutputSection(elf_file, shdr) catch unreachable;681 const out_shndx = self.initOutputSection(elf_file, shdr) catch unreachable;
682682
683 const gpa = elf_file.base.allocator;683 const gpa = elf_file.base.allocator;
684 const gop = try elf_file.output_rela_sections.getOrPut(gpa, out_shndx);684 const gop = try elf_file.output_rela_sections.getOrPut(gpa, atom.outputShndx().?);
685 if (!gop.found_existing) gop.value_ptr.* = .{};685 if (!gop.found_existing) gop.value_ptr.* = .{ .shndx = out_shndx };
686 try gop.value_ptr.append(gpa, atom_index);686 try gop.value_ptr.atom_list.append(gpa, atom_index);
687 }687 }
688}688}
689689
...@@ -718,11 +718,13 @@ pub fn writeAr(self: Object, writer: anytype) !void {...@@ -718,11 +718,13 @@ pub fn writeAr(self: Object, writer: anytype) !void {
718}718}
719719
720pub fn locals(self: Object) []const Symbol.Index {720pub fn locals(self: Object) []const Symbol.Index {
721 if (self.symbols.items.len == 0) return &[0]Symbol.Index{};
721 const end = self.first_global orelse self.symbols.items.len;722 const end = self.first_global orelse self.symbols.items.len;
722 return self.symbols.items[0..end];723 return self.symbols.items[0..end];
723}724}
724725
725pub fn globals(self: Object) []const Symbol.Index {726pub fn globals(self: Object) []const Symbol.Index {
727 if (self.symbols.items.len == 0) return &[0]Symbol.Index{};
726 const start = self.first_global orelse self.symbols.items.len;728 const start = self.first_global orelse self.symbols.items.len;
727 return self.symbols.items[start..];729 return self.symbols.items[start..];
728}730}
src/link/Elf/ZigObject.zig+2-3
...@@ -541,9 +541,8 @@ pub fn addAtomsToRelaSections(self: ZigObject, elf_file: *Elf) !void {...@@ -541,9 +541,8 @@ pub fn addAtomsToRelaSections(self: ZigObject, elf_file: *Elf) !void {
541 const out_shndx = atom.outputShndx().?;541 const out_shndx = atom.outputShndx().?;
542542
543 const gpa = elf_file.base.allocator;543 const gpa = elf_file.base.allocator;
544 const gop = try elf_file.output_rela_sections.getOrPut(gpa, out_shndx);544 const sec = elf_file.output_rela_sections.getPtr(out_shndx).?;
545 if (!gop.found_existing) gop.value_ptr.* = .{};545 try sec.atom_list.append(gpa, atom_index);
546 try gop.value_ptr.append(gpa, atom_index);
547 }546 }
548}547}
549548