authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-09-04 21:56:45+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-09-04 21:56:45+02:00
log7e31804870cac14063b2468f544fc77a4cbb616f
tree87e84657c242c95177218185fe34bb5c6f69f035
parentf87dd43c1285d38d7a0f3092f6487bf1e1f4faa6
parente1d5bb365b3b8d645fbdfc4ffb6a14ef3bb0e766
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #21305 from ziglang/elf-incr

elf: redo how we allocate atoms extracted from input relocatable object files

10 files changed, 1145 insertions(+), 988 deletions(-)

CMakeLists.txt+1
......@@ -600,6 +600,7 @@ set(ZIG_STAGE2_SOURCES
600600 src/link/Elf.zig
601601 src/link/Elf/Archive.zig
602602 src/link/Elf/Atom.zig
603 src/link/Elf/AtomList.zig
603604 src/link/Elf/LdScript.zig
604605 src/link/Elf/LinkerDefined.zig
605606 src/link/Elf/Object.zig
src/link/Dwarf.zig+81-63
......@@ -261,7 +261,6 @@ pub const Section = struct {
261261 index: u32,
262262 first: Unit.Index.Optional,
263263 last: Unit.Index.Optional,
264 off: u64,
265264 len: u64,
266265 units: std.ArrayListUnmanaged(Unit),
267266
......@@ -284,9 +283,8 @@ pub const Section = struct {
284283 .index = std.math.maxInt(u32),
285284 .first = .none,
286285 .last = .none,
287 .off = 0,
288 .len = 0,
289286 .units = .{},
287 .len = 0,
290288 };
291289
292290 fn deinit(sec: *Section, gpa: std.mem.Allocator) void {
......@@ -295,6 +293,20 @@ pub const Section = struct {
295293 sec.* = undefined;
296294 }
297295
296 fn off(sec: Section, dwarf: *Dwarf) u64 {
297 if (dwarf.bin_file.cast(.elf)) |elf_file| {
298 const zo = elf_file.zigObjectPtr().?;
299 const atom = zo.symbol(sec.index).atom(elf_file).?;
300 return atom.offset(elf_file);
301 } else if (dwarf.bin_file.cast(.macho)) |macho_file| {
302 const header = if (macho_file.d_sym) |d_sym|
303 d_sym.sections.items[sec.index]
304 else
305 macho_file.sections.items(.header)[sec.index];
306 return header.offset;
307 } else unreachable;
308 }
309
298310 fn addUnit(sec: *Section, header_len: u32, trailer_len: u32, dwarf: *Dwarf) UpdateError!Unit.Index {
299311 const unit: Unit.Index = @enumFromInt(sec.units.items.len);
300312 const unit_ptr = try sec.units.addOne(dwarf.gpa);
......@@ -306,9 +318,9 @@ pub const Section = struct {
306318 .next = .none,
307319 .first = .none,
308320 .last = .none,
309 .off = 0,
310321 .header_len = aligned_header_len,
311322 .trailer_len = aligned_trailer_len,
323 .off = 0,
312324 .len = aligned_header_len + aligned_trailer_len,
313325 .entries = .{},
314326 .cross_unit_relocs = .{},
......@@ -375,12 +387,16 @@ pub const Section = struct {
375387 fn resize(sec: *Section, dwarf: *Dwarf, len: u64) UpdateError!void {
376388 if (len <= sec.len) return;
377389 if (dwarf.bin_file.cast(.elf)) |elf_file| {
390 const zo = elf_file.zigObjectPtr().?;
391 const atom = zo.symbol(sec.index).atom(elf_file).?;
392 const shndx = atom.output_section_index;
378393 if (sec == &dwarf.debug_frame.section)
379 try elf_file.growAllocSection(sec.index, len)
394 try elf_file.growAllocSection(shndx, len, sec.alignment.toByteUnits().?)
380395 else
381 try elf_file.growNonAllocSection(sec.index, len, @intCast(sec.alignment.toByteUnits().?), true);
382 const shdr = &elf_file.sections.items(.shdr)[sec.index];
383 sec.off = shdr.sh_offset;
396 try elf_file.growNonAllocSection(shndx, len, sec.alignment.toByteUnits().?, true);
397 const shdr = elf_file.sections.items(.shdr)[shndx];
398 atom.size = shdr.sh_size;
399 atom.alignment = InternPool.Alignment.fromNonzeroByteUnits(shdr.sh_addralign);
384400 sec.len = shdr.sh_size;
385401 } else if (dwarf.bin_file.cast(.macho)) |macho_file| {
386402 const header = if (macho_file.d_sym) |*d_sym| header: {
......@@ -390,7 +406,6 @@ pub const Section = struct {
390406 try macho_file.growSection(@intCast(sec.index), len);
391407 break :header &macho_file.sections.items(.header)[sec.index];
392408 };
393 sec.off = header.offset;
394409 sec.len = header.size;
395410 }
396411 }
......@@ -399,18 +414,21 @@ pub const Section = struct {
399414 const len = sec.getUnit(sec.first.unwrap() orelse return).off;
400415 if (len == 0) return;
401416 for (sec.units.items) |*unit| unit.off -= len;
402 sec.off += len;
403417 sec.len -= len;
404418 if (dwarf.bin_file.cast(.elf)) |elf_file| {
405 const shdr = &elf_file.sections.items(.shdr)[sec.index];
406 shdr.sh_offset = sec.off;
419 const zo = elf_file.zigObjectPtr().?;
420 const atom = zo.symbol(sec.index).atom(elf_file).?;
421 const shndx = atom.output_section_index;
422 const shdr = &elf_file.sections.items(.shdr)[shndx];
423 atom.size = sec.len;
424 shdr.sh_offset += len;
407425 shdr.sh_size = sec.len;
408426 } else if (dwarf.bin_file.cast(.macho)) |macho_file| {
409427 const header = if (macho_file.d_sym) |*d_sym|
410428 &d_sym.sections.items[sec.index]
411429 else
412430 &macho_file.sections.items(.header)[sec.index];
413 header.offset = @intCast(sec.off);
431 header.offset += @intCast(len);
414432 header.size = sec.len;
415433 }
416434 }
......@@ -539,9 +557,9 @@ const Unit = struct {
539557 fn move(unit: *Unit, sec: *Section, dwarf: *Dwarf, new_off: u32) UpdateError!void {
540558 if (unit.off == new_off) return;
541559 if (try dwarf.getFile().?.copyRangeAll(
542 sec.off + unit.off,
560 sec.off(dwarf) + unit.off,
543561 dwarf.getFile().?,
544 sec.off + new_off,
562 sec.off(dwarf) + new_off,
545563 unit.len,
546564 ) != unit.len) return error.InputOutput;
547565 unit.off = new_off;
......@@ -573,7 +591,7 @@ const Unit = struct {
573591
574592 fn replaceHeader(unit: *Unit, sec: *Section, dwarf: *Dwarf, contents: []const u8) UpdateError!void {
575593 assert(contents.len == unit.header_len);
576 try dwarf.getFile().?.pwriteAll(contents, sec.off + unit.off);
594 try dwarf.getFile().?.pwriteAll(contents, sec.off(dwarf) + unit.off);
577595 }
578596
579597 fn writeTrailer(unit: *Unit, sec: *Section, dwarf: *Dwarf) UpdateError!void {
......@@ -605,7 +623,7 @@ const Unit = struct {
605623 assert(fbs.pos == extended_op_bytes + op_len_bytes);
606624 writer.writeByte(DW.LNE.padding) catch unreachable;
607625 assert(fbs.pos >= unit.trailer_len and fbs.pos <= len);
608 return dwarf.getFile().?.pwriteAll(fbs.getWritten(), sec.off + start);
626 return dwarf.getFile().?.pwriteAll(fbs.getWritten(), sec.off(dwarf) + start);
609627 }
610628 var trailer = try std.ArrayList(u8).initCapacity(dwarf.gpa, len);
611629 defer trailer.deinit();
......@@ -664,11 +682,11 @@ const Unit = struct {
664682 assert(trailer.items.len == unit.trailer_len);
665683 trailer.appendNTimesAssumeCapacity(fill_byte, len - unit.trailer_len);
666684 assert(trailer.items.len == len);
667 try dwarf.getFile().?.pwriteAll(trailer.items, sec.off + start);
685 try dwarf.getFile().?.pwriteAll(trailer.items, sec.off(dwarf) + start);
668686 }
669687
670688 fn resolveRelocs(unit: *Unit, sec: *Section, dwarf: *Dwarf) RelocError!void {
671 const unit_off = sec.off + unit.off;
689 const unit_off = sec.off(dwarf) + unit.off;
672690 for (unit.cross_unit_relocs.items) |reloc| {
673691 const target_unit = sec.getUnit(reloc.target_unit);
674692 try dwarf.resolveReloc(
......@@ -755,12 +773,12 @@ const Entry = struct {
755773 dwarf.writeInt(unit_len[0..dwarf.sectionOffsetBytes()], len - dwarf.unitLengthBytes());
756774 try dwarf.getFile().?.pwriteAll(
757775 unit_len[0..dwarf.sectionOffsetBytes()],
758 sec.off + unit.off + unit.header_len + entry.off,
776 sec.off(dwarf) + unit.off + unit.header_len + entry.off,
759777 );
760778 const buf = try dwarf.gpa.alloc(u8, len - entry.len);
761779 defer dwarf.gpa.free(buf);
762780 @memset(buf, DW.CFA.nop);
763 try dwarf.getFile().?.pwriteAll(buf, sec.off + unit.off + unit.header_len + start);
781 try dwarf.getFile().?.pwriteAll(buf, sec.off(dwarf) + unit.off + unit.header_len + start);
764782 return;
765783 }
766784 const len = unit.getEntry(entry.next.unwrap() orelse return).off - start;
......@@ -816,7 +834,7 @@ const Entry = struct {
816834 },
817835 } else assert(!sec.pad_to_ideal and len == 0);
818836 assert(fbs.pos <= len);
819 try dwarf.getFile().?.pwriteAll(fbs.getWritten(), sec.off + unit.off + unit.header_len + start);
837 try dwarf.getFile().?.pwriteAll(fbs.getWritten(), sec.off(dwarf) + unit.off + unit.header_len + start);
820838 }
821839
822840 fn resize(entry_ptr: *Entry, unit: *Unit, sec: *Section, dwarf: *Dwarf, len: u32) UpdateError!void {
......@@ -851,15 +869,15 @@ const Entry = struct {
851869
852870 fn replace(entry_ptr: *Entry, unit: *Unit, sec: *Section, dwarf: *Dwarf, contents: []const u8) UpdateError!void {
853871 assert(contents.len == entry_ptr.len);
854 try dwarf.getFile().?.pwriteAll(contents, sec.off + unit.off + unit.header_len + entry_ptr.off);
872 try dwarf.getFile().?.pwriteAll(contents, sec.off(dwarf) + unit.off + unit.header_len + entry_ptr.off);
855873 if (false) {
856874 const buf = try dwarf.gpa.alloc(u8, sec.len);
857875 defer dwarf.gpa.free(buf);
858 _ = try dwarf.getFile().?.preadAll(buf, sec.off);
876 _ = try dwarf.getFile().?.preadAll(buf, sec.off(dwarf));
859877 log.info("Section{{ .first = {}, .last = {}, .off = 0x{x}, .len = 0x{x} }}", .{
860878 @intFromEnum(sec.first),
861879 @intFromEnum(sec.last),
862 sec.off,
880 sec.off(dwarf),
863881 sec.len,
864882 });
865883 for (sec.units.items) |*unit_ptr| {
......@@ -891,9 +909,11 @@ const Entry = struct {
891909 if (std.debug.runtime_safety) {
892910 log.err("missing {} from {s}", .{
893911 @as(Entry.Index, @enumFromInt(entry - unit.entries.items.ptr)),
894 std.mem.sliceTo(if (dwarf.bin_file.cast(.elf)) |elf_file|
895 elf_file.shstrtab.items[elf_file.sections.items(.shdr)[sec.index].sh_name..]
896 else if (dwarf.bin_file.cast(.macho)) |macho_file|
912 std.mem.sliceTo(if (dwarf.bin_file.cast(.elf)) |elf_file| sh_name: {
913 const zo = elf_file.zigObjectPtr().?;
914 const shndx = zo.symbol(sec.index).atom(elf_file).?.output_section_index;
915 break :sh_name elf_file.shstrtab.items[elf_file.sections.items(.shdr)[shndx].sh_name..];
916 } else if (dwarf.bin_file.cast(.macho)) |macho_file|
897917 if (macho_file.d_sym) |*d_sym|
898918 &d_sym.sections.items[sec.index].segname
899919 else
......@@ -924,7 +944,7 @@ const Entry = struct {
924944 }
925945
926946 fn resolveRelocs(entry: *Entry, unit: *Unit, sec: *Section, dwarf: *Dwarf) RelocError!void {
927 const entry_off = sec.off + unit.off + unit.header_len + entry.off;
947 const entry_off = sec.off(dwarf) + unit.off + unit.header_len + entry.off;
928948 for (entry.cross_entry_relocs.items) |reloc| {
929949 try dwarf.resolveReloc(
930950 entry_off + reloc.source_off,
......@@ -961,7 +981,8 @@ const Entry = struct {
961981 .none, .debug_frame => {},
962982 .eh_frame => return if (dwarf.bin_file.cast(.elf)) |elf_file| {
963983 const zo = elf_file.zigObjectPtr().?;
964 const entry_addr: i64 = @intCast(entry_off - sec.off + elf_file.shdrs.items[sec.index].sh_addr);
984 const shndx = zo.symbol(sec.index).atom(elf_file).?.output_section_index;
985 const entry_addr: i64 = @intCast(entry_off - sec.off(dwarf) + elf_file.shdrs.items[shndx].sh_addr);
965986 for (entry.external_relocs.items) |reloc| {
966987 const symbol = zo.symbol(reloc.target_sym);
967988 try dwarf.resolveReloc(
......@@ -1877,34 +1898,7 @@ pub fn init(lf: *link.File, format: DW.Format) Dwarf {
18771898}
18781899
18791900pub fn reloadSectionMetadata(dwarf: *Dwarf) void {
1880 if (dwarf.bin_file.cast(.elf)) |elf_file| {
1881 for ([_]*Section{
1882 &dwarf.debug_abbrev.section,
1883 &dwarf.debug_aranges.section,
1884 &dwarf.debug_frame.section,
1885 &dwarf.debug_info.section,
1886 &dwarf.debug_line.section,
1887 &dwarf.debug_line_str.section,
1888 &dwarf.debug_loclists.section,
1889 &dwarf.debug_rnglists.section,
1890 &dwarf.debug_str.section,
1891 }, [_]u32{
1892 elf_file.debug_abbrev_section_index.?,
1893 elf_file.debug_aranges_section_index.?,
1894 elf_file.eh_frame_section_index.?,
1895 elf_file.debug_info_section_index.?,
1896 elf_file.debug_line_section_index.?,
1897 elf_file.debug_line_str_section_index.?,
1898 elf_file.debug_loclists_section_index.?,
1899 elf_file.debug_rnglists_section_index.?,
1900 elf_file.debug_str_section_index.?,
1901 }) |sec, section_index| {
1902 const shdr = &elf_file.sections.items(.shdr)[section_index];
1903 sec.index = section_index;
1904 sec.off = shdr.sh_offset;
1905 sec.len = shdr.sh_size;
1906 }
1907 } else if (dwarf.bin_file.cast(.macho)) |macho_file| {
1901 if (dwarf.bin_file.cast(.macho)) |macho_file| {
19081902 if (macho_file.d_sym) |*d_sym| {
19091903 for ([_]*Section{
19101904 &dwarf.debug_abbrev.section,
......@@ -1927,7 +1921,6 @@ pub fn reloadSectionMetadata(dwarf: *Dwarf) void {
19271921 }) |sec, sect_index| {
19281922 const header = &d_sym.sections.items[sect_index];
19291923 sec.index = sect_index;
1930 sec.off = header.offset;
19311924 sec.len = header.size;
19321925 }
19331926 } else {
......@@ -1952,7 +1945,6 @@ pub fn reloadSectionMetadata(dwarf: *Dwarf) void {
19521945 }) |sec, sect_index| {
19531946 const header = &macho_file.sections.items(.header)[sect_index];
19541947 sec.index = sect_index;
1955 sec.off = header.offset;
19561948 sec.len = header.size;
19571949 }
19581950 }
......@@ -1960,6 +1952,32 @@ pub fn reloadSectionMetadata(dwarf: *Dwarf) void {
19601952}
19611953
19621954pub fn initMetadata(dwarf: *Dwarf) UpdateError!void {
1955 if (dwarf.bin_file.cast(.elf)) |elf_file| {
1956 const zo = elf_file.zigObjectPtr().?;
1957 for ([_]*Section{
1958 &dwarf.debug_abbrev.section,
1959 &dwarf.debug_aranges.section,
1960 &dwarf.debug_frame.section,
1961 &dwarf.debug_info.section,
1962 &dwarf.debug_line.section,
1963 &dwarf.debug_line_str.section,
1964 &dwarf.debug_loclists.section,
1965 &dwarf.debug_rnglists.section,
1966 &dwarf.debug_str.section,
1967 }, [_]u32{
1968 zo.debug_abbrev_index.?,
1969 zo.debug_aranges_index.?,
1970 zo.eh_frame_index.?,
1971 zo.debug_info_index.?,
1972 zo.debug_line_index.?,
1973 zo.debug_line_str_index.?,
1974 zo.debug_loclists_index.?,
1975 zo.debug_rnglists_index.?,
1976 zo.debug_str_index.?,
1977 }) |sec, sym_index| {
1978 sec.index = sym_index;
1979 }
1980 }
19631981 dwarf.reloadSectionMetadata();
19641982
19651983 dwarf.debug_abbrev.section.pad_to_ideal = false;
......@@ -2523,7 +2541,7 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool
25232541 var abbrev_code_buf: [AbbrevCode.decl_bytes]u8 = undefined;
25242542 if (try dwarf.getFile().?.preadAll(
25252543 &abbrev_code_buf,
2526 dwarf.debug_info.section.off + unit_ptr.off + unit_ptr.header_len + entry_ptr.off,
2544 dwarf.debug_info.section.off(dwarf) + unit_ptr.off + unit_ptr.header_len + entry_ptr.off,
25272545 ) != abbrev_code_buf.len) return error.InputOutput;
25282546 var abbrev_code_fbs = std.io.fixedBufferStream(&abbrev_code_buf);
25292547 const abbrev_code: AbbrevCode = @enumFromInt(
......@@ -3934,7 +3952,7 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {
39343952 if (dwarf.debug_str.section.dirty) {
39353953 const contents = dwarf.debug_str.contents.items;
39363954 try dwarf.debug_str.section.resize(dwarf, contents.len);
3937 try dwarf.getFile().?.pwriteAll(contents, dwarf.debug_str.section.off);
3955 try dwarf.getFile().?.pwriteAll(contents, dwarf.debug_str.section.off(dwarf));
39383956 dwarf.debug_str.section.dirty = false;
39393957 }
39403958 if (dwarf.debug_line.section.dirty) {
......@@ -4040,7 +4058,7 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {
40404058 if (dwarf.debug_line_str.section.dirty) {
40414059 const contents = dwarf.debug_line_str.contents.items;
40424060 try dwarf.debug_line_str.section.resize(dwarf, contents.len);
4043 try dwarf.getFile().?.pwriteAll(contents, dwarf.debug_line_str.section.off);
4061 try dwarf.getFile().?.pwriteAll(contents, dwarf.debug_line_str.section.off(dwarf));
40444062 dwarf.debug_line_str.section.dirty = false;
40454063 }
40464064 if (dwarf.debug_loclists.section.dirty) {
src/link/Elf.zig+328-293
......@@ -54,16 +54,6 @@ shdr_table_offset: ?u64 = null,
5454/// Same order as in the file.
5555phdrs: std.ArrayListUnmanaged(elf.Elf64_Phdr) = .{},
5656
57/// Tracked loadable segments during incremental linking.
58/// The index into the program headers of a PT_LOAD program header with Read and Execute flags
59phdr_zig_load_re_index: ?u16 = null,
60/// The index into the program headers of a PT_LOAD program header with Read flag
61phdr_zig_load_ro_index: ?u16 = null,
62/// The index into the program headers of a PT_LOAD program header with Write flag
63phdr_zig_load_rw_index: ?u16 = null,
64/// The index into the program headers of a PT_LOAD program header with zerofill data.
65phdr_zig_load_zerofill_index: ?u16 = null,
66
6757/// Special program headers
6858/// PT_PHDR
6959phdr_table_index: ?u16 = null,
......@@ -124,22 +114,6 @@ rela_plt: std.ArrayListUnmanaged(elf.Elf64_Rela) = .{},
124114/// Applies only to a relocatable.
125115comdat_group_sections: std.ArrayListUnmanaged(ComdatGroupSection) = .{},
126116
127/// Tracked section headers with incremental updates to Zig object.
128/// .rela.* sections are only used when emitting a relocatable object file.
129zig_text_section_index: ?u32 = null,
130zig_data_rel_ro_section_index: ?u32 = null,
131zig_data_section_index: ?u32 = null,
132zig_bss_section_index: ?u32 = null,
133
134debug_info_section_index: ?u32 = null,
135debug_abbrev_section_index: ?u32 = null,
136debug_str_section_index: ?u32 = null,
137debug_aranges_section_index: ?u32 = null,
138debug_line_section_index: ?u32 = null,
139debug_line_str_section_index: ?u32 = null,
140debug_loclists_section_index: ?u32 = null,
141debug_rnglists_section_index: ?u32 = null,
142
143117copy_rel_section_index: ?u32 = null,
144118dynamic_section_index: ?u32 = null,
145119dynstrtab_section_index: ?u32 = null,
......@@ -419,7 +393,8 @@ pub fn deinit(self: *Elf) void {
419393 self.objects.deinit(gpa);
420394 self.shared_objects.deinit(gpa);
421395
422 for (self.sections.items(.atom_list), self.sections.items(.free_list)) |*atoms, *free_list| {
396 for (self.sections.items(.atom_list_2), self.sections.items(.atom_list), self.sections.items(.free_list)) |*atom_list, *atoms, *free_list| {
397 atom_list.deinit(gpa);
423398 atoms.deinit(gpa);
424399 free_list.deinit(gpa);
425400 }
......@@ -554,7 +529,7 @@ pub fn findFreeSpace(self: *Elf, object_size: u64, min_alignment: u64) !u64 {
554529 return start;
555530}
556531
557pub fn growAllocSection(self: *Elf, shdr_index: u32, needed_size: u64) !void {
532pub fn growAllocSection(self: *Elf, shdr_index: u32, needed_size: u64, min_alignment: u64) !void {
558533 const slice = self.sections.slice();
559534 const shdr = &slice.items(.shdr)[shdr_index];
560535 assert(shdr.sh_flags & elf.SHF_ALLOC != 0);
......@@ -573,8 +548,7 @@ pub fn growAllocSection(self: *Elf, shdr_index: u32, needed_size: u64) !void {
573548 const existing_size = shdr.sh_size;
574549 shdr.sh_size = 0;
575550 // Must move the entire section.
576 const alignment = if (maybe_phdr) |phdr| phdr.p_align else shdr.sh_addralign;
577 const new_offset = try self.findFreeSpace(needed_size, alignment);
551 const new_offset = try self.findFreeSpace(needed_size, min_alignment);
578552
579553 log.debug("new '{s}' file offset 0x{x} to 0x{x}", .{
580554 self.getShString(shdr.sh_name),
......@@ -614,7 +588,7 @@ pub fn growNonAllocSection(
614588 self: *Elf,
615589 shdr_index: u32,
616590 needed_size: u64,
617 min_alignment: u32,
591 min_alignment: u64,
618592 requires_file_copy: bool,
619593) !void {
620594 const shdr = &self.sections.items(.shdr)[shdr_index];
......@@ -648,33 +622,124 @@ pub fn growNonAllocSection(
648622 try self.base.file.?.setEndPos(shdr.sh_offset + needed_size);
649623 }
650624 shdr.sh_size = needed_size;
651
652625 self.markDirty(shdr_index);
653626}
654627
655628pub fn markDirty(self: *Elf, shdr_index: u32) void {
656 const zig_object = self.zigObjectPtr().?;
657 if (zig_object.dwarf) |_| {
658 if (self.debug_info_section_index.? == shdr_index) {
659 zig_object.debug_info_section_dirty = true;
660 } else if (self.debug_abbrev_section_index.? == shdr_index) {
661 zig_object.debug_abbrev_section_dirty = true;
662 } else if (self.debug_str_section_index.? == shdr_index) {
663 zig_object.debug_str_section_dirty = true;
664 } else if (self.debug_aranges_section_index.? == shdr_index) {
665 zig_object.debug_aranges_section_dirty = true;
666 } else if (self.debug_line_section_index.? == shdr_index) {
667 zig_object.debug_line_section_dirty = true;
668 } else if (self.debug_line_str_section_index.? == shdr_index) {
669 zig_object.debug_line_str_section_dirty = true;
670 } else if (self.debug_loclists_section_index.? == shdr_index) {
671 zig_object.debug_loclists_section_dirty = true;
672 } else if (self.debug_rnglists_section_index.? == shdr_index) {
673 zig_object.debug_rnglists_section_dirty = true;
629 if (self.zigObjectPtr()) |zo| {
630 for ([_]?Symbol.Index{
631 zo.debug_info_index,
632 zo.debug_abbrev_index,
633 zo.debug_aranges_index,
634 zo.debug_str_index,
635 zo.debug_line_index,
636 zo.debug_line_str_index,
637 zo.debug_loclists_index,
638 zo.debug_rnglists_index,
639 }, [_]*bool{
640 &zo.debug_info_section_dirty,
641 &zo.debug_abbrev_section_dirty,
642 &zo.debug_aranges_section_dirty,
643 &zo.debug_str_section_dirty,
644 &zo.debug_line_section_dirty,
645 &zo.debug_line_str_section_dirty,
646 &zo.debug_loclists_section_dirty,
647 &zo.debug_rnglists_section_dirty,
648 }) |maybe_sym_index, dirty| {
649 const sym_index = maybe_sym_index orelse continue;
650 if (zo.symbol(sym_index).atom(self).?.output_section_index == shdr_index) {
651 dirty.* = true;
652 break;
653 }
674654 }
675655 }
676656}
677657
658const AllocateChunkResult = struct {
659 value: u64,
660 placement: Ref,
661};
662
663pub fn allocateChunk(self: *Elf, args: struct {
664 size: u64,
665 shndx: u32,
666 alignment: Atom.Alignment,
667 requires_padding: bool = true,
668}) !AllocateChunkResult {
669 const slice = self.sections.slice();
670 const shdr = &slice.items(.shdr)[args.shndx];
671 const free_list = &slice.items(.free_list)[args.shndx];
672 const last_atom_ref = &slice.items(.last_atom)[args.shndx];
673 const new_atom_ideal_capacity = if (args.requires_padding) padToIdeal(args.size) else args.size;
674
675 // First we look for an appropriately sized free list node.
676 // The list is unordered. We'll just take the first thing that works.
677 const res: AllocateChunkResult = blk: {
678 var i: usize = if (self.base.child_pid == null) 0 else free_list.items.len;
679 while (i < free_list.items.len) {
680 const big_atom_ref = free_list.items[i];
681 const big_atom = self.atom(big_atom_ref).?;
682 // We now have a pointer to a live atom that has too much capacity.
683 // Is it enough that we could fit this new atom?
684 const cap = big_atom.capacity(self);
685 const ideal_capacity = if (args.requires_padding) padToIdeal(cap) else cap;
686 const ideal_capacity_end_vaddr = std.math.add(u64, @intCast(big_atom.value), ideal_capacity) catch ideal_capacity;
687 const capacity_end_vaddr = @as(u64, @intCast(big_atom.value)) + cap;
688 const new_start_vaddr_unaligned = capacity_end_vaddr - new_atom_ideal_capacity;
689 const new_start_vaddr = args.alignment.backward(new_start_vaddr_unaligned);
690 if (new_start_vaddr < ideal_capacity_end_vaddr) {
691 // Additional bookkeeping here to notice if this free list node
692 // should be deleted because the block that it points to has grown to take up
693 // more of the extra capacity.
694 if (!big_atom.freeListEligible(self)) {
695 _ = free_list.swapRemove(i);
696 } else {
697 i += 1;
698 }
699 continue;
700 }
701 // At this point we know that we will place the new block here. But the
702 // remaining question is whether there is still yet enough capacity left
703 // over for there to still be a free list node.
704 const remaining_capacity = new_start_vaddr - ideal_capacity_end_vaddr;
705 const keep_free_list_node = remaining_capacity >= min_text_capacity;
706
707 if (!keep_free_list_node) {
708 _ = free_list.swapRemove(i);
709 }
710 break :blk .{ .value = new_start_vaddr, .placement = big_atom_ref };
711 } else if (self.atom(last_atom_ref.*)) |last_atom| {
712 const ideal_capacity = if (args.requires_padding) padToIdeal(last_atom.size) else last_atom.size;
713 const ideal_capacity_end_vaddr = @as(u64, @intCast(last_atom.value)) + ideal_capacity;
714 const new_start_vaddr = args.alignment.forward(ideal_capacity_end_vaddr);
715 break :blk .{ .value = new_start_vaddr, .placement = last_atom.ref() };
716 } else {
717 break :blk .{ .value = 0, .placement = .{} };
718 }
719 };
720
721 log.debug("allocated chunk (size({x}),align({x})) at 0x{x} (file(0x{x}))", .{
722 args.size,
723 args.alignment.toByteUnits().?,
724 shdr.sh_addr + res.value,
725 shdr.sh_offset + res.value,
726 });
727
728 const expand_section = if (self.atom(res.placement)) |placement_atom|
729 placement_atom.nextAtom(self) == null
730 else
731 true;
732 if (expand_section) {
733 const needed_size = res.value + args.size;
734 if (shdr.sh_flags & elf.SHF_ALLOC != 0)
735 try self.growAllocSection(args.shndx, needed_size, args.alignment.toByteUnits().?)
736 else
737 try self.growNonAllocSection(args.shndx, needed_size, args.alignment.toByteUnits().?, true);
738 }
739
740 return res;
741}
742
678743pub fn flush(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void {
679744 const use_lld = build_options.have_llvm and self.base.comp.config.use_lld;
680745 if (use_lld) {
......@@ -972,14 +1037,13 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
9721037 try self.initSyntheticSections();
9731038 try self.initSpecialPhdrs();
9741039 try self.sortShdrs();
975 for (self.objects.items) |index| {
976 try self.file(index).?.object.addAtomsToOutputSections(self);
977 }
978 try self.sortInitFini();
1040
9791041 try self.setDynamicSection(rpath_table.keys());
9801042 self.sortDynamicSymtab();
9811043 try self.setHashSections();
9821044 try self.setVersionSymtab();
1045
1046 try self.sortInitFini();
9831047 try self.updateMergeSectionSizes();
9841048 try self.updateSectionSizes();
9851049
......@@ -1010,7 +1074,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
10101074 if (shdr.sh_type == elf.SHT_NOBITS) continue;
10111075 const code = try zo.codeAlloc(self, atom_index);
10121076 defer gpa.free(code);
1013 const file_offset = shdr.sh_offset + @as(u64, @intCast(atom_ptr.value));
1077 const file_offset = atom_ptr.offset(self);
10141078 atom_ptr.resolveRelocsAlloc(self, code) catch |err| switch (err) {
10151079 error.RelocFailure, error.RelaxFailure => has_reloc_errors = true,
10161080 error.UnsupportedCpuArch => {
......@@ -1750,6 +1814,59 @@ fn scanRelocs(self: *Elf) !void {
17501814 }
17511815}
17521816
1817pub fn initOutputSection(self: *Elf, args: struct {
1818 name: [:0]const u8,
1819 flags: u64,
1820 type: u32,
1821}) error{OutOfMemory}!u32 {
1822 const name = blk: {
1823 if (self.base.isRelocatable()) break :blk args.name;
1824 if (args.flags & elf.SHF_MERGE != 0) break :blk args.name;
1825 const name_prefixes: []const [:0]const u8 = &.{
1826 ".text", ".data.rel.ro", ".data", ".rodata", ".bss.rel.ro", ".bss",
1827 ".init_array", ".fini_array", ".tbss", ".tdata", ".gcc_except_table", ".ctors",
1828 ".dtors", ".gnu.warning",
1829 };
1830 inline for (name_prefixes) |prefix| {
1831 if (std.mem.eql(u8, args.name, prefix) or std.mem.startsWith(u8, args.name, prefix ++ ".")) {
1832 break :blk prefix;
1833 }
1834 }
1835 break :blk args.name;
1836 };
1837 const @"type" = tt: {
1838 if (self.getTarget().cpu.arch == .x86_64 and args.type == elf.SHT_X86_64_UNWIND)
1839 break :tt elf.SHT_PROGBITS;
1840 switch (args.type) {
1841 elf.SHT_NULL => unreachable,
1842 elf.SHT_PROGBITS => {
1843 if (std.mem.eql(u8, args.name, ".init_array") or std.mem.startsWith(u8, args.name, ".init_array."))
1844 break :tt elf.SHT_INIT_ARRAY;
1845 if (std.mem.eql(u8, args.name, ".fini_array") or std.mem.startsWith(u8, args.name, ".fini_array."))
1846 break :tt elf.SHT_FINI_ARRAY;
1847 break :tt args.type;
1848 },
1849 else => break :tt args.type,
1850 }
1851 };
1852 const flags = blk: {
1853 var flags = args.flags;
1854 if (!self.base.isRelocatable()) {
1855 flags &= ~@as(u64, elf.SHF_COMPRESSED | elf.SHF_GROUP | elf.SHF_GNU_RETAIN);
1856 }
1857 break :blk switch (@"type") {
1858 elf.SHT_INIT_ARRAY, elf.SHT_FINI_ARRAY => flags | elf.SHF_WRITE,
1859 else => flags,
1860 };
1861 };
1862 const out_shndx = self.sectionByName(name) orelse try self.addSection(.{
1863 .type = @"type",
1864 .flags = flags,
1865 .name = try self.insertShString(name),
1866 });
1867 return out_shndx;
1868}
1869
17531870fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) !void {
17541871 dev.check(.lld_linker);
17551872
......@@ -2783,12 +2900,16 @@ fn initSyntheticSections(self: *Elf) !void {
27832900 const target = self.getTarget();
27842901 const ptr_size = self.ptrWidthBytes();
27852902
2786 const needs_eh_frame = for (self.objects.items) |index| {
2787 if (self.file(index).?.object.cies.items.len > 0) break true;
2788 } else false;
2903 const needs_eh_frame = blk: {
2904 if (self.zigObjectPtr()) |zo|
2905 if (zo.eh_frame_index != null) break :blk true;
2906 break :blk for (self.objects.items) |index| {
2907 if (self.file(index).?.object.cies.items.len > 0) break true;
2908 } else false;
2909 };
27892910 if (needs_eh_frame) {
27902911 if (self.eh_frame_section_index == null) {
2791 self.eh_frame_section_index = try self.addSection(.{
2912 self.eh_frame_section_index = self.sectionByName(".eh_frame") orelse try self.addSection(.{
27922913 .name = try self.insertShString(".eh_frame"),
27932914 .type = if (target.cpu.arch == .x86_64)
27942915 elf.SHT_X86_64_UNWIND
......@@ -3084,8 +3205,9 @@ fn sortInitFini(self: *Elf) !void {
30843205 }
30853206 };
30863207
3087 for (slice.items(.shdr), slice.items(.atom_list)) |shdr, *atom_list| {
3208 for (slice.items(.shdr), slice.items(.atom_list_2)) |shdr, *atom_list| {
30883209 if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue;
3210 if (atom_list.atoms.items.len == 0) continue;
30893211
30903212 var is_init_fini = false;
30913213 var is_ctor_dtor = false;
......@@ -3099,15 +3221,13 @@ fn sortInitFini(self: *Elf) !void {
30993221 is_ctor_dtor = mem.indexOf(u8, name, ".ctors") != null or mem.indexOf(u8, name, ".dtors") != null;
31003222 },
31013223 }
3102
31033224 if (!is_init_fini and !is_ctor_dtor) continue;
3104 if (atom_list.items.len == 0) continue;
31053225
31063226 var entries = std.ArrayList(Entry).init(gpa);
3107 try entries.ensureTotalCapacityPrecise(atom_list.items.len);
3227 try entries.ensureTotalCapacityPrecise(atom_list.atoms.items.len);
31083228 defer entries.deinit();
31093229
3110 for (atom_list.items) |ref| {
3230 for (atom_list.atoms.items) |ref| {
31113231 const atom_ptr = self.atom(ref).?;
31123232 const object = atom_ptr.file(self).?.object;
31133233 const priority = blk: {
......@@ -3126,9 +3246,9 @@ fn sortInitFini(self: *Elf) !void {
31263246
31273247 mem.sort(Entry, entries.items, self, Entry.lessThan);
31283248
3129 atom_list.clearRetainingCapacity();
3249 atom_list.atoms.clearRetainingCapacity();
31303250 for (entries.items) |entry| {
3131 atom_list.appendAssumeCapacity(entry.atom_ref);
3251 atom_list.atoms.appendAssumeCapacity(entry.atom_ref);
31323252 }
31333253 }
31343254}
......@@ -3233,9 +3353,6 @@ fn sortPhdrs(self: *Elf) error{OutOfMemory}!void {
32333353 }
32343354
32353355 for (&[_]*?u16{
3236 &self.phdr_zig_load_re_index,
3237 &self.phdr_zig_load_ro_index,
3238 &self.phdr_zig_load_zerofill_index,
32393356 &self.phdr_table_index,
32403357 &self.phdr_table_load_index,
32413358 &self.phdr_interp_index,
......@@ -3272,33 +3389,36 @@ fn shdrRank(self: *Elf, shndx: u32) u8 {
32723389 elf.SHT_PREINIT_ARRAY,
32733390 elf.SHT_INIT_ARRAY,
32743391 elf.SHT_FINI_ARRAY,
3275 => return 0xf2,
3392 => return 0xf1,
32763393
3277 elf.SHT_DYNAMIC => return 0xf3,
3394 elf.SHT_DYNAMIC => return 0xf2,
32783395
32793396 elf.SHT_RELA, elf.SHT_GROUP => return 0xf,
32803397
32813398 elf.SHT_PROGBITS => if (flags & elf.SHF_ALLOC != 0) {
32823399 if (flags & elf.SHF_EXECINSTR != 0) {
3283 return 0xf1;
3400 return 0xf0;
32843401 } else if (flags & elf.SHF_WRITE != 0) {
3285 return if (flags & elf.SHF_TLS != 0) 0xf4 else 0xf6;
3402 return if (flags & elf.SHF_TLS != 0) 0xf3 else 0xf5;
32863403 } else if (mem.eql(u8, name, ".interp")) {
32873404 return 1;
3405 } else if (mem.startsWith(u8, name, ".eh_frame")) {
3406 return 0xe1;
32883407 } else {
3289 return 0xf0;
3408 return 0xe0;
32903409 }
32913410 } else {
32923411 if (mem.startsWith(u8, name, ".debug")) {
3293 return 0xf8;
3412 return 0xf7;
32943413 } else {
3295 return 0xf9;
3414 return 0xf8;
32963415 }
32973416 },
3417 elf.SHT_X86_64_UNWIND => return 0xe1,
32983418
3299 elf.SHT_NOBITS => return if (flags & elf.SHF_TLS != 0) 0xf5 else 0xf7,
3300 elf.SHT_SYMTAB => return 0xfa,
3301 elf.SHT_STRTAB => return if (mem.eql(u8, name, ".dynstr")) 0x4 else 0xfb,
3419 elf.SHT_NOBITS => return if (flags & elf.SHF_TLS != 0) 0xf4 else 0xf6,
3420 elf.SHT_SYMTAB => return 0xf9,
3421 elf.SHT_STRTAB => return if (mem.eql(u8, name, ".dynstr")) 0x4 else 0xfa,
33023422 else => return 0xff,
33033423 }
33043424}
......@@ -3361,18 +3481,6 @@ fn resetShdrIndexes(self: *Elf, backlinks: []const u32) void {
33613481 &self.copy_rel_section_index,
33623482 &self.versym_section_index,
33633483 &self.verneed_section_index,
3364 &self.zig_text_section_index,
3365 &self.zig_data_rel_ro_section_index,
3366 &self.zig_data_section_index,
3367 &self.zig_bss_section_index,
3368 &self.debug_info_section_index,
3369 &self.debug_abbrev_section_index,
3370 &self.debug_str_section_index,
3371 &self.debug_aranges_section_index,
3372 &self.debug_line_section_index,
3373 &self.debug_line_str_section_index,
3374 &self.debug_loclists_section_index,
3375 &self.debug_rnglists_section_index,
33763484 }) |maybe_index| {
33773485 if (maybe_index.*) |*index| {
33783486 index.* = backlinks[index.*];
......@@ -3383,13 +3491,19 @@ fn resetShdrIndexes(self: *Elf, backlinks: []const u32) void {
33833491 msec.output_section_index = backlinks[msec.output_section_index];
33843492 }
33853493
3386 for (self.sections.items(.shdr)) |*shdr| {
3387 if (shdr.sh_type != elf.SHT_RELA) continue;
3388 // FIXME:JK we should spin up .symtab potentially earlier, or set all non-dynamic RELA sections
3389 // to point at symtab
3390 // shdr.sh_link = backlinks[shdr.sh_link];
3391 shdr.sh_link = self.symtab_section_index.?;
3392 shdr.sh_info = backlinks[shdr.sh_info];
3494 const slice = self.sections.slice();
3495 for (slice.items(.shdr), slice.items(.atom_list_2)) |*shdr, *atom_list| {
3496 atom_list.output_section_index = backlinks[atom_list.output_section_index];
3497 for (atom_list.atoms.items) |ref| {
3498 self.atom(ref).?.output_section_index = atom_list.output_section_index;
3499 }
3500 if (shdr.sh_type == elf.SHT_RELA) {
3501 // FIXME:JK we should spin up .symtab potentially earlier, or set all non-dynamic RELA sections
3502 // to point at symtab
3503 // shdr.sh_link = backlinks[shdr.sh_link];
3504 shdr.sh_link = self.symtab_section_index.?;
3505 shdr.sh_info = backlinks[shdr.sh_info];
3506 }
33933507 }
33943508
33953509 if (self.zigObjectPtr()) |zo| {
......@@ -3397,7 +3511,6 @@ fn resetShdrIndexes(self: *Elf, backlinks: []const u32) void {
33973511 const atom_ptr = zo.atom(atom_index) orelse continue;
33983512 atom_ptr.output_section_index = backlinks[atom_ptr.output_section_index];
33993513 }
3400 if (zo.dwarf) |*dwarf| dwarf.reloadSectionMetadata();
34013514 }
34023515
34033516 for (self.comdat_group_sections.items) |*cg| {
......@@ -3405,53 +3518,53 @@ fn resetShdrIndexes(self: *Elf, backlinks: []const u32) void {
34053518 }
34063519
34073520 if (self.symtab_section_index) |index| {
3408 const shdr = &self.sections.items(.shdr)[index];
3521 const shdr = &slice.items(.shdr)[index];
34093522 shdr.sh_link = self.strtab_section_index.?;
34103523 }
34113524
34123525 if (self.dynamic_section_index) |index| {
3413 const shdr = &self.sections.items(.shdr)[index];
3526 const shdr = &slice.items(.shdr)[index];
34143527 shdr.sh_link = self.dynstrtab_section_index.?;
34153528 }
34163529
34173530 if (self.dynsymtab_section_index) |index| {
3418 const shdr = &self.sections.items(.shdr)[index];
3531 const shdr = &slice.items(.shdr)[index];
34193532 shdr.sh_link = self.dynstrtab_section_index.?;
34203533 }
34213534
34223535 if (self.hash_section_index) |index| {
3423 const shdr = &self.sections.items(.shdr)[index];
3536 const shdr = &slice.items(.shdr)[index];
34243537 shdr.sh_link = self.dynsymtab_section_index.?;
34253538 }
34263539
34273540 if (self.gnu_hash_section_index) |index| {
3428 const shdr = &self.sections.items(.shdr)[index];
3541 const shdr = &slice.items(.shdr)[index];
34293542 shdr.sh_link = self.dynsymtab_section_index.?;
34303543 }
34313544
34323545 if (self.versym_section_index) |index| {
3433 const shdr = &self.sections.items(.shdr)[index];
3546 const shdr = &slice.items(.shdr)[index];
34343547 shdr.sh_link = self.dynsymtab_section_index.?;
34353548 }
34363549
34373550 if (self.verneed_section_index) |index| {
3438 const shdr = &self.sections.items(.shdr)[index];
3551 const shdr = &slice.items(.shdr)[index];
34393552 shdr.sh_link = self.dynstrtab_section_index.?;
34403553 }
34413554
34423555 if (self.rela_dyn_section_index) |index| {
3443 const shdr = &self.sections.items(.shdr)[index];
3556 const shdr = &slice.items(.shdr)[index];
34443557 shdr.sh_link = self.dynsymtab_section_index orelse 0;
34453558 }
34463559
34473560 if (self.rela_plt_section_index) |index| {
3448 const shdr = &self.sections.items(.shdr)[index];
3561 const shdr = &slice.items(.shdr)[index];
34493562 shdr.sh_link = self.dynsymtab_section_index.?;
34503563 shdr.sh_info = self.plt_section_index.?;
34513564 }
34523565
34533566 if (self.eh_frame_rela_section_index) |index| {
3454 const shdr = &self.sections.items(.shdr)[index];
3567 const shdr = &slice.items(.shdr)[index];
34553568 shdr.sh_link = self.symtab_section_index.?;
34563569 shdr.sh_info = self.eh_frame_section_index.?;
34573570 }
......@@ -3459,37 +3572,32 @@ fn resetShdrIndexes(self: *Elf, backlinks: []const u32) void {
34593572
34603573fn updateSectionSizes(self: *Elf) !void {
34613574 const slice = self.sections.slice();
3462 for (slice.items(.shdr), slice.items(.atom_list)) |*shdr, atom_list| {
3463 if (atom_list.items.len == 0) continue;
3575 for (slice.items(.shdr), slice.items(.atom_list_2)) |shdr, *atom_list| {
3576 if (atom_list.atoms.items.len == 0) continue;
34643577 if (self.requiresThunks() and shdr.sh_flags & elf.SHF_EXECINSTR != 0) continue;
3465 for (atom_list.items) |ref| {
3466 const atom_ptr = self.atom(ref) orelse continue;
3467 if (!atom_ptr.alive) continue;
3468 const offset = atom_ptr.alignment.forward(shdr.sh_size);
3469 const padding = offset - shdr.sh_size;
3470 atom_ptr.value = @intCast(offset);
3471 shdr.sh_size += padding + atom_ptr.size;
3472 shdr.sh_addralign = @max(shdr.sh_addralign, atom_ptr.alignment.toByteUnits() orelse 1);
3473 }
3578 atom_list.updateSize(self);
3579 try atom_list.allocate(self);
34743580 }
34753581
34763582 if (self.requiresThunks()) {
3477 for (slice.items(.shdr), slice.items(.atom_list), 0..) |*shdr, atom_list, shndx| {
3583 for (slice.items(.shdr), slice.items(.atom_list_2)) |shdr, *atom_list| {
34783584 if (shdr.sh_flags & elf.SHF_EXECINSTR == 0) continue;
3479 if (atom_list.items.len == 0) continue;
3585 if (atom_list.atoms.items.len == 0) continue;
34803586
34813587 // Create jump/branch range extenders if needed.
3482 try self.createThunks(shdr, @intCast(shndx));
3588 try self.createThunks(atom_list);
3589 try atom_list.allocate(self);
3590 }
3591
3592 // FIXME:JK this will hopefully not be needed once we create a link from Atom/Thunk to AtomList.
3593 for (self.thunks.items) |*th| {
3594 th.value += slice.items(.atom_list_2)[th.output_section_index].value;
34833595 }
34843596 }
34853597
34863598 const shdrs = slice.items(.shdr);
34873599 if (self.eh_frame_section_index) |index| {
3488 shdrs[index].sh_size = existing_size: {
3489 const zo = self.zigObjectPtr() orelse break :existing_size 0;
3490 const sym = zo.symbol(zo.eh_frame_index orelse break :existing_size 0);
3491 break :existing_size sym.atom(self).?.size;
3492 } + try eh_frame.calcEhFrameSize(self);
3600 shdrs[index].sh_size = try eh_frame.calcEhFrameSize(self);
34933601 }
34943602
34953603 if (self.eh_frame_hdr_section_index) |index| {
......@@ -3587,13 +3695,11 @@ fn shdrToPhdrFlags(sh_flags: u64) u32 {
35873695/// (This is an upper bound so that we can reserve enough space for the header and progam header
35883696/// table without running out of space and being forced to move things around.)
35893697fn getMaxNumberOfPhdrs() u64 {
3590 // First, assume we compile Zig's source incrementally, this gives us:
3591 var num: u64 = number_of_zig_segments;
3592 // Next, the estimated maximum number of segments the linker can emit for input sections are:
3593 num += max_number_of_object_segments;
3594 // Next, any other non-loadable program headers, including TLS, DYNAMIC, GNU_STACK, GNU_EH_FRAME, INTERP:
3698 // The estimated maximum number of segments the linker can emit for input sections are:
3699 var num: u64 = max_number_of_object_segments;
3700 // Any other non-loadable program headers, including TLS, DYNAMIC, GNU_STACK, GNU_EH_FRAME, INTERP:
35953701 num += max_number_of_special_phdrs;
3596 // Finally, PHDR program header and corresponding read-only load segment:
3702 // PHDR program header and corresponding read-only load segment:
35973703 num += 2;
35983704 return num;
35993705}
......@@ -3603,10 +3709,9 @@ fn getMaxNumberOfPhdrs() u64 {
36033709/// We permit a maximum of 3**2 number of segments.
36043710fn calcNumberOfSegments(self: *Elf) usize {
36053711 var covers: [9]bool = [_]bool{false} ** 9;
3606 for (self.sections.items(.shdr), 0..) |shdr, shndx| {
3712 for (self.sections.items(.shdr)) |shdr| {
36073713 if (shdr.sh_type == elf.SHT_NULL) continue;
36083714 if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue;
3609 if (self.isZigSection(@intCast(shndx))) continue;
36103715 const flags = shdrToPhdrFlags(shdr.sh_flags);
36113716 covers[flags - 1] = true;
36123717 }
......@@ -3704,7 +3809,6 @@ pub fn allocateAllocSections(self: *Elf) !void {
37043809 for (slice.items(.shdr), 0..) |shdr, shndx| {
37053810 if (shdr.sh_type == elf.SHT_NULL) continue;
37063811 if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue;
3707 if (self.isZigSection(@intCast(shndx))) continue;
37083812 const flags = shdrToPhdrFlags(shdr.sh_flags);
37093813 try covers[flags - 1].append(@intCast(shndx));
37103814 }
......@@ -3794,10 +3898,20 @@ pub fn allocateAllocSections(self: *Elf) !void {
37943898 }
37953899 new_offset = alignment.@"align"(shndx, shdr.sh_addralign, new_offset);
37963900
3797 if (shndx == self.eh_frame_section_index) eh_frame: {
3798 const zo = self.zigObjectPtr() orelse break :eh_frame;
3799 const sym = zo.symbol(zo.eh_frame_index orelse break :eh_frame);
3800 const existing_size = sym.atom(self).?.size;
3901 if (self.zigObjectPtr()) |zo| blk: {
3902 const existing_size = for ([_]?Symbol.Index{
3903 zo.text_index,
3904 zo.rodata_index,
3905 zo.data_relro_index,
3906 zo.data_index,
3907 zo.tdata_index,
3908 zo.eh_frame_index,
3909 }) |maybe_sym_index| {
3910 const sect_sym_index = maybe_sym_index orelse continue;
3911 const sect_atom_ptr = zo.symbol(sect_sym_index).atom(self).?;
3912 if (sect_atom_ptr.output_section_index != shndx) continue;
3913 break sect_atom_ptr.size;
3914 } else break :blk;
38013915 log.debug("moving {s} from 0x{x} to 0x{x}", .{
38023916 self.getShString(shdr.sh_name),
38033917 shdr.sh_offset,
......@@ -3830,27 +3944,27 @@ pub fn allocateNonAllocSections(self: *Elf) !void {
38303944 shdr.sh_size = 0;
38313945 const new_offset = try self.findFreeSpace(needed_size, shdr.sh_addralign);
38323946
3833 if (self.isDebugSection(@intCast(shndx))) {
3947 if (self.zigObjectPtr()) |zo| blk: {
3948 const existing_size = for ([_]?Symbol.Index{
3949 zo.debug_info_index,
3950 zo.debug_abbrev_index,
3951 zo.debug_aranges_index,
3952 zo.debug_str_index,
3953 zo.debug_line_index,
3954 zo.debug_line_str_index,
3955 zo.debug_loclists_index,
3956 zo.debug_rnglists_index,
3957 }) |maybe_sym_index| {
3958 const sym_index = maybe_sym_index orelse continue;
3959 const sym = zo.symbol(sym_index);
3960 const atom_ptr = sym.atom(self).?;
3961 if (atom_ptr.output_section_index == shndx) break atom_ptr.size;
3962 } else break :blk;
38343963 log.debug("moving {s} from 0x{x} to 0x{x}", .{
38353964 self.getShString(shdr.sh_name),
38363965 shdr.sh_offset,
38373966 new_offset,
38383967 });
3839 const zo = self.zigObjectPtr().?;
3840 const existing_size = for ([_]Symbol.Index{
3841 zo.debug_info_index.?,
3842 zo.debug_abbrev_index.?,
3843 zo.debug_aranges_index.?,
3844 zo.debug_str_index.?,
3845 zo.debug_line_index.?,
3846 zo.debug_line_str_index.?,
3847 zo.debug_loclists_index.?,
3848 zo.debug_rnglists_index.?,
3849 }) |sym_index| {
3850 const sym = zo.symbol(sym_index);
3851 const atom_ptr = sym.atom(self).?;
3852 if (atom_ptr.output_section_index == shndx) break atom_ptr.size;
3853 } else 0;
38543968 const amt = try self.base.file.?.copyRangeAll(
38553969 shdr.sh_offset,
38563970 self.base.file.?,
......@@ -3934,91 +4048,28 @@ fn writeAtoms(self: *Elf) !void {
39344048 undefs.deinit();
39354049 }
39364050
3937 var has_reloc_errors = false;
4051 var buffer = std.ArrayList(u8).init(gpa);
4052 defer buffer.deinit();
4053
39384054 const slice = self.sections.slice();
3939 for (slice.items(.shdr), slice.items(.atom_list), 0..) |shdr, atom_list, shndx| {
3940 if (shdr.sh_type == elf.SHT_NULL) continue;
4055 var has_reloc_errors = false;
4056 for (slice.items(.shdr), slice.items(.atom_list_2)) |shdr, atom_list| {
39414057 if (shdr.sh_type == elf.SHT_NOBITS) continue;
3942 if (atom_list.items.len == 0) continue;
3943
3944 log.debug("writing atoms in '{s}' section", .{self.getShString(shdr.sh_name)});
3945
3946 // TODO really, really handle debug section separately
3947 const base_offset = if (self.isDebugSection(@intCast(shndx))) base_offset: {
3948 const zo = self.zigObjectPtr().?;
3949 for ([_]Symbol.Index{
3950 zo.debug_info_index.?,
3951 zo.debug_abbrev_index.?,
3952 zo.debug_aranges_index.?,
3953 zo.debug_str_index.?,
3954 zo.debug_line_index.?,
3955 zo.debug_line_str_index.?,
3956 zo.debug_loclists_index.?,
3957 zo.debug_rnglists_index.?,
3958 }) |sym_index| {
3959 const sym = zo.symbol(sym_index);
3960 const atom_ptr = sym.atom(self).?;
3961 if (atom_ptr.output_section_index == shndx) break :base_offset atom_ptr.size;
3962 }
3963 break :base_offset 0;
3964 } else if (@as(u32, @intCast(shndx)) == self.eh_frame_section_index) base_offset: {
3965 const zo = self.zigObjectPtr() orelse break :base_offset 0;
3966 const sym = zo.symbol(zo.eh_frame_index orelse break :base_offset 0);
3967 break :base_offset sym.atom(self).?.size;
3968 } else 0;
3969 const sh_offset = shdr.sh_offset + base_offset;
3970 const sh_size = math.cast(usize, shdr.sh_size - base_offset) orelse return error.Overflow;
3971
3972 const buffer = try gpa.alloc(u8, sh_size);
3973 defer gpa.free(buffer);
3974 const padding_byte: u8 = if (shdr.sh_type == elf.SHT_PROGBITS and
3975 shdr.sh_flags & elf.SHF_EXECINSTR != 0 and self.getTarget().cpu.arch == .x86_64)
3976 0xcc // int3
3977 else
3978 0;
3979 @memset(buffer, padding_byte);
3980
3981 for (atom_list.items) |ref| {
3982 const atom_ptr = self.atom(ref).?;
3983 assert(atom_ptr.alive);
3984
3985 const offset = math.cast(usize, atom_ptr.value - @as(i64, @intCast(base_offset))) orelse
3986 return error.Overflow;
3987 const size = math.cast(usize, atom_ptr.size) orelse return error.Overflow;
3988
3989 log.debug("writing atom({}) at 0x{x}", .{ ref, sh_offset + offset });
3990
3991 // TODO decompress directly into provided buffer
3992 const out_code = buffer[offset..][0..size];
3993 const in_code = switch (atom_ptr.file(self).?) {
3994 .object => |x| try x.codeDecompressAlloc(self, ref.index),
3995 .zig_object => |x| try x.codeAlloc(self, ref.index),
3996 else => unreachable,
3997 };
3998 defer gpa.free(in_code);
3999 @memcpy(out_code, in_code);
4000
4001 const res = if (shdr.sh_flags & elf.SHF_ALLOC == 0)
4002 atom_ptr.resolveRelocsNonAlloc(self, out_code, &undefs)
4003 else
4004 atom_ptr.resolveRelocsAlloc(self, out_code);
4005 _ = res catch |err| switch (err) {
4006 error.UnsupportedCpuArch => {
4007 try self.reportUnsupportedCpuArch();
4008 return error.FlushFailure;
4009 },
4010 error.RelocFailure, error.RelaxFailure => has_reloc_errors = true,
4011 else => |e| return e,
4012 };
4013 }
4014
4015 try self.base.file.?.pwriteAll(buffer, sh_offset);
4058 if (atom_list.atoms.items.len == 0) continue;
4059 atom_list.write(&buffer, &undefs, self) catch |err| switch (err) {
4060 error.UnsupportedCpuArch => {
4061 try self.reportUnsupportedCpuArch();
4062 return error.FlushFailure;
4063 },
4064 error.RelocFailure, error.RelaxFailure => has_reloc_errors = true,
4065 else => |e| return e,
4066 };
40164067 }
40174068
4018 if (self.requiresThunks()) {
4019 var buffer = std.ArrayList(u8).init(gpa);
4020 defer buffer.deinit();
4069 try self.reportUndefinedSymbols(&undefs);
4070 if (has_reloc_errors) return error.FlushFailure;
40214071
4072 if (self.requiresThunks()) {
40224073 for (self.thunks.items) |th| {
40234074 const thunk_size = th.size(self);
40244075 try buffer.ensureUnusedCapacity(thunk_size);
......@@ -4030,10 +4081,6 @@ fn writeAtoms(self: *Elf) !void {
40304081 buffer.clearRetainingCapacity();
40314082 }
40324083 }
4033
4034 try self.reportUndefinedSymbols(&undefs);
4035
4036 if (has_reloc_errors) return error.FlushFailure;
40374084}
40384085
40394086pub fn updateSymtabSize(self: *Elf) !void {
......@@ -4667,34 +4714,6 @@ pub fn isEffectivelyDynLib(self: Elf) bool {
46674714 };
46684715}
46694716
4670pub fn isZigSection(self: Elf, shndx: u32) bool {
4671 inline for (&[_]?u32{
4672 self.zig_text_section_index,
4673 self.zig_data_rel_ro_section_index,
4674 self.zig_data_section_index,
4675 self.zig_bss_section_index,
4676 }) |index| {
4677 if (index == shndx) return true;
4678 }
4679 return false;
4680}
4681
4682pub fn isDebugSection(self: Elf, shndx: u32) bool {
4683 inline for (&[_]?u32{
4684 self.debug_info_section_index,
4685 self.debug_abbrev_section_index,
4686 self.debug_str_section_index,
4687 self.debug_aranges_section_index,
4688 self.debug_line_section_index,
4689 self.debug_line_str_section_index,
4690 self.debug_loclists_section_index,
4691 self.debug_rnglists_section_index,
4692 }) |index| {
4693 if (index == shndx) return true;
4694 }
4695 return false;
4696}
4697
46984717pub fn addPhdr(self: *Elf, opts: struct {
46994718 type: u32 = 0,
47004719 flags: u32 = 0,
......@@ -5070,7 +5089,7 @@ fn reportMissingLibraryError(
50705089 }
50715090}
50725091
5073pub fn reportUnsupportedCpuArch(self: *Elf) error{OutOfMemory}!void {
5092fn reportUnsupportedCpuArch(self: *Elf) error{OutOfMemory}!void {
50745093 var err = try self.base.addErrorWithNotes(0);
50755094 try err.addMsg("fatal linker error: unsupported CPU architecture {s}", .{
50765095 @tagName(self.getTarget().cpu.arch),
......@@ -5282,6 +5301,14 @@ fn fmtDumpState(
52825301 try writer.print("{}\n", .{linker_defined.fmtSymtab(self)});
52835302 }
52845303
5304 const slice = self.sections.slice();
5305 {
5306 try writer.writeAll("atom lists\n");
5307 for (slice.items(.shdr), slice.items(.atom_list_2), 0..) |shdr, atom_list, shndx| {
5308 try writer.print("shdr({d}) : {s} : {}", .{ shndx, self.getShString(shdr.sh_name), atom_list.fmt(self) });
5309 }
5310 }
5311
52855312 if (self.requiresThunks()) {
52865313 try writer.writeAll("thunks\n");
52875314 for (self.thunks.items, 0..) |th, index| {
......@@ -5303,7 +5330,7 @@ fn fmtDumpState(
53035330 }
53045331
53055332 try writer.writeAll("\nOutput shdrs\n");
5306 for (self.sections.items(.shdr), self.sections.items(.phndx), 0..) |shdr, phndx, shndx| {
5333 for (slice.items(.shdr), slice.items(.phndx), 0..) |shdr, phndx, shndx| {
53075334 try writer.print(" shdr({d}) : phdr({?d}) : {}\n", .{
53085335 shndx,
53095336 phndx,
......@@ -5373,7 +5400,6 @@ fn requiresThunks(self: Elf) bool {
53735400/// so that we reserve enough space for the program header table up-front.
53745401/// Bump these numbers when adding or deleting a Zig specific pre-allocated segment, or adding
53755402/// more special-purpose program headers.
5376pub const number_of_zig_segments = 4;
53775403const max_number_of_object_segments = 9;
53785404const max_number_of_special_phdrs = 5;
53795405
......@@ -5558,8 +5584,14 @@ const Section = struct {
55585584 phndx: ?u32 = null,
55595585
55605586 /// List of atoms contributing to this section.
5587 /// TODO currently this is only used for relocations tracking in relocatable mode
5588 /// but will be merged with atom_list_2.
55615589 atom_list: std.ArrayListUnmanaged(Ref) = .{},
55625590
5591 /// List of atoms contributing to this section.
5592 /// This can be used by sections that require special handling such as init/fini array, etc.
5593 atom_list_2: AtomList = .{},
5594
55635595 /// Index of the last allocated atom in this section.
55645596 last_atom: Ref = .{ .index = 0, .file = 0 },
55655597
......@@ -5588,9 +5620,10 @@ fn defaultEntrySymbolName(cpu_arch: std.Target.Cpu.Arch) []const u8 {
55885620 };
55895621}
55905622
5591fn createThunks(elf_file: *Elf, shdr: *elf.Elf64_Shdr, shndx: u32) !void {
5623fn createThunks(elf_file: *Elf, atom_list: *AtomList) !void {
55925624 const gpa = elf_file.base.comp.gpa;
55935625 const cpu_arch = elf_file.getTarget().cpu.arch;
5626
55945627 // A branch will need an extender if its target is larger than
55955628 // `2^(jump_bits - 1) - margin` where margin is some arbitrary number.
55965629 const max_distance = switch (cpu_arch) {
......@@ -5598,36 +5631,44 @@ fn createThunks(elf_file: *Elf, shdr: *elf.Elf64_Shdr, shndx: u32) !void {
55985631 .x86_64, .riscv64 => unreachable,
55995632 else => @panic("unhandled arch"),
56005633 };
5601 const atoms = elf_file.sections.items(.atom_list)[shndx].items;
5602 assert(atoms.len > 0);
56035634
5604 for (atoms) |ref| {
5635 const advance = struct {
5636 fn advance(list: *AtomList, size: u64, alignment: Atom.Alignment) !i64 {
5637 const offset = alignment.forward(list.size);
5638 const padding = offset - list.size;
5639 list.size += padding + size;
5640 list.alignment = list.alignment.max(alignment);
5641 return @intCast(offset);
5642 }
5643 }.advance;
5644
5645 for (atom_list.atoms.items) |ref| {
56055646 elf_file.atom(ref).?.value = -1;
56065647 }
56075648
56085649 var i: usize = 0;
5609 while (i < atoms.len) {
5650 while (i < atom_list.atoms.items.len) {
56105651 const start = i;
5611 const start_atom = elf_file.atom(atoms[start]).?;
5652 const start_atom = elf_file.atom(atom_list.atoms.items[start]).?;
56125653 assert(start_atom.alive);
5613 start_atom.value = try advanceSection(shdr, start_atom.size, start_atom.alignment);
5654 start_atom.value = try advance(atom_list, start_atom.size, start_atom.alignment);
56145655 i += 1;
56155656
5616 while (i < atoms.len) : (i += 1) {
5617 const atom_ptr = elf_file.atom(atoms[i]).?;
5657 while (i < atom_list.atoms.items.len) : (i += 1) {
5658 const atom_ptr = elf_file.atom(atom_list.atoms.items[i]).?;
56185659 assert(atom_ptr.alive);
5619 if (@as(i64, @intCast(atom_ptr.alignment.forward(shdr.sh_size))) - start_atom.value >= max_distance)
5660 if (@as(i64, @intCast(atom_ptr.alignment.forward(atom_list.size))) - start_atom.value >= max_distance)
56205661 break;
5621 atom_ptr.value = try advanceSection(shdr, atom_ptr.size, atom_ptr.alignment);
5662 atom_ptr.value = try advance(atom_list, atom_ptr.size, atom_ptr.alignment);
56225663 }
56235664
56245665 // Insert a thunk at the group end
56255666 const thunk_index = try elf_file.addThunk();
56265667 const thunk_ptr = elf_file.thunk(thunk_index);
5627 thunk_ptr.output_section_index = shndx;
5668 thunk_ptr.output_section_index = atom_list.output_section_index;
56285669
56295670 // Scan relocs in the group and create trampolines for any unreachable callsite
5630 for (atoms[start..i]) |ref| {
5671 for (atom_list.atoms.items[start..i]) |ref| {
56315672 const atom_ptr = elf_file.atom(ref).?;
56325673 const file_ptr = atom_ptr.file(elf_file).?;
56335674 log.debug("atom({}) {s}", .{ ref, atom_ptr.name(elf_file) });
......@@ -5657,18 +5698,11 @@ fn createThunks(elf_file: *Elf, shdr: *elf.Elf64_Shdr, shndx: u32) !void {
56575698 atom_ptr.addExtra(.{ .thunk = thunk_index }, elf_file);
56585699 }
56595700
5660 thunk_ptr.value = try advanceSection(shdr, thunk_ptr.size(elf_file), Atom.Alignment.fromNonzeroByteUnits(2));
5701 thunk_ptr.value = try advance(atom_list, thunk_ptr.size(elf_file), Atom.Alignment.fromNonzeroByteUnits(2));
56615702
56625703 log.debug("thunk({d}) : {}", .{ thunk_index, thunk_ptr.fmt(elf_file) });
56635704 }
56645705}
5665fn advanceSection(shdr: *elf.Elf64_Shdr, adv_size: u64, alignment: Atom.Alignment) !i64 {
5666 const offset = alignment.forward(shdr.sh_size);
5667 const padding = offset - shdr.sh_size;
5668 shdr.sh_size += padding + adv_size;
5669 shdr.sh_addralign = @max(shdr.sh_addralign, alignment.toByteUnits() orelse 1);
5670 return @intCast(offset);
5671}
56725706
56735707const std = @import("std");
56745708const build_options = @import("build_options");
......@@ -5699,6 +5733,7 @@ const Air = @import("../Air.zig");
56995733const Allocator = std.mem.Allocator;
57005734const Archive = @import("Elf/Archive.zig");
57015735pub const Atom = @import("Elf/Atom.zig");
5736const AtomList = @import("Elf/AtomList.zig");
57025737const Cache = std.Build.Cache;
57035738const Path = Cache.Path;
57045739const Compilation = @import("../Compilation.zig");
src/link/Elf/Atom.zig+15-144
......@@ -51,6 +51,11 @@ pub fn address(self: Atom, elf_file: *Elf) i64 {
5151 return @as(i64, @intCast(shdr.sh_addr)) + self.value;
5252}
5353
54pub fn offset(self: Atom, elf_file: *Elf) u64 {
55 const shdr = elf_file.sections.items(.shdr)[self.output_section_index];
56 return shdr.sh_offset + @as(u64, @intCast(self.value));
57}
58
5459pub fn ref(self: Atom) Elf.Ref {
5560 return .{ .index = self.atom_index, .file = self.file_index };
5661}
......@@ -123,140 +128,6 @@ pub fn freeListEligible(self: Atom, elf_file: *Elf) bool {
123128 return surplus >= Elf.min_text_capacity;
124129}
125130
126pub fn allocate(self: *Atom, elf_file: *Elf) !void {
127 const slice = elf_file.sections.slice();
128 const shdr = &slice.items(.shdr)[self.output_section_index];
129 const free_list = &slice.items(.free_list)[self.output_section_index];
130 const last_atom_ref = &slice.items(.last_atom)[self.output_section_index];
131 const new_atom_ideal_capacity = Elf.padToIdeal(self.size);
132
133 // We use these to indicate our intention to update metadata, placing the new atom,
134 // and possibly removing a free list node.
135 // It would be simpler to do it inside the for loop below, but that would cause a
136 // problem if an error was returned later in the function. So this action
137 // is actually carried out at the end of the function, when errors are no longer possible.
138 var atom_placement: ?Elf.Ref = null;
139 var free_list_removal: ?usize = null;
140
141 // First we look for an appropriately sized free list node.
142 // The list is unordered. We'll just take the first thing that works.
143 self.value = blk: {
144 var i: usize = if (elf_file.base.child_pid == null) 0 else free_list.items.len;
145 while (i < free_list.items.len) {
146 const big_atom_ref = free_list.items[i];
147 const big_atom = elf_file.atom(big_atom_ref).?;
148 // We now have a pointer to a live atom that has too much capacity.
149 // Is it enough that we could fit this new atom?
150 const cap = big_atom.capacity(elf_file);
151 const ideal_capacity = Elf.padToIdeal(cap);
152 const ideal_capacity_end_vaddr = std.math.add(u64, @intCast(big_atom.value), ideal_capacity) catch ideal_capacity;
153 const capacity_end_vaddr = @as(u64, @intCast(big_atom.value)) + cap;
154 const new_start_vaddr_unaligned = capacity_end_vaddr - new_atom_ideal_capacity;
155 const new_start_vaddr = self.alignment.backward(new_start_vaddr_unaligned);
156 if (new_start_vaddr < ideal_capacity_end_vaddr) {
157 // Additional bookkeeping here to notice if this free list node
158 // should be deleted because the block that it points to has grown to take up
159 // more of the extra capacity.
160 if (!big_atom.freeListEligible(elf_file)) {
161 _ = free_list.swapRemove(i);
162 } else {
163 i += 1;
164 }
165 continue;
166 }
167 // At this point we know that we will place the new block here. But the
168 // remaining question is whether there is still yet enough capacity left
169 // over for there to still be a free list node.
170 const remaining_capacity = new_start_vaddr - ideal_capacity_end_vaddr;
171 const keep_free_list_node = remaining_capacity >= Elf.min_text_capacity;
172
173 // Set up the metadata to be updated, after errors are no longer possible.
174 atom_placement = big_atom_ref;
175 if (!keep_free_list_node) {
176 free_list_removal = i;
177 }
178 break :blk @intCast(new_start_vaddr);
179 } else if (elf_file.atom(last_atom_ref.*)) |last_atom| {
180 const ideal_capacity = Elf.padToIdeal(last_atom.size);
181 const ideal_capacity_end_vaddr = @as(u64, @intCast(last_atom.value)) + ideal_capacity;
182 const new_start_vaddr = self.alignment.forward(ideal_capacity_end_vaddr);
183 // Set up the metadata to be updated, after errors are no longer possible.
184 atom_placement = last_atom.ref();
185 break :blk @intCast(new_start_vaddr);
186 } else {
187 break :blk 0;
188 }
189 };
190
191 log.debug("allocated atom({}) : '{s}' at 0x{x} to 0x{x}", .{
192 self.ref(),
193 self.name(elf_file),
194 self.address(elf_file),
195 self.address(elf_file) + @as(i64, @intCast(self.size)),
196 });
197
198 const expand_section = if (atom_placement) |placement_ref|
199 elf_file.atom(placement_ref).?.nextAtom(elf_file) == null
200 else
201 true;
202 if (expand_section) {
203 const needed_size: u64 = @intCast(self.value + @as(i64, @intCast(self.size)));
204 try elf_file.growAllocSection(self.output_section_index, needed_size);
205 last_atom_ref.* = self.ref();
206
207 switch (self.file(elf_file).?) {
208 .zig_object => |zo| if (zo.dwarf) |_| {
209 // The .debug_info section has `low_pc` and `high_pc` values which is the virtual address
210 // range of the compilation unit. When we expand the text section, this range changes,
211 // so the DW_TAG.compile_unit tag of the .debug_info section becomes dirty.
212 zo.debug_info_section_dirty = true;
213 // This becomes dirty for the same reason. We could potentially make this more
214 // fine-grained with the addition of support for more compilation units. It is planned to
215 // model each package as a different compilation unit.
216 zo.debug_aranges_section_dirty = true;
217 zo.debug_rnglists_section_dirty = true;
218 },
219 else => {},
220 }
221 }
222 shdr.sh_addralign = @max(shdr.sh_addralign, self.alignment.toByteUnits().?);
223
224 // This function can also reallocate an atom.
225 // In this case we need to "unplug" it from its previous location before
226 // plugging it in to its new location.
227 if (self.prevAtom(elf_file)) |prev| {
228 prev.next_atom_ref = self.next_atom_ref;
229 }
230 if (self.nextAtom(elf_file)) |next| {
231 next.prev_atom_ref = self.prev_atom_ref;
232 }
233
234 if (atom_placement) |big_atom_ref| {
235 const big_atom = elf_file.atom(big_atom_ref).?;
236 self.prev_atom_ref = big_atom_ref;
237 self.next_atom_ref = big_atom.next_atom_ref;
238 big_atom.next_atom_ref = self.ref();
239 } else {
240 self.prev_atom_ref = .{ .index = 0, .file = 0 };
241 self.next_atom_ref = .{ .index = 0, .file = 0 };
242 }
243 if (free_list_removal) |i| {
244 _ = free_list.swapRemove(i);
245 }
246
247 self.alive = true;
248}
249
250pub fn shrink(self: *Atom, elf_file: *Elf) void {
251 _ = self;
252 _ = elf_file;
253}
254
255pub fn grow(self: *Atom, elf_file: *Elf) !void {
256 if (!self.alignment.check(@intCast(self.value)) or self.size > self.capacity(elf_file))
257 try self.allocate(elf_file);
258}
259
260131pub fn free(self: *Atom, elf_file: *Elf) void {
261132 log.debug("freeAtom atom({}) ({s})", .{ self.ref(), self.name(elf_file) });
262133
......@@ -1807,7 +1678,7 @@ const aarch64 = struct {
18071678 => {
18081679 // TODO: NC means no overflow check
18091680 const taddr = @as(u64, @intCast(S + A));
1810 const offset: u12 = switch (r_type) {
1681 const off: u12 = switch (r_type) {
18111682 .LDST8_ABS_LO12_NC => @truncate(taddr),
18121683 .LDST16_ABS_LO12_NC => @divExact(@as(u12, @truncate(taddr)), 2),
18131684 .LDST32_ABS_LO12_NC => @divExact(@as(u12, @truncate(taddr)), 4),
......@@ -1815,7 +1686,7 @@ const aarch64 = struct {
18151686 .LDST128_ABS_LO12_NC => @divExact(@as(u12, @truncate(taddr)), 16),
18161687 else => unreachable,
18171688 };
1818 aarch64_util.writeLoadStoreRegInst(offset, code);
1689 aarch64_util.writeLoadStoreRegInst(off, code);
18191690 },
18201691
18211692 .TLSLE_ADD_TPREL_HI12 => {
......@@ -1839,8 +1710,8 @@ const aarch64 = struct {
18391710 .TLSIE_LD64_GOTTPREL_LO12_NC => {
18401711 const S_ = target.gotTpAddress(elf_file);
18411712 relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });
1842 const offset: u12 = try math.divExact(u12, @truncate(@as(u64, @bitCast(S_ + A))), 8);
1843 aarch64_util.writeLoadStoreRegInst(offset, code);
1713 const off: u12 = try math.divExact(u12, @truncate(@as(u64, @bitCast(S_ + A))), 8);
1714 aarch64_util.writeLoadStoreRegInst(off, code);
18441715 },
18451716
18461717 .TLSGD_ADR_PAGE21 => {
......@@ -1853,8 +1724,8 @@ const aarch64 = struct {
18531724 .TLSGD_ADD_LO12_NC => {
18541725 const S_ = target.tlsGdAddress(elf_file);
18551726 relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });
1856 const offset: u12 = @truncate(@as(u64, @bitCast(S_ + A)));
1857 aarch64_util.writeAddImmInst(offset, code);
1727 const off: u12 = @truncate(@as(u64, @bitCast(S_ + A)));
1728 aarch64_util.writeAddImmInst(off, code);
18581729 },
18591730
18601731 .TLSDESC_ADR_PAGE21 => {
......@@ -1873,8 +1744,8 @@ const aarch64 = struct {
18731744 if (target.flags.has_tlsdesc) {
18741745 const S_ = target.tlsDescAddress(elf_file);
18751746 relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });
1876 const offset: u12 = try math.divExact(u12, @truncate(@as(u64, @bitCast(S_ + A))), 8);
1877 aarch64_util.writeLoadStoreRegInst(offset, code);
1747 const off: u12 = try math.divExact(u12, @truncate(@as(u64, @bitCast(S_ + A))), 8);
1748 aarch64_util.writeLoadStoreRegInst(off, code);
18781749 } else {
18791750 relocs_log.debug(" relaxing ldr => nop", .{});
18801751 mem.writeInt(u32, code, Instruction.nop().toU32(), .little);
......@@ -1885,8 +1756,8 @@ const aarch64 = struct {
18851756 if (target.flags.has_tlsdesc) {
18861757 const S_ = target.tlsDescAddress(elf_file);
18871758 relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });
1888 const offset: u12 = @truncate(@as(u64, @bitCast(S_ + A)));
1889 aarch64_util.writeAddImmInst(offset, code);
1759 const off: u12 = @truncate(@as(u64, @bitCast(S_ + A)));
1760 aarch64_util.writeAddImmInst(off, code);
18901761 } else {
18911762 const old_inst = Instruction{
18921763 .add_subtract_immediate = mem.bytesToValue(std.meta.TagPayload(
src/link/Elf/AtomList.zig created+208
......@@ -0,0 +1,208 @@
1value: i64 = 0,
2size: u64 = 0,
3alignment: Atom.Alignment = .@"1",
4output_section_index: u32 = 0,
5atoms: std.ArrayListUnmanaged(Elf.Ref) = .{},
6
7pub fn deinit(list: *AtomList, allocator: Allocator) void {
8 list.atoms.deinit(allocator);
9}
10
11pub fn address(list: AtomList, elf_file: *Elf) i64 {
12 const shdr = elf_file.sections.items(.shdr)[list.output_section_index];
13 return @as(i64, @intCast(shdr.sh_addr)) + list.value;
14}
15
16pub fn offset(list: AtomList, elf_file: *Elf) u64 {
17 const shdr = elf_file.sections.items(.shdr)[list.output_section_index];
18 return shdr.sh_offset + @as(u64, @intCast(list.value));
19}
20
21pub fn updateSize(list: *AtomList, elf_file: *Elf) void {
22 for (list.atoms.items) |ref| {
23 const atom_ptr = elf_file.atom(ref).?;
24 assert(atom_ptr.alive);
25 const off = atom_ptr.alignment.forward(list.size);
26 const padding = off - list.size;
27 atom_ptr.value = @intCast(off);
28 list.size += padding + atom_ptr.size;
29 list.alignment = list.alignment.max(atom_ptr.alignment);
30 }
31}
32
33pub fn allocate(list: *AtomList, elf_file: *Elf) !void {
34 const alloc_res = try elf_file.allocateChunk(.{
35 .shndx = list.output_section_index,
36 .size = list.size,
37 .alignment = list.alignment,
38 .requires_padding = false,
39 });
40 list.value = @intCast(alloc_res.value);
41
42 const slice = elf_file.sections.slice();
43 const shdr = &slice.items(.shdr)[list.output_section_index];
44 const last_atom_ref = &slice.items(.last_atom)[list.output_section_index];
45
46 const expand_section = if (elf_file.atom(alloc_res.placement)) |placement_atom|
47 placement_atom.nextAtom(elf_file) == null
48 else
49 true;
50 if (expand_section) last_atom_ref.* = list.lastAtom(elf_file).ref();
51 shdr.sh_addralign = @max(shdr.sh_addralign, list.alignment.toByteUnits().?);
52
53 // FIXME:JK this currently ignores Thunks as valid chunks.
54 {
55 var idx: usize = 0;
56 while (idx < list.atoms.items.len) : (idx += 1) {
57 const curr_atom_ptr = elf_file.atom(list.atoms.items[idx]).?;
58 if (idx > 0) {
59 curr_atom_ptr.prev_atom_ref = list.atoms.items[idx - 1];
60 }
61 if (idx + 1 < list.atoms.items.len) {
62 curr_atom_ptr.next_atom_ref = list.atoms.items[idx + 1];
63 }
64 }
65 }
66
67 if (elf_file.atom(alloc_res.placement)) |placement_atom| {
68 list.firstAtom(elf_file).prev_atom_ref = placement_atom.ref();
69 list.lastAtom(elf_file).next_atom_ref = placement_atom.next_atom_ref;
70 placement_atom.next_atom_ref = list.firstAtom(elf_file).ref();
71 }
72
73 // FIXME:JK if we had a link from Atom to parent AtomList we would not need to update Atom's value or osec index
74 for (list.atoms.items) |ref| {
75 const atom_ptr = elf_file.atom(ref).?;
76 atom_ptr.output_section_index = list.output_section_index;
77 atom_ptr.value += list.value;
78 }
79}
80
81pub fn write(list: AtomList, buffer: *std.ArrayList(u8), undefs: anytype, elf_file: *Elf) !void {
82 const gpa = elf_file.base.comp.gpa;
83 const osec = elf_file.sections.items(.shdr)[list.output_section_index];
84 assert(osec.sh_type != elf.SHT_NOBITS);
85
86 log.debug("writing atoms in section '{s}'", .{elf_file.getShString(osec.sh_name)});
87
88 const list_size = math.cast(usize, list.size) orelse return error.Overflow;
89 try buffer.ensureUnusedCapacity(list_size);
90 buffer.appendNTimesAssumeCapacity(0, list_size);
91
92 for (list.atoms.items) |ref| {
93 const atom_ptr = elf_file.atom(ref).?;
94 assert(atom_ptr.alive);
95
96 const off = math.cast(usize, atom_ptr.value - list.value) orelse return error.Overflow;
97 const size = math.cast(usize, atom_ptr.size) orelse return error.Overflow;
98
99 log.debug(" atom({}) at 0x{x}", .{ ref, list.offset(elf_file) + off });
100
101 const object = atom_ptr.file(elf_file).?.object;
102 const code = try object.codeDecompressAlloc(elf_file, ref.index);
103 defer gpa.free(code);
104 const out_code = buffer.items[off..][0..size];
105 @memcpy(out_code, code);
106
107 if (osec.sh_flags & elf.SHF_ALLOC == 0)
108 try atom_ptr.resolveRelocsNonAlloc(elf_file, out_code, undefs)
109 else
110 try atom_ptr.resolveRelocsAlloc(elf_file, out_code);
111 }
112
113 try elf_file.base.file.?.pwriteAll(buffer.items, list.offset(elf_file));
114 buffer.clearRetainingCapacity();
115}
116
117pub fn writeRelocatable(list: AtomList, buffer: *std.ArrayList(u8), elf_file: *Elf) !void {
118 const gpa = elf_file.base.comp.gpa;
119 const osec = elf_file.sections.items(.shdr)[list.output_section_index];
120 assert(osec.sh_type != elf.SHT_NOBITS);
121
122 log.debug("writing atoms in section '{s}'", .{elf_file.getShString(osec.sh_name)});
123
124 const list_size = math.cast(usize, list.size) orelse return error.Overflow;
125 try buffer.ensureUnusedCapacity(list_size);
126 buffer.appendNTimesAssumeCapacity(0, list_size);
127
128 for (list.atoms.items) |ref| {
129 const atom_ptr = elf_file.atom(ref).?;
130 assert(atom_ptr.alive);
131
132 const off = math.cast(usize, atom_ptr.value - list.value) orelse return error.Overflow;
133 const size = math.cast(usize, atom_ptr.size) orelse return error.Overflow;
134
135 log.debug(" atom({}) at 0x{x}", .{ ref, list.offset(elf_file) + off });
136
137 const object = atom_ptr.file(elf_file).?.object;
138 const code = try object.codeDecompressAlloc(elf_file, ref.index);
139 defer gpa.free(code);
140 const out_code = buffer.items[off..][0..size];
141 @memcpy(out_code, code);
142 }
143
144 try elf_file.base.file.?.pwriteAll(buffer.items, list.offset(elf_file));
145 buffer.clearRetainingCapacity();
146}
147
148pub fn firstAtom(list: AtomList, elf_file: *Elf) *Atom {
149 assert(list.atoms.items.len > 0);
150 return elf_file.atom(list.atoms.items[0]).?;
151}
152
153pub fn lastAtom(list: AtomList, elf_file: *Elf) *Atom {
154 assert(list.atoms.items.len > 0);
155 return elf_file.atom(list.atoms.items[list.atoms.items.len - 1]).?;
156}
157
158pub fn format(
159 list: AtomList,
160 comptime unused_fmt_string: []const u8,
161 options: std.fmt.FormatOptions,
162 writer: anytype,
163) !void {
164 _ = list;
165 _ = unused_fmt_string;
166 _ = options;
167 _ = writer;
168 @compileError("do not format AtomList directly");
169}
170
171const FormatCtx = struct { AtomList, *Elf };
172
173pub fn fmt(list: AtomList, elf_file: *Elf) std.fmt.Formatter(format2) {
174 return .{ .data = .{ list, elf_file } };
175}
176
177fn format2(
178 ctx: FormatCtx,
179 comptime unused_fmt_string: []const u8,
180 options: std.fmt.FormatOptions,
181 writer: anytype,
182) !void {
183 _ = unused_fmt_string;
184 _ = options;
185 const list, const elf_file = ctx;
186 try writer.print("list : @{x} : shdr({d}) : align({x}) : size({x})", .{
187 list.address(elf_file), list.output_section_index,
188 list.alignment.toByteUnits() orelse 0, list.size,
189 });
190 try writer.writeAll(" : atoms{ ");
191 for (list.atoms.items, 0..) |ref, i| {
192 try writer.print("{}", .{ref});
193 if (i < list.atoms.items.len - 1) try writer.writeAll(", ");
194 }
195 try writer.writeAll(" }");
196}
197
198const assert = std.debug.assert;
199const elf = std.elf;
200const log = std.log.scoped(.link);
201const math = std.math;
202const std = @import("std");
203
204const Allocator = std.mem.Allocator;
205const Atom = @import("Atom.zig");
206const AtomList = @This();
207const Elf = @import("../Elf.zig");
208const Object = @import("Object.zig");
src/link/Elf/Object.zig+42-81
......@@ -311,58 +311,6 @@ fn initAtoms(self: *Object, allocator: Allocator, handle: std.fs.File, elf_file:
311311 };
312312}
313313
314fn initOutputSection(self: Object, elf_file: *Elf, shdr: elf.Elf64_Shdr) error{OutOfMemory}!u32 {
315 const name = blk: {
316 const name = self.getString(shdr.sh_name);
317 if (elf_file.base.isRelocatable()) break :blk name;
318 if (shdr.sh_flags & elf.SHF_MERGE != 0) break :blk name;
319 const sh_name_prefixes: []const [:0]const u8 = &.{
320 ".text", ".data.rel.ro", ".data", ".rodata", ".bss.rel.ro", ".bss",
321 ".init_array", ".fini_array", ".tbss", ".tdata", ".gcc_except_table", ".ctors",
322 ".dtors", ".gnu.warning",
323 };
324 inline for (sh_name_prefixes) |prefix| {
325 if (std.mem.eql(u8, name, prefix) or std.mem.startsWith(u8, name, prefix ++ ".")) {
326 break :blk prefix;
327 }
328 }
329 break :blk name;
330 };
331 const @"type" = tt: {
332 if (elf_file.getTarget().cpu.arch == .x86_64 and
333 shdr.sh_type == elf.SHT_X86_64_UNWIND) break :tt elf.SHT_PROGBITS;
334
335 const @"type" = switch (shdr.sh_type) {
336 elf.SHT_NULL => unreachable,
337 elf.SHT_PROGBITS => blk: {
338 if (std.mem.eql(u8, name, ".init_array") or std.mem.startsWith(u8, name, ".init_array."))
339 break :blk elf.SHT_INIT_ARRAY;
340 if (std.mem.eql(u8, name, ".fini_array") or std.mem.startsWith(u8, name, ".fini_array."))
341 break :blk elf.SHT_FINI_ARRAY;
342 break :blk shdr.sh_type;
343 },
344 else => shdr.sh_type,
345 };
346 break :tt @"type";
347 };
348 const flags = blk: {
349 var flags = shdr.sh_flags;
350 if (!elf_file.base.isRelocatable()) {
351 flags &= ~@as(u64, elf.SHF_COMPRESSED | elf.SHF_GROUP | elf.SHF_GNU_RETAIN);
352 }
353 break :blk switch (@"type") {
354 elf.SHT_INIT_ARRAY, elf.SHT_FINI_ARRAY => flags | elf.SHF_WRITE,
355 else => flags,
356 };
357 };
358 const out_shndx = elf_file.sectionByName(name) orelse try elf_file.addSection(.{
359 .type = @"type",
360 .flags = flags,
361 .name = try elf_file.insertShString(name),
362 });
363 return out_shndx;
364}
365
366314fn skipShdr(self: *Object, index: u32, elf_file: *Elf) bool {
367315 const comp = elf_file.base.comp;
368316 const shdr = self.shdrs.items[index];
......@@ -438,15 +386,24 @@ fn parseEhFrame(self: *Object, allocator: Allocator, handle: std.fs.File, shndx:
438386 .input_section_index = shndx,
439387 .file_index = self.index,
440388 }),
441 .fde => try self.fdes.append(allocator, .{
442 .offset = data_start + rec.offset,
443 .size = rec.size,
444 .cie_index = undefined,
445 .rel_index = rel_start + @as(u32, @intCast(rel_range.start)),
446 .rel_num = @as(u32, @intCast(rel_range.len)),
447 .input_section_index = shndx,
448 .file_index = self.index,
449 }),
389 .fde => {
390 if (rel_range.len == 0) {
391 // No relocs for an FDE means we cannot associate this FDE to an Atom
392 // so we skip it. According to mold source code
393 // (https://github.com/rui314/mold/blob/a3e69502b0eaf1126d6093e8ea5e6fdb95219811/src/input-files.cc#L525-L528)
394 // this can happen for object files built with -r flag by the linker.
395 continue;
396 }
397 try self.fdes.append(allocator, .{
398 .offset = data_start + rec.offset,
399 .size = rec.size,
400 .cie_index = undefined,
401 .rel_index = rel_start + @as(u32, @intCast(rel_range.start)),
402 .rel_num = @as(u32, @intCast(rel_range.len)),
403 .input_section_index = shndx,
404 .file_index = self.index,
405 });
406 },
450407 }
451408 }
452409
......@@ -622,7 +579,7 @@ pub fn claimUnresolved(self: *Object, elf_file: *Elf) void {
622579 }
623580}
624581
625pub fn claimUnresolvedObject(self: *Object, elf_file: *Elf) void {
582pub fn claimUnresolvedRelocatable(self: *Object, elf_file: *Elf) void {
626583 const first_global = self.first_global orelse return;
627584 for (self.globals(), 0..) |*sym, i| {
628585 const esym_index = @as(u32, @intCast(first_global + i));
......@@ -985,21 +942,14 @@ pub fn initOutputSections(self: *Object, elf_file: *Elf) !void {
985942 const atom_ptr = self.atom(atom_index) orelse continue;
986943 if (!atom_ptr.alive) continue;
987944 const shdr = atom_ptr.inputShdr(elf_file);
988 _ = try self.initOutputSection(elf_file, shdr);
989 }
990}
991
992pub fn addAtomsToOutputSections(self: *Object, elf_file: *Elf) !void {
993 for (self.atoms_indexes.items) |atom_index| {
994 const atom_ptr = self.atom(atom_index) orelse continue;
995 if (!atom_ptr.alive) continue;
996 const shdr = atom_ptr.inputShdr(elf_file);
997 atom_ptr.output_section_index = self.initOutputSection(elf_file, shdr) catch unreachable;
998
999 const comp = elf_file.base.comp;
1000 const gpa = comp.gpa;
1001 const atom_list = &elf_file.sections.items(.atom_list)[atom_ptr.output_section_index];
1002 try atom_list.append(gpa, .{ .index = atom_index, .file = self.index });
945 const osec = try elf_file.initOutputSection(.{
946 .name = self.getString(shdr.sh_name),
947 .flags = shdr.sh_flags,
948 .type = shdr.sh_type,
949 });
950 const atom_list = &elf_file.sections.items(.atom_list_2)[osec];
951 atom_list.output_section_index = osec;
952 try atom_list.atoms.append(elf_file.base.comp.gpa, atom_ptr.ref());
1003953 }
1004954}
1005955
......@@ -1007,9 +957,14 @@ pub fn initRelaSections(self: *Object, elf_file: *Elf) !void {
1007957 for (self.atoms_indexes.items) |atom_index| {
1008958 const atom_ptr = self.atom(atom_index) orelse continue;
1009959 if (!atom_ptr.alive) continue;
960 if (atom_ptr.output_section_index == elf_file.eh_frame_section_index) continue;
1010961 const shndx = atom_ptr.relocsShndx() orelse continue;
1011962 const shdr = self.shdrs.items[shndx];
1012 const out_shndx = try self.initOutputSection(elf_file, shdr);
963 const out_shndx = try elf_file.initOutputSection(.{
964 .name = self.getString(shdr.sh_name),
965 .flags = shdr.sh_flags,
966 .type = shdr.sh_type,
967 });
1013968 const out_shdr = &elf_file.sections.items(.shdr)[out_shndx];
1014969 out_shdr.sh_type = elf.SHT_RELA;
1015970 out_shdr.sh_addralign = @alignOf(elf.Elf64_Rela);
......@@ -1022,10 +977,15 @@ pub fn addAtomsToRelaSections(self: *Object, elf_file: *Elf) !void {
1022977 for (self.atoms_indexes.items) |atom_index| {
1023978 const atom_ptr = self.atom(atom_index) orelse continue;
1024979 if (!atom_ptr.alive) continue;
980 if (atom_ptr.output_section_index == elf_file.eh_frame_section_index) continue;
1025981 const shndx = blk: {
1026982 const shndx = atom_ptr.relocsShndx() orelse continue;
1027983 const shdr = self.shdrs.items[shndx];
1028 break :blk self.initOutputSection(elf_file, shdr) catch unreachable;
984 break :blk elf_file.initOutputSection(.{
985 .name = self.getString(shdr.sh_name),
986 .flags = shdr.sh_flags,
987 .type = shdr.sh_type,
988 }) catch unreachable;
1029989 };
1030990 const slice = elf_file.sections.slice();
1031991 const shdr = &slice.items(.shdr)[shndx];
......@@ -1538,12 +1498,12 @@ fn formatComdatGroups(
15381498 }
15391499}
15401500
1541pub fn fmtPath(self: *Object) std.fmt.Formatter(formatPath) {
1501pub fn fmtPath(self: Object) std.fmt.Formatter(formatPath) {
15421502 return .{ .data = self };
15431503}
15441504
15451505fn formatPath(
1546 object: *Object,
1506 object: Object,
15471507 comptime unused_fmt_string: []const u8,
15481508 options: std.fmt.FormatOptions,
15491509 writer: anytype,
......@@ -1578,6 +1538,7 @@ const mem = std.mem;
15781538const Allocator = mem.Allocator;
15791539const Archive = @import("Archive.zig");
15801540const Atom = @import("Atom.zig");
1541const AtomList = @import("AtomList.zig");
15811542const Cie = eh_frame.Cie;
15821543const Elf = @import("../Elf.zig");
15831544const Fde = eh_frame.Fde;
src/link/Elf/ZigObject.zig+358-287
......@@ -51,6 +51,14 @@ debug_loclists_section_dirty: bool = false,
5151debug_rnglists_section_dirty: bool = false,
5252eh_frame_section_dirty: bool = false,
5353
54text_index: ?Symbol.Index = null,
55rodata_index: ?Symbol.Index = null,
56data_relro_index: ?Symbol.Index = null,
57data_index: ?Symbol.Index = null,
58bss_index: ?Symbol.Index = null,
59tdata_index: ?Symbol.Index = null,
60tbss_index: ?Symbol.Index = null,
61eh_frame_index: ?Symbol.Index = null,
5462debug_info_index: ?Symbol.Index = null,
5563debug_abbrev_index: ?Symbol.Index = null,
5664debug_aranges_index: ?Symbol.Index = null,
......@@ -59,7 +67,6 @@ debug_line_index: ?Symbol.Index = null,
5967debug_line_str_index: ?Symbol.Index = null,
6068debug_loclists_index: ?Symbol.Index = null,
6169debug_rnglists_index: ?Symbol.Index = null,
62eh_frame_index: ?Symbol.Index = null,
6370
6471pub const global_symbol_bit: u32 = 0x80000000;
6572pub const symbol_mask: u32 = 0x7fffffff;
......@@ -71,6 +78,7 @@ const InitOptions = struct {
7178};
7279
7380pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {
81 _ = options;
7482 const comp = elf_file.base.comp;
7583 const gpa = comp.gpa;
7684 const ptr_size = elf_file.ptrWidthBytes();
......@@ -88,190 +96,13 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {
8896 esym.st_shndx = elf.SHN_ABS;
8997 }
9098
91 const fillSection = struct {
92 fn fillSection(ef: *Elf, shdr: *elf.Elf64_Shdr, size: u64, phndx: ?u16) !void {
93 if (ef.base.isRelocatable()) {
94 const off = try ef.findFreeSpace(size, shdr.sh_addralign);
95 shdr.sh_offset = off;
96 shdr.sh_size = size;
97 } else {
98 const phdr = ef.phdrs.items[phndx.?];
99 shdr.sh_addr = phdr.p_vaddr;
100 shdr.sh_offset = phdr.p_offset;
101 shdr.sh_size = phdr.p_memsz;
102 }
103 }
104 }.fillSection;
105
106 comptime assert(Elf.number_of_zig_segments == 4);
107
108 if (!elf_file.base.isRelocatable()) {
109 if (elf_file.phdr_zig_load_re_index == null) {
110 const filesz = options.program_code_size_hint;
111 const off = try elf_file.findFreeSpace(filesz, elf_file.page_size);
112 elf_file.phdr_zig_load_re_index = try elf_file.addPhdr(.{
113 .type = elf.PT_LOAD,
114 .offset = off,
115 .filesz = filesz,
116 .addr = if (ptr_size >= 4) 0x4000000 else 0x4000,
117 .memsz = filesz,
118 .@"align" = elf_file.page_size,
119 .flags = elf.PF_X | elf.PF_R | elf.PF_W,
120 });
121 }
122
123 if (elf_file.phdr_zig_load_ro_index == null) {
124 const alignment = elf_file.page_size;
125 const filesz: u64 = 1024;
126 const off = try elf_file.findFreeSpace(filesz, alignment);
127 elf_file.phdr_zig_load_ro_index = try elf_file.addPhdr(.{
128 .type = elf.PT_LOAD,
129 .offset = off,
130 .filesz = filesz,
131 .addr = if (ptr_size >= 4) 0xc000000 else 0xa000,
132 .memsz = filesz,
133 .@"align" = alignment,
134 .flags = elf.PF_R | elf.PF_W,
135 });
136 }
137
138 if (elf_file.phdr_zig_load_rw_index == null) {
139 const alignment = elf_file.page_size;
140 const filesz: u64 = 1024;
141 const off = try elf_file.findFreeSpace(filesz, alignment);
142 elf_file.phdr_zig_load_rw_index = try elf_file.addPhdr(.{
143 .type = elf.PT_LOAD,
144 .offset = off,
145 .filesz = filesz,
146 .addr = if (ptr_size >= 4) 0x10000000 else 0xc000,
147 .memsz = filesz,
148 .@"align" = alignment,
149 .flags = elf.PF_R | elf.PF_W,
150 });
151 }
152
153 if (elf_file.phdr_zig_load_zerofill_index == null) {
154 const alignment = elf_file.page_size;
155 elf_file.phdr_zig_load_zerofill_index = try elf_file.addPhdr(.{
156 .type = elf.PT_LOAD,
157 .addr = if (ptr_size >= 4) 0x14000000 else 0xf000,
158 .memsz = 1024,
159 .@"align" = alignment,
160 .flags = elf.PF_R | elf.PF_W,
161 });
162 }
163 }
164
165 if (elf_file.zig_text_section_index == null) {
166 elf_file.zig_text_section_index = try elf_file.addSection(.{
167 .name = try elf_file.insertShString(".text.zig"),
168 .type = elf.SHT_PROGBITS,
169 .flags = elf.SHF_ALLOC | elf.SHF_EXECINSTR,
170 .addralign = 1,
171 .offset = std.math.maxInt(u64),
172 });
173 const shdr = &elf_file.sections.items(.shdr)[elf_file.zig_text_section_index.?];
174 const phndx = &elf_file.sections.items(.phndx)[elf_file.zig_text_section_index.?];
175 try fillSection(elf_file, shdr, options.program_code_size_hint, elf_file.phdr_zig_load_re_index);
176 if (elf_file.base.isRelocatable()) {
177 _ = try elf_file.addRelaShdr(
178 try elf_file.insertShString(".rela.text.zig"),
179 elf_file.zig_text_section_index.?,
180 );
181 } else {
182 phndx.* = elf_file.phdr_zig_load_re_index.?;
183 }
184 }
185
186 if (elf_file.zig_data_rel_ro_section_index == null) {
187 elf_file.zig_data_rel_ro_section_index = try elf_file.addSection(.{
188 .name = try elf_file.insertShString(".data.rel.ro.zig"),
189 .type = elf.SHT_PROGBITS,
190 .addralign = 1,
191 .flags = elf.SHF_ALLOC | elf.SHF_WRITE,
192 .offset = std.math.maxInt(u64),
193 });
194 const shdr = &elf_file.sections.items(.shdr)[elf_file.zig_data_rel_ro_section_index.?];
195 const phndx = &elf_file.sections.items(.phndx)[elf_file.zig_data_rel_ro_section_index.?];
196 try fillSection(elf_file, shdr, 1024, elf_file.phdr_zig_load_ro_index);
197 if (elf_file.base.isRelocatable()) {
198 _ = try elf_file.addRelaShdr(
199 try elf_file.insertShString(".rela.data.rel.ro.zig"),
200 elf_file.zig_data_rel_ro_section_index.?,
201 );
202 } else {
203 phndx.* = elf_file.phdr_zig_load_ro_index.?;
204 }
205 }
206
207 if (elf_file.zig_data_section_index == null) {
208 elf_file.zig_data_section_index = try elf_file.addSection(.{
209 .name = try elf_file.insertShString(".data.zig"),
210 .type = elf.SHT_PROGBITS,
211 .addralign = ptr_size,
212 .flags = elf.SHF_ALLOC | elf.SHF_WRITE,
213 .offset = std.math.maxInt(u64),
214 });
215 const shdr = &elf_file.sections.items(.shdr)[elf_file.zig_data_section_index.?];
216 const phndx = &elf_file.sections.items(.phndx)[elf_file.zig_data_section_index.?];
217 try fillSection(elf_file, shdr, 1024, elf_file.phdr_zig_load_rw_index);
218 if (elf_file.base.isRelocatable()) {
219 _ = try elf_file.addRelaShdr(
220 try elf_file.insertShString(".rela.data.zig"),
221 elf_file.zig_data_section_index.?,
222 );
223 } else {
224 phndx.* = elf_file.phdr_zig_load_rw_index.?;
225 }
226 }
227
228 if (elf_file.zig_bss_section_index == null) {
229 elf_file.zig_bss_section_index = try elf_file.addSection(.{
230 .name = try elf_file.insertShString(".bss.zig"),
231 .type = elf.SHT_NOBITS,
232 .addralign = ptr_size,
233 .flags = elf.SHF_ALLOC | elf.SHF_WRITE,
234 .offset = 0,
235 });
236 const shdr = &elf_file.sections.items(.shdr)[elf_file.zig_bss_section_index.?];
237 const phndx = &elf_file.sections.items(.phndx)[elf_file.zig_bss_section_index.?];
238 if (elf_file.base.isRelocatable()) {
239 shdr.sh_size = 1024;
240 } else {
241 phndx.* = elf_file.phdr_zig_load_zerofill_index.?;
242 const phdr = elf_file.phdrs.items[phndx.*.?];
243 shdr.sh_addr = phdr.p_vaddr;
244 shdr.sh_size = phdr.p_memsz;
245 }
246 }
247
24899 switch (comp.config.debug_format) {
249100 .strip => {},
250101 .dwarf => |v| {
251102 var dwarf = Dwarf.init(&elf_file.base, v);
252103
253 const addSectionSymbol = struct {
254 fn addSectionSymbol(
255 zig_object: *ZigObject,
256 alloc: Allocator,
257 name: [:0]const u8,
258 alignment: Atom.Alignment,
259 shndx: u32,
260 ) !Symbol.Index {
261 const name_off = try zig_object.addString(alloc, name);
262 const index = try zig_object.newSymbolWithAtom(alloc, name_off);
263 const sym = zig_object.symbol(index);
264 const esym = &zig_object.symtab.items(.elf_sym)[sym.esym_index];
265 esym.st_info |= elf.STT_SECTION;
266 const atom_ptr = zig_object.atom(sym.ref.index).?;
267 atom_ptr.alignment = alignment;
268 atom_ptr.output_section_index = shndx;
269 return index;
270 }
271 }.addSectionSymbol;
272
273 if (elf_file.debug_str_section_index == null) {
274 elf_file.debug_str_section_index = try elf_file.addSection(.{
104 if (self.debug_str_index == null) {
105 const osec = try elf_file.addSection(.{
275106 .name = try elf_file.insertShString(".debug_str"),
276107 .flags = elf.SHF_MERGE | elf.SHF_STRINGS,
277108 .entsize = 1,
......@@ -279,51 +110,56 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {
279110 .addralign = 1,
280111 });
281112 self.debug_str_section_dirty = true;
282 self.debug_str_index = try addSectionSymbol(self, gpa, ".debug_str", .@"1", elf_file.debug_str_section_index.?);
113 self.debug_str_index = try self.addSectionSymbol(gpa, ".debug_str", .@"1", osec);
114 elf_file.sections.items(.last_atom)[osec] = self.symbol(self.debug_str_index.?).ref;
283115 }
284116
285 if (elf_file.debug_info_section_index == null) {
286 elf_file.debug_info_section_index = try elf_file.addSection(.{
117 if (self.debug_info_index == null) {
118 const osec = try elf_file.addSection(.{
287119 .name = try elf_file.insertShString(".debug_info"),
288120 .type = elf.SHT_PROGBITS,
289121 .addralign = 1,
290122 });
291123 self.debug_info_section_dirty = true;
292 self.debug_info_index = try addSectionSymbol(self, gpa, ".debug_info", .@"1", elf_file.debug_info_section_index.?);
124 self.debug_info_index = try self.addSectionSymbol(gpa, ".debug_info", .@"1", osec);
125 elf_file.sections.items(.last_atom)[osec] = self.symbol(self.debug_info_index.?).ref;
293126 }
294127
295 if (elf_file.debug_abbrev_section_index == null) {
296 elf_file.debug_abbrev_section_index = try elf_file.addSection(.{
128 if (self.debug_abbrev_index == null) {
129 const osec = try elf_file.addSection(.{
297130 .name = try elf_file.insertShString(".debug_abbrev"),
298131 .type = elf.SHT_PROGBITS,
299132 .addralign = 1,
300133 });
301134 self.debug_abbrev_section_dirty = true;
302 self.debug_abbrev_index = try addSectionSymbol(self, gpa, ".debug_abbrev", .@"1", elf_file.debug_abbrev_section_index.?);
135 self.debug_abbrev_index = try self.addSectionSymbol(gpa, ".debug_abbrev", .@"1", osec);
136 elf_file.sections.items(.last_atom)[osec] = self.symbol(self.debug_abbrev_index.?).ref;
303137 }
304138
305 if (elf_file.debug_aranges_section_index == null) {
306 elf_file.debug_aranges_section_index = try elf_file.addSection(.{
139 if (self.debug_aranges_index == null) {
140 const osec = try elf_file.addSection(.{
307141 .name = try elf_file.insertShString(".debug_aranges"),
308142 .type = elf.SHT_PROGBITS,
309143 .addralign = 16,
310144 });
311145 self.debug_aranges_section_dirty = true;
312 self.debug_aranges_index = try addSectionSymbol(self, gpa, ".debug_aranges", .@"16", elf_file.debug_aranges_section_index.?);
146 self.debug_aranges_index = try self.addSectionSymbol(gpa, ".debug_aranges", .@"16", osec);
147 elf_file.sections.items(.last_atom)[osec] = self.symbol(self.debug_aranges_index.?).ref;
313148 }
314149
315 if (elf_file.debug_line_section_index == null) {
316 elf_file.debug_line_section_index = try elf_file.addSection(.{
150 if (self.debug_line_index == null) {
151 const osec = try elf_file.addSection(.{
317152 .name = try elf_file.insertShString(".debug_line"),
318153 .type = elf.SHT_PROGBITS,
319154 .addralign = 1,
320155 });
321156 self.debug_line_section_dirty = true;
322 self.debug_line_index = try addSectionSymbol(self, gpa, ".debug_line", .@"1", elf_file.debug_line_section_index.?);
157 self.debug_line_index = try self.addSectionSymbol(gpa, ".debug_line", .@"1", osec);
158 elf_file.sections.items(.last_atom)[osec] = self.symbol(self.debug_line_index.?).ref;
323159 }
324160
325 if (elf_file.debug_line_str_section_index == null) {
326 elf_file.debug_line_str_section_index = try elf_file.addSection(.{
161 if (self.debug_line_str_index == null) {
162 const osec = try elf_file.addSection(.{
327163 .name = try elf_file.insertShString(".debug_line_str"),
328164 .flags = elf.SHF_MERGE | elf.SHF_STRINGS,
329165 .entsize = 1,
......@@ -331,31 +167,34 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {
331167 .addralign = 1,
332168 });
333169 self.debug_line_str_section_dirty = true;
334 self.debug_line_str_index = try addSectionSymbol(self, gpa, ".debug_line_str", .@"1", elf_file.debug_line_str_section_index.?);
170 self.debug_line_str_index = try self.addSectionSymbol(gpa, ".debug_line_str", .@"1", osec);
171 elf_file.sections.items(.last_atom)[osec] = self.symbol(self.debug_line_str_index.?).ref;
335172 }
336173
337 if (elf_file.debug_loclists_section_index == null) {
338 elf_file.debug_loclists_section_index = try elf_file.addSection(.{
174 if (self.debug_loclists_index == null) {
175 const osec = try elf_file.addSection(.{
339176 .name = try elf_file.insertShString(".debug_loclists"),
340177 .type = elf.SHT_PROGBITS,
341178 .addralign = 1,
342179 });
343180 self.debug_loclists_section_dirty = true;
344 self.debug_loclists_index = try addSectionSymbol(self, gpa, ".debug_loclists", .@"1", elf_file.debug_loclists_section_index.?);
181 self.debug_loclists_index = try self.addSectionSymbol(gpa, ".debug_loclists", .@"1", osec);
182 elf_file.sections.items(.last_atom)[osec] = self.symbol(self.debug_loclists_index.?).ref;
345183 }
346184
347 if (elf_file.debug_rnglists_section_index == null) {
348 elf_file.debug_rnglists_section_index = try elf_file.addSection(.{
185 if (self.debug_rnglists_index == null) {
186 const osec = try elf_file.addSection(.{
349187 .name = try elf_file.insertShString(".debug_rnglists"),
350188 .type = elf.SHT_PROGBITS,
351189 .addralign = 1,
352190 });
353191 self.debug_rnglists_section_dirty = true;
354 self.debug_rnglists_index = try addSectionSymbol(self, gpa, ".debug_rnglists", .@"1", elf_file.debug_rnglists_section_index.?);
192 self.debug_rnglists_index = try self.addSectionSymbol(gpa, ".debug_rnglists", .@"1", osec);
193 elf_file.sections.items(.last_atom)[osec] = self.symbol(self.debug_rnglists_index.?).ref;
355194 }
356195
357 if (elf_file.eh_frame_section_index == null) {
358 elf_file.eh_frame_section_index = try elf_file.addSection(.{
196 if (self.eh_frame_index == null) {
197 const osec = try elf_file.addSection(.{
359198 .name = try elf_file.insertShString(".eh_frame"),
360199 .type = if (elf_file.getTarget().cpu.arch == .x86_64)
361200 elf.SHT_X86_64_UNWIND
......@@ -365,7 +204,8 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {
365204 .addralign = ptr_size,
366205 });
367206 self.eh_frame_section_dirty = true;
368 self.eh_frame_index = try addSectionSymbol(self, gpa, ".eh_frame", Atom.Alignment.fromNonzeroByteUnits(ptr_size), elf_file.eh_frame_section_index.?);
207 self.eh_frame_index = try self.addSectionSymbol(gpa, ".eh_frame", Atom.Alignment.fromNonzeroByteUnits(ptr_size), osec);
208 elf_file.sections.items(.last_atom)[osec] = self.symbol(self.eh_frame_index.?).ref;
369209 }
370210
371211 try dwarf.initMetadata();
......@@ -404,10 +244,6 @@ pub fn deinit(self: *ZigObject, allocator: Allocator) void {
404244 meta.exports.deinit(allocator);
405245 }
406246 self.uavs.deinit(allocator);
407
408 for (self.tls_variables.values()) |*tlv| {
409 tlv.deinit(allocator);
410 }
411247 self.tls_variables.deinit(allocator);
412248
413249 if (self.dwarf) |*dwarf| {
......@@ -499,12 +335,6 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi
499335 const sym = self.symbol(sym_index);
500336 const atom_ptr = self.atom(sym.ref.index).?;
501337 if (!atom_ptr.alive) continue;
502 const shndx = sym.outputShndx(elf_file).?;
503 const shdr = elf_file.sections.items(.shdr)[shndx];
504 const esym = &self.symtab.items(.elf_sym)[sym.esym_index];
505 esym.st_size = shdr.sh_size;
506 atom_ptr.size = shdr.sh_size;
507 atom_ptr.alignment = Atom.Alignment.fromNonzeroByteUnits(shdr.sh_addralign);
508338
509339 log.debug("parsing relocs in {s}", .{sym.name(elf_file)});
510340
......@@ -665,14 +495,6 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi
665495 }
666496 }
667497 }
668
669 if (elf_file.base.isRelocatable() and relocs.items.len > 0) {
670 const rela_sect_name = try std.fmt.allocPrintZ(gpa, ".rela{s}", .{elf_file.getShString(shdr.sh_name)});
671 defer gpa.free(rela_sect_name);
672 if (elf_file.sectionByName(rela_sect_name) == null) {
673 _ = try elf_file.addRelaShdr(try elf_file.insertShString(rela_sect_name), shndx);
674 }
675 }
676498 }
677499
678500 self.debug_abbrev_section_dirty = false;
......@@ -835,7 +657,7 @@ pub fn claimUnresolved(self: *ZigObject, elf_file: *Elf) void {
835657 }
836658}
837659
838pub fn claimUnresolvedObject(self: ZigObject, elf_file: *Elf) void {
660pub fn claimUnresolvedRelocatable(self: ZigObject, elf_file: *Elf) void {
839661 for (self.global_symbols.items, 0..) |index, i| {
840662 const global = &self.symbols.items[index];
841663 const esym = self.symtab.items(.elf_sym)[index];
......@@ -990,21 +812,48 @@ pub fn writeAr(self: ZigObject, writer: anytype) !void {
990812 try writer.writeAll(self.data.items);
991813}
992814
815pub fn initRelaSections(self: *ZigObject, elf_file: *Elf) !void {
816 const gpa = elf_file.base.comp.gpa;
817 for (self.atoms_indexes.items) |atom_index| {
818 const atom_ptr = self.atom(atom_index) orelse continue;
819 if (!atom_ptr.alive) continue;
820 if (atom_ptr.output_section_index == elf_file.eh_frame_section_index) continue;
821 const rela_shndx = atom_ptr.relocsShndx() orelse continue;
822 // TODO this check will become obsolete when we rework our relocs mechanism at the ZigObject level
823 if (self.relocs.items[rela_shndx].items.len == 0) continue;
824 const out_shndx = atom_ptr.output_section_index;
825 const out_shdr = elf_file.sections.items(.shdr)[out_shndx];
826 if (out_shdr.sh_type == elf.SHT_NOBITS) continue;
827 const rela_sect_name = try std.fmt.allocPrintZ(gpa, ".rela{s}", .{
828 elf_file.getShString(out_shdr.sh_name),
829 });
830 defer gpa.free(rela_sect_name);
831 _ = elf_file.sectionByName(rela_sect_name) orelse
832 try elf_file.addRelaShdr(try elf_file.insertShString(rela_sect_name), out_shndx);
833 }
834}
835
993836pub fn addAtomsToRelaSections(self: *ZigObject, elf_file: *Elf) !void {
837 const gpa = elf_file.base.comp.gpa;
994838 for (self.atoms_indexes.items) |atom_index| {
995839 const atom_ptr = self.atom(atom_index) orelse continue;
996840 if (!atom_ptr.alive) continue;
841 if (atom_ptr.output_section_index == elf_file.eh_frame_section_index) continue;
997842 const rela_shndx = atom_ptr.relocsShndx() orelse continue;
998843 // TODO this check will become obsolete when we rework our relocs mechanism at the ZigObject level
999844 if (self.relocs.items[rela_shndx].items.len == 0) continue;
1000845 const out_shndx = atom_ptr.output_section_index;
1001846 const out_shdr = elf_file.sections.items(.shdr)[out_shndx];
1002847 if (out_shdr.sh_type == elf.SHT_NOBITS) continue;
1003 const out_rela_shndx = for (elf_file.sections.items(.shdr), 0..) |out_rela_shdr, out_rela_shndx| {
1004 if (out_rela_shdr.sh_type == elf.SHT_RELA and out_rela_shdr.sh_info == out_shndx) break out_rela_shndx;
1005 } else unreachable;
848 const rela_sect_name = try std.fmt.allocPrintZ(gpa, ".rela{s}", .{
849 elf_file.getShString(out_shdr.sh_name),
850 });
851 defer gpa.free(rela_sect_name);
852 const out_rela_shndx = elf_file.sectionByName(rela_sect_name).?;
853 const out_rela_shdr = &elf_file.sections.items(.shdr)[out_rela_shndx];
854 out_rela_shdr.sh_info = out_shndx;
855 out_rela_shdr.sh_link = elf_file.symtab_section_index.?;
1006856 const atom_list = &elf_file.sections.items(.atom_list)[out_rela_shndx];
1007 const gpa = elf_file.base.comp.gpa;
1008857 try atom_list.append(gpa, .{ .index = atom_index, .file = self.index });
1009858 }
1010859}
......@@ -1075,15 +924,7 @@ pub fn writeSymtab(self: ZigObject, elf_file: *Elf) void {
1075924pub fn codeAlloc(self: *ZigObject, elf_file: *Elf, atom_index: Atom.Index) ![]u8 {
1076925 const gpa = elf_file.base.comp.gpa;
1077926 const atom_ptr = self.atom(atom_index).?;
1078 const shdr = &elf_file.sections.items(.shdr)[atom_ptr.output_section_index];
1079
1080 if (shdr.sh_flags & elf.SHF_TLS != 0) {
1081 const tlv = self.tls_variables.get(atom_index).?;
1082 const code = try gpa.dupe(u8, tlv.code);
1083 return code;
1084 }
1085
1086 const file_offset = shdr.sh_offset + @as(u64, @intCast(atom_ptr.value));
927 const file_offset = atom_ptr.offset(elf_file);
1087928 const size = std.math.cast(usize, atom_ptr.size) orelse return error.Overflow;
1088929 const code = try gpa.alloc(u8, size);
1089930 errdefer gpa.free(code);
......@@ -1168,6 +1009,20 @@ pub fn lowerUav(
11681009 return .{ .mcv = .{ .load_symbol = metadata.symbol_index } };
11691010 }
11701011
1012 const osec = if (self.data_relro_index) |sym_index|
1013 self.symbol(sym_index).atom(elf_file).?.output_section_index
1014 else osec: {
1015 const osec = try elf_file.addSection(.{
1016 .name = try elf_file.insertShString(".data.rel.ro"),
1017 .type = elf.SHT_PROGBITS,
1018 .addralign = 1,
1019 .flags = elf.SHF_ALLOC | elf.SHF_WRITE,
1020 .offset = std.math.maxInt(u64),
1021 });
1022 self.data_relro_index = try self.addSectionSymbol(gpa, ".data.rel.ro", .@"1", osec);
1023 break :osec osec;
1024 };
1025
11711026 var name_buf: [32]u8 = undefined;
11721027 const name = std.fmt.bufPrint(&name_buf, "__anon_{d}", .{
11731028 @intFromEnum(uav),
......@@ -1178,7 +1033,7 @@ pub fn lowerUav(
11781033 name,
11791034 val,
11801035 uav_alignment,
1181 elf_file.zig_data_rel_ro_section_index.?,
1036 osec,
11821037 src_loc,
11831038 ) catch |err| switch (err) {
11841039 error.OutOfMemory => return error.OutOfMemory,
......@@ -1270,6 +1125,27 @@ pub fn getOrCreateMetadataForNav(
12701125 return gop.value_ptr.symbol_index;
12711126}
12721127
1128// FIXME: we always create an atom to basically store size and alignment, however, this is only true for
1129// sections that have a single atom like the debug sections. It would be a better solution to decouple this
1130// concept from the atom, maybe.
1131fn addSectionSymbol(
1132 self: *ZigObject,
1133 allocator: Allocator,
1134 name: [:0]const u8,
1135 alignment: Atom.Alignment,
1136 shndx: u32,
1137) !Symbol.Index {
1138 const name_off = try self.addString(allocator, name);
1139 const index = try self.newSymbolWithAtom(allocator, name_off);
1140 const sym = self.symbol(index);
1141 const esym = &self.symtab.items(.elf_sym)[sym.esym_index];
1142 esym.st_info |= elf.STT_SECTION;
1143 const atom_ptr = self.atom(sym.ref.index).?;
1144 atom_ptr.alignment = alignment;
1145 atom_ptr.output_section_index = shndx;
1146 return index;
1147}
1148
12731149fn getNavShdrIndex(
12741150 self: *ZigObject,
12751151 elf_file: *Elf,
......@@ -1278,10 +1154,24 @@ fn getNavShdrIndex(
12781154 sym_index: Symbol.Index,
12791155 code: []const u8,
12801156) error{OutOfMemory}!u32 {
1157 const gpa = elf_file.base.comp.gpa;
1158 const ptr_size = elf_file.ptrWidthBytes();
12811159 const ip = &zcu.intern_pool;
12821160 const any_non_single_threaded = elf_file.base.comp.config.any_non_single_threaded;
12831161 const nav_val = zcu.navValue(nav_index);
1284 if (ip.isFunctionType(nav_val.typeOf(zcu).toIntern())) return elf_file.zig_text_section_index.?;
1162 if (ip.isFunctionType(nav_val.typeOf(zcu).toIntern())) {
1163 if (self.text_index) |symbol_index|
1164 return self.symbol(symbol_index).atom(elf_file).?.output_section_index;
1165 const osec = try elf_file.addSection(.{
1166 .type = elf.SHT_PROGBITS,
1167 .flags = elf.SHF_ALLOC | elf.SHF_EXECINSTR,
1168 .name = try elf_file.insertShString(".text"),
1169 .addralign = 1,
1170 .offset = std.math.maxInt(u64),
1171 });
1172 self.text_index = try self.addSectionSymbol(gpa, ".text", .@"1", osec);
1173 return osec;
1174 }
12851175 const is_const, const is_threadlocal, const nav_init = switch (ip.indexToKey(nav_val.toIntern())) {
12861176 .variable => |variable| .{ false, variable.is_threadlocal, variable.init },
12871177 .@"extern" => |@"extern"| .{ @"extern".is_const, @"extern".is_threadlocal, .none },
......@@ -1292,30 +1182,107 @@ fn getNavShdrIndex(
12921182 const is_bss = !has_relocs and for (code) |byte| {
12931183 if (byte != 0) break false;
12941184 } else true;
1295 if (is_bss) return elf_file.sectionByName(".tbss") orelse try elf_file.addSection(.{
1296 .type = elf.SHT_NOBITS,
1185 if (is_bss) {
1186 if (self.tbss_index) |symbol_index|
1187 return self.symbol(symbol_index).atom(elf_file).?.output_section_index;
1188 const osec = try elf_file.addSection(.{
1189 .name = try elf_file.insertShString(".tbss"),
1190 .flags = elf.SHF_ALLOC | elf.SHF_WRITE | elf.SHF_TLS,
1191 .type = elf.SHT_NOBITS,
1192 .addralign = 1,
1193 });
1194 self.tbss_index = try self.addSectionSymbol(gpa, ".tbss", .@"1", osec);
1195 return osec;
1196 }
1197 if (self.tdata_index) |symbol_index|
1198 return self.symbol(symbol_index).atom(elf_file).?.output_section_index;
1199 const osec = try elf_file.addSection(.{
1200 .type = elf.SHT_PROGBITS,
12971201 .flags = elf.SHF_ALLOC | elf.SHF_WRITE | elf.SHF_TLS,
1298 .name = try elf_file.insertShString(".tbss"),
1202 .name = try elf_file.insertShString(".tdata"),
1203 .addralign = 1,
12991204 .offset = std.math.maxInt(u64),
13001205 });
1301 return elf_file.sectionByName(".tdata") orelse try elf_file.addSection(.{
1206 self.tdata_index = try self.addSectionSymbol(gpa, ".tdata", .@"1", osec);
1207 return osec;
1208 }
1209 if (is_const) {
1210 if (self.data_relro_index) |symbol_index|
1211 return self.symbol(symbol_index).atom(elf_file).?.output_section_index;
1212 const osec = try elf_file.addSection(.{
1213 .name = try elf_file.insertShString(".data.rel.ro"),
13021214 .type = elf.SHT_PROGBITS,
1303 .flags = elf.SHF_ALLOC | elf.SHF_WRITE | elf.SHF_TLS,
1304 .name = try elf_file.insertShString(".tdata"),
1215 .addralign = 1,
1216 .flags = elf.SHF_ALLOC | elf.SHF_WRITE,
13051217 .offset = std.math.maxInt(u64),
13061218 });
1219 self.data_relro_index = try self.addSectionSymbol(gpa, ".data.rel.ro", .@"1", osec);
1220 return osec;
13071221 }
1308 if (is_const) return elf_file.zig_data_rel_ro_section_index.?;
13091222 if (nav_init != .none and Value.fromInterned(nav_init).isUndefDeep(zcu))
13101223 return switch (zcu.navFileScope(nav_index).mod.optimize_mode) {
1311 .Debug, .ReleaseSafe => elf_file.zig_data_section_index.?,
1312 .ReleaseFast, .ReleaseSmall => elf_file.zig_bss_section_index.?,
1224 .Debug, .ReleaseSafe => {
1225 if (self.data_index) |symbol_index|
1226 return self.symbol(symbol_index).atom(elf_file).?.output_section_index;
1227 const osec = try elf_file.addSection(.{
1228 .name = try elf_file.insertShString(".data"),
1229 .type = elf.SHT_PROGBITS,
1230 .addralign = ptr_size,
1231 .flags = elf.SHF_ALLOC | elf.SHF_WRITE,
1232 .offset = std.math.maxInt(u64),
1233 });
1234 self.data_index = try self.addSectionSymbol(
1235 gpa,
1236 ".data",
1237 Atom.Alignment.fromNonzeroByteUnits(ptr_size),
1238 osec,
1239 );
1240 return osec;
1241 },
1242 .ReleaseFast, .ReleaseSmall => {
1243 if (self.bss_index) |symbol_index|
1244 return self.symbol(symbol_index).atom(elf_file).?.output_section_index;
1245 const osec = try elf_file.addSection(.{
1246 .type = elf.SHT_NOBITS,
1247 .flags = elf.SHF_ALLOC | elf.SHF_WRITE,
1248 .name = try elf_file.insertShString(".bss"),
1249 .addralign = 1,
1250 });
1251 self.bss_index = try self.addSectionSymbol(gpa, ".bss", .@"1", osec);
1252 return osec;
1253 },
13131254 };
13141255 const is_bss = !has_relocs and for (code) |byte| {
13151256 if (byte != 0) break false;
13161257 } else true;
1317 if (is_bss) return elf_file.zig_bss_section_index.?;
1318 return elf_file.zig_data_section_index.?;
1258 if (is_bss) {
1259 if (self.bss_index) |symbol_index|
1260 return self.symbol(symbol_index).atom(elf_file).?.output_section_index;
1261 const osec = try elf_file.addSection(.{
1262 .type = elf.SHT_NOBITS,
1263 .flags = elf.SHF_ALLOC | elf.SHF_WRITE,
1264 .name = try elf_file.insertShString(".bss"),
1265 .addralign = 1,
1266 });
1267 self.bss_index = try self.addSectionSymbol(gpa, ".bss", .@"1", osec);
1268 return osec;
1269 }
1270 if (self.data_index) |symbol_index|
1271 return self.symbol(symbol_index).atom(elf_file).?.output_section_index;
1272 const osec = try elf_file.addSection(.{
1273 .name = try elf_file.insertShString(".data"),
1274 .type = elf.SHT_PROGBITS,
1275 .addralign = ptr_size,
1276 .flags = elf.SHF_ALLOC | elf.SHF_WRITE,
1277 .offset = std.math.maxInt(u64),
1278 });
1279 self.data_index = try self.addSectionSymbol(
1280 gpa,
1281 ".data",
1282 Atom.Alignment.fromNonzeroByteUnits(ptr_size),
1283 osec,
1284 );
1285 return osec;
13191286}
13201287
13211288fn updateNavCode(
......@@ -1362,19 +1329,18 @@ fn updateNavCode(
13621329 const capacity = atom_ptr.capacity(elf_file);
13631330 const need_realloc = code.len > capacity or !required_alignment.check(@intCast(atom_ptr.value));
13641331 if (need_realloc) {
1365 try atom_ptr.grow(elf_file);
1332 try self.growAtom(atom_ptr, elf_file);
13661333 log.debug("growing {} from 0x{x} to 0x{x}", .{ nav.fqn.fmt(ip), old_vaddr, atom_ptr.value });
13671334 if (old_vaddr != atom_ptr.value) {
13681335 sym.value = 0;
13691336 esym.st_value = 0;
13701337 }
13711338 } else if (code.len < old_size) {
1372 atom_ptr.shrink(elf_file);
1339 // TODO shrink section size
13731340 }
13741341 } else {
1375 try atom_ptr.allocate(elf_file);
1342 try self.allocateAtom(atom_ptr, elf_file);
13761343 errdefer self.freeNavMetadata(elf_file, sym_index);
1377
13781344 sym.value = 0;
13791345 esym.st_value = 0;
13801346 }
......@@ -1404,7 +1370,7 @@ fn updateNavCode(
14041370
14051371 const shdr = elf_file.sections.items(.shdr)[shdr_index];
14061372 if (shdr.sh_type != elf.SHT_NOBITS) {
1407 const file_offset = shdr.sh_offset + @as(u64, @intCast(atom_ptr.value));
1373 const file_offset = atom_ptr.offset(elf_file);
14081374 try elf_file.base.file.?.pwriteAll(code, file_offset);
14091375 log.debug("writing {} from 0x{x} to 0x{x}", .{ nav.fqn.fmt(ip), file_offset, file_offset + code.len });
14101376 }
......@@ -1433,15 +1399,11 @@ fn updateTlv(
14331399 const atom_ptr = sym.atom(elf_file).?;
14341400 const name_offset = try self.strtab.insert(gpa, nav.fqn.toSlice(ip));
14351401
1436 sym.value = 0;
1437 sym.name_offset = name_offset;
1438
1439 atom_ptr.output_section_index = shndx;
14401402 atom_ptr.alive = true;
14411403 atom_ptr.name_offset = name_offset;
1404 atom_ptr.output_section_index = shndx;
14421405
14431406 sym.name_offset = name_offset;
1444 esym.st_value = 0;
14451407 esym.st_name = name_offset;
14461408 esym.st_info = elf.STT_TLS;
14471409 esym.st_size = code.len;
......@@ -1449,21 +1411,25 @@ fn updateTlv(
14491411 atom_ptr.alignment = required_alignment;
14501412 atom_ptr.size = code.len;
14511413
1452 self.navs.getPtr(nav_index).?.allocated = true;
1414 const gop = try self.tls_variables.getOrPut(gpa, atom_ptr.atom_index);
1415 assert(!gop.found_existing); // TODO incremental updates
14531416
1454 {
1455 const gop = try self.tls_variables.getOrPut(gpa, atom_ptr.atom_index);
1456 assert(!gop.found_existing); // TODO incremental updates
1457 gop.value_ptr.* = .{ .symbol_index = sym_index };
1417 try self.allocateAtom(atom_ptr, elf_file);
1418 sym.value = 0;
1419 esym.st_value = 0;
14581420
1459 // We only store the data for the TLV if it's non-zerofill.
1460 if (elf_file.sections.items(.shdr)[shndx].sh_type != elf.SHT_NOBITS) {
1461 gop.value_ptr.code = try gpa.dupe(u8, code);
1462 }
1463 }
1421 self.navs.getPtr(nav_index).?.allocated = true;
14641422
1465 const atom_list = &elf_file.sections.items(.atom_list)[atom_ptr.output_section_index];
1466 try atom_list.append(gpa, .{ .index = atom_ptr.atom_index, .file = self.index });
1423 const shdr = elf_file.sections.items(.shdr)[shndx];
1424 if (shdr.sh_type != elf.SHT_NOBITS) {
1425 const file_offset = atom_ptr.offset(elf_file);
1426 try elf_file.base.file.?.pwriteAll(code, file_offset);
1427 log.debug("writing TLV {s} from 0x{x} to 0x{x}", .{
1428 atom_ptr.name(elf_file),
1429 file_offset,
1430 file_offset + code.len,
1431 });
1432 }
14671433}
14681434
14691435pub fn updateFunc(
......@@ -1558,6 +1524,19 @@ pub fn updateFunc(
15581524 self.symbol(sym_index).name(elf_file),
15591525 });
15601526 defer gpa.free(name);
1527 const osec = if (self.text_index) |sect_sym_index|
1528 self.symbol(sect_sym_index).atom(elf_file).?.output_section_index
1529 else osec: {
1530 const osec = try elf_file.addSection(.{
1531 .name = try elf_file.insertShString(".text"),
1532 .flags = elf.SHF_ALLOC | elf.SHF_EXECINSTR,
1533 .type = elf.SHT_PROGBITS,
1534 .addralign = 1,
1535 .offset = std.math.maxInt(u64),
1536 });
1537 self.text_index = try self.addSectionSymbol(gpa, ".text", .@"1", osec);
1538 break :osec osec;
1539 };
15611540 const name_off = try self.addString(gpa, name);
15621541 const tr_size = trampolineSize(elf_file.getTarget().cpu.arch);
15631542 const tr_sym_index = try self.newSymbolWithAtom(gpa, name_off);
......@@ -1569,7 +1548,7 @@ pub fn updateFunc(
15691548 tr_atom_ptr.value = old_rva;
15701549 tr_atom_ptr.alive = true;
15711550 tr_atom_ptr.alignment = old_alignment;
1572 tr_atom_ptr.output_section_index = elf_file.zig_text_section_index.?;
1551 tr_atom_ptr.output_section_index = osec;
15731552 tr_atom_ptr.size = tr_size;
15741553 const target_sym = self.symbol(sym_index);
15751554 target_sym.addExtra(.{ .trampoline = tr_sym_index }, elf_file);
......@@ -1723,8 +1702,32 @@ fn updateLazySymbol(
17231702 };
17241703
17251704 const output_section_index = switch (sym.kind) {
1726 .code => elf_file.zig_text_section_index.?,
1727 .const_data => elf_file.zig_data_rel_ro_section_index.?,
1705 .code => if (self.text_index) |sym_index|
1706 self.symbol(sym_index).atom(elf_file).?.output_section_index
1707 else osec: {
1708 const osec = try elf_file.addSection(.{
1709 .name = try elf_file.insertShString(".text"),
1710 .type = elf.SHT_PROGBITS,
1711 .addralign = 1,
1712 .flags = elf.SHF_ALLOC | elf.SHF_EXECINSTR,
1713 .offset = std.math.maxInt(u64),
1714 });
1715 self.text_index = try self.addSectionSymbol(gpa, ".text", .@"1", osec);
1716 break :osec osec;
1717 },
1718 .const_data => if (self.rodata_index) |sym_index|
1719 self.symbol(sym_index).atom(elf_file).?.output_section_index
1720 else osec: {
1721 const osec = try elf_file.addSection(.{
1722 .name = try elf_file.insertShString(".rodata"),
1723 .type = elf.SHT_PROGBITS,
1724 .addralign = 1,
1725 .flags = elf.SHF_ALLOC,
1726 .offset = std.math.maxInt(u64),
1727 });
1728 self.rodata_index = try self.addSectionSymbol(gpa, ".rodata", .@"1", osec);
1729 break :osec osec;
1730 },
17281731 };
17291732 const local_sym = self.symbol(symbol_index);
17301733 local_sym.name_offset = name_str_index;
......@@ -1739,15 +1742,13 @@ fn updateLazySymbol(
17391742 atom_ptr.size = code.len;
17401743 atom_ptr.output_section_index = output_section_index;
17411744
1742 try atom_ptr.allocate(elf_file);
1745 try self.allocateAtom(atom_ptr, elf_file);
17431746 errdefer self.freeNavMetadata(elf_file, symbol_index);
17441747
17451748 local_sym.value = 0;
17461749 local_esym.st_value = 0;
17471750
1748 const shdr = elf_file.sections.items(.shdr)[output_section_index];
1749 const file_offset = shdr.sh_offset + @as(u64, @intCast(atom_ptr.value));
1750 try elf_file.base.file.?.pwriteAll(code, file_offset);
1751 try elf_file.base.file.?.pwriteAll(code, atom_ptr.offset(elf_file));
17511752}
17521753
17531754const LowerConstResult = union(enum) {
......@@ -1797,13 +1798,10 @@ fn lowerConst(
17971798 atom_ptr.size = code.len;
17981799 atom_ptr.output_section_index = output_section_index;
17991800
1800 try atom_ptr.allocate(elf_file);
1801 // TODO rename and re-audit this method
1801 try self.allocateAtom(atom_ptr, elf_file);
18021802 errdefer self.freeNavMetadata(elf_file, sym_index);
18031803
1804 const shdr = elf_file.sections.items(.shdr)[output_section_index];
1805 const file_offset = shdr.sh_offset + @as(u64, @intCast(atom_ptr.value));
1806 try elf_file.base.file.?.pwriteAll(code, file_offset);
1804 try elf_file.base.file.?.pwriteAll(code, atom_ptr.offset(elf_file));
18071805
18081806 return .{ .ok = sym_index };
18091807}
......@@ -1965,8 +1963,7 @@ fn trampolineSize(cpu_arch: std.Target.Cpu.Arch) u64 {
19651963
19661964fn writeTrampoline(tr_sym: Symbol, target: Symbol, elf_file: *Elf) !void {
19671965 const atom_ptr = tr_sym.atom(elf_file).?;
1968 const shdr = elf_file.sections.items(.shdr)[atom_ptr.output_section_index];
1969 const fileoff = shdr.sh_offset + @as(u64, @intCast(atom_ptr.value));
1966 const fileoff = atom_ptr.offset(elf_file);
19701967 const source_addr = tr_sym.address(.{}, elf_file);
19711968 const target_addr = target.address(.{ .trampoline = false }, elf_file);
19721969 var buf: [max_trampoline_len]u8 = undefined;
......@@ -1998,6 +1995,80 @@ fn writeTrampoline(tr_sym: Symbol, target: Symbol, elf_file: *Elf) !void {
19981995 }
19991996}
20001997
1998fn allocateAtom(self: *ZigObject, atom_ptr: *Atom, elf_file: *Elf) !void {
1999 const alloc_res = try elf_file.allocateChunk(.{
2000 .shndx = atom_ptr.output_section_index,
2001 .size = atom_ptr.size,
2002 .alignment = atom_ptr.alignment,
2003 });
2004 atom_ptr.value = @intCast(alloc_res.value);
2005
2006 const slice = elf_file.sections.slice();
2007 const shdr = &slice.items(.shdr)[atom_ptr.output_section_index];
2008 const last_atom_ref = &slice.items(.last_atom)[atom_ptr.output_section_index];
2009
2010 const expand_section = if (elf_file.atom(alloc_res.placement)) |placement_atom|
2011 placement_atom.nextAtom(elf_file) == null
2012 else
2013 true;
2014 if (expand_section) {
2015 last_atom_ref.* = atom_ptr.ref();
2016 if (self.dwarf) |_| {
2017 // The .debug_info section has `low_pc` and `high_pc` values which is the virtual address
2018 // range of the compilation unit. When we expand the text section, this range changes,
2019 // so the DW_TAG.compile_unit tag of the .debug_info section becomes dirty.
2020 self.debug_info_section_dirty = true;
2021 // This becomes dirty for the same reason. We could potentially make this more
2022 // fine-grained with the addition of support for more compilation units. It is planned to
2023 // model each package as a different compilation unit.
2024 self.debug_aranges_section_dirty = true;
2025 self.debug_rnglists_section_dirty = true;
2026 }
2027 }
2028 shdr.sh_addralign = @max(shdr.sh_addralign, atom_ptr.alignment.toByteUnits().?);
2029
2030 const sect_atom_ptr = for ([_]?Symbol.Index{
2031 self.text_index,
2032 self.rodata_index,
2033 self.data_relro_index,
2034 self.data_index,
2035 self.tdata_index,
2036 }) |maybe_sym_index| {
2037 const sect_sym_index = maybe_sym_index orelse continue;
2038 const sect_atom_ptr = self.symbol(sect_sym_index).atom(elf_file).?;
2039 if (sect_atom_ptr.output_section_index == atom_ptr.output_section_index) break sect_atom_ptr;
2040 } else null;
2041 if (sect_atom_ptr) |sap| {
2042 sap.size = shdr.sh_size;
2043 sap.alignment = Atom.Alignment.fromNonzeroByteUnits(shdr.sh_addralign);
2044 }
2045
2046 // This function can also reallocate an atom.
2047 // In this case we need to "unplug" it from its previous location before
2048 // plugging it in to its new location.
2049 if (atom_ptr.prevAtom(elf_file)) |prev| {
2050 prev.next_atom_ref = atom_ptr.next_atom_ref;
2051 }
2052 if (atom_ptr.nextAtom(elf_file)) |next| {
2053 next.prev_atom_ref = atom_ptr.prev_atom_ref;
2054 }
2055
2056 if (elf_file.atom(alloc_res.placement)) |big_atom| {
2057 atom_ptr.prev_atom_ref = alloc_res.placement;
2058 atom_ptr.next_atom_ref = big_atom.next_atom_ref;
2059 big_atom.next_atom_ref = atom_ptr.ref();
2060 } else {
2061 atom_ptr.prev_atom_ref = .{ .index = 0, .file = 0 };
2062 atom_ptr.next_atom_ref = .{ .index = 0, .file = 0 };
2063 }
2064}
2065
2066fn growAtom(self: *ZigObject, atom_ptr: *Atom, elf_file: *Elf) !void {
2067 if (!atom_ptr.alignment.check(@intCast(atom_ptr.value)) or atom_ptr.size > atom_ptr.capacity(elf_file)) {
2068 try self.allocateAtom(atom_ptr, elf_file);
2069 }
2070}
2071
20012072pub fn asFile(self: *ZigObject) File {
20022073 return .{ .zig_object = self };
20032074}
......@@ -2271,7 +2342,7 @@ const AtomList = std.ArrayListUnmanaged(Atom.Index);
22712342const NavTable = std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, AvMetadata);
22722343const UavTable = std.AutoArrayHashMapUnmanaged(InternPool.Index, AvMetadata);
22732344const LazySymbolTable = std.AutoArrayHashMapUnmanaged(InternPool.Index, LazySymbolMetadata);
2274const TlsTable = std.AutoArrayHashMapUnmanaged(Atom.Index, TlsVariable);
2345const TlsTable = std.AutoArrayHashMapUnmanaged(Atom.Index, void);
22752346
22762347const x86_64 = struct {
22772348 fn writeTrampolineCode(source_addr: i64, target_addr: i64, buf: *[max_trampoline_len]u8) ![]u8 {
src/link/Elf/eh_frame.zig+30-6
......@@ -233,7 +233,10 @@ pub fn calcEhFrameSize(elf_file: *Elf) !usize {
233233 const comp = elf_file.base.comp;
234234 const gpa = comp.gpa;
235235
236 var offset: usize = 0;
236 var offset: usize = if (elf_file.zigObjectPtr()) |zo| blk: {
237 const sym = zo.symbol(zo.eh_frame_index orelse break :blk 0);
238 break :blk math.cast(usize, sym.atom(elf_file).?.size) orelse return error.Overflow;
239 } else 0;
237240
238241 var cies = std.ArrayList(Cie).init(gpa);
239242 defer cies.deinit();
......@@ -288,6 +291,13 @@ pub fn calcEhFrameHdrSize(elf_file: *Elf) usize {
288291
289292pub fn calcEhFrameRelocs(elf_file: *Elf) usize {
290293 var count: usize = 0;
294 if (elf_file.zigObjectPtr()) |zo| zo: {
295 const sym_index = zo.eh_frame_index orelse break :zo;
296 const sym = zo.symbol(sym_index);
297 const atom_ptr = zo.atom(sym.ref.index).?;
298 if (!atom_ptr.alive) break :zo;
299 count += atom_ptr.relocs(elf_file).len;
300 }
291301 for (elf_file.objects.items) |index| {
292302 const object = elf_file.file(index).?.object;
293303 for (object.cies.items) |cie| {
......@@ -386,7 +396,7 @@ pub fn writeEhFrame(elf_file: *Elf, writer: anytype) !void {
386396 if (has_reloc_errors) return error.RelocFailure;
387397}
388398
389pub fn writeEhFrameObject(elf_file: *Elf, writer: anytype) !void {
399pub fn writeEhFrameRelocatable(elf_file: *Elf, writer: anytype) !void {
390400 for (elf_file.objects.items) |index| {
391401 const object = elf_file.file(index).?.object;
392402
......@@ -416,9 +426,8 @@ pub fn writeEhFrameObject(elf_file: *Elf, writer: anytype) !void {
416426 }
417427}
418428
419fn emitReloc(elf_file: *Elf, rec: anytype, sym: *const Symbol, rel: elf.Elf64_Rela) elf.Elf64_Rela {
429fn emitReloc(elf_file: *Elf, r_offset: u64, sym: *const Symbol, rel: elf.Elf64_Rela) elf.Elf64_Rela {
420430 const cpu_arch = elf_file.getTarget().cpu.arch;
421 const r_offset = rec.address(elf_file) + rel.r_offset - rec.offset;
422431 const r_type = rel.r_type();
423432 var r_addend = rel.r_addend;
424433 var r_sym: u32 = 0;
......@@ -452,6 +461,19 @@ pub fn writeEhFrameRelocs(elf_file: *Elf, writer: anytype) !void {
452461 elf_file.sections.items(.shdr)[elf_file.eh_frame_section_index.?].sh_addr,
453462 });
454463
464 if (elf_file.zigObjectPtr()) |zo| zo: {
465 const sym_index = zo.eh_frame_index orelse break :zo;
466 const sym = zo.symbol(sym_index);
467 const atom_ptr = zo.atom(sym.ref.index).?;
468 if (!atom_ptr.alive) break :zo;
469 for (atom_ptr.relocs(elf_file)) |rel| {
470 const ref = zo.resolveSymbol(rel.r_sym(), elf_file);
471 const target = elf_file.symbol(ref).?;
472 const out_rel = emitReloc(elf_file, rel.r_offset, target, rel);
473 try writer.writeStruct(out_rel);
474 }
475 }
476
455477 for (elf_file.objects.items) |index| {
456478 const object = elf_file.file(index).?.object;
457479
......@@ -460,7 +482,8 @@ pub fn writeEhFrameRelocs(elf_file: *Elf, writer: anytype) !void {
460482 for (cie.relocs(elf_file)) |rel| {
461483 const ref = object.resolveSymbol(rel.r_sym(), elf_file);
462484 const sym = elf_file.symbol(ref).?;
463 const out_rel = emitReloc(elf_file, cie, sym, rel);
485 const r_offset = cie.address(elf_file) + rel.r_offset - cie.offset;
486 const out_rel = emitReloc(elf_file, r_offset, sym, rel);
464487 try writer.writeStruct(out_rel);
465488 }
466489 }
......@@ -470,7 +493,8 @@ pub fn writeEhFrameRelocs(elf_file: *Elf, writer: anytype) !void {
470493 for (fde.relocs(elf_file)) |rel| {
471494 const ref = object.resolveSymbol(rel.r_sym(), elf_file);
472495 const sym = elf_file.symbol(ref).?;
473 const out_rel = emitReloc(elf_file, fde, sym, rel);
496 const r_offset = fde.address(elf_file) + rel.r_offset - fde.offset;
497 const out_rel = emitReloc(elf_file, r_offset, sym, rel);
474498 try writer.writeStruct(out_rel);
475499 }
476500 }
src/link/Elf/relocatable.zig+80-114
......@@ -18,7 +18,7 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]co
1818 }
1919
2020 for (positionals.items) |obj| {
21 parsePositional(elf_file, obj.path) catch |err| switch (err) {
21 parsePositionalStaticLib(elf_file, obj.path) catch |err| switch (err) {
2222 error.MalformedObject,
2323 error.MalformedArchive,
2424 error.InvalidMachineType,
......@@ -38,17 +38,12 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]co
3838 // First, we flush relocatable object file generated with our backends.
3939 if (elf_file.zigObjectPtr()) |zig_object| {
4040 try zig_object.resolveSymbols(elf_file);
41 elf_file.markEhFrameAtomsDead();
4142 try elf_file.addCommentString();
4243 try elf_file.finalizeMergeSections();
43 zig_object.claimUnresolvedObject(elf_file);
44 zig_object.claimUnresolvedRelocatable(elf_file);
4445
45 for (elf_file.merge_sections.items) |*msec| {
46 if (msec.finalized_subsections.items.len == 0) continue;
47 try msec.initOutputSection(elf_file);
48 }
49
50 try elf_file.initSymtab();
51 try elf_file.initShStrtab();
46 try initSections(elf_file);
5247 try elf_file.sortShdrs();
5348 try zig_object.addAtomsToRelaSections(elf_file);
5449 try elf_file.updateMergeSectionSizes();
......@@ -208,7 +203,6 @@ pub fn flushObject(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]const
208203 }
209204 for (elf_file.objects.items) |index| {
210205 const object = elf_file.file(index).?.object;
211 try object.addAtomsToOutputSections(elf_file);
212206 try object.addAtomsToRelaSections(elf_file);
213207 }
214208 try elf_file.updateMergeSectionSizes();
......@@ -230,17 +224,17 @@ pub fn flushObject(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]const
230224 if (elf_file.base.hasErrors()) return error.FlushFailure;
231225}
232226
233fn parsePositional(elf_file: *Elf, path: []const u8) Elf.ParseError!void {
227fn parsePositionalStaticLib(elf_file: *Elf, path: []const u8) Elf.ParseError!void {
234228 if (try Object.isObject(path)) {
235 try parseObject(elf_file, path);
229 try parseObjectStaticLib(elf_file, path);
236230 } else if (try Archive.isArchive(path)) {
237 try parseArchive(elf_file, path);
231 try parseArchiveStaticLib(elf_file, path);
238232 } else return error.UnknownFileType;
239233 // TODO: should we check for LD script?
240234 // Actually, should we even unpack an archive?
241235}
242236
243fn parseObject(elf_file: *Elf, path: []const u8) Elf.ParseError!void {
237fn parseObjectStaticLib(elf_file: *Elf, path: []const u8) Elf.ParseError!void {
244238 const gpa = elf_file.base.comp.gpa;
245239 const handle = try std.fs.cwd().openFile(path, .{});
246240 const fh = try elf_file.addFileHandle(handle);
......@@ -257,7 +251,7 @@ fn parseObject(elf_file: *Elf, path: []const u8) Elf.ParseError!void {
257251 try object.parseAr(elf_file);
258252}
259253
260fn parseArchive(elf_file: *Elf, path: []const u8) Elf.ParseError!void {
254fn parseArchiveStaticLib(elf_file: *Elf, path: []const u8) Elf.ParseError!void {
261255 const gpa = elf_file.base.comp.gpa;
262256 const handle = try std.fs.cwd().openFile(path, .{});
263257 const fh = try elf_file.addFileHandle(handle);
......@@ -281,14 +275,17 @@ fn parseArchive(elf_file: *Elf, path: []const u8) Elf.ParseError!void {
281275
282276fn claimUnresolved(elf_file: *Elf) void {
283277 if (elf_file.zigObjectPtr()) |zig_object| {
284 zig_object.claimUnresolvedObject(elf_file);
278 zig_object.claimUnresolvedRelocatable(elf_file);
285279 }
286280 for (elf_file.objects.items) |index| {
287 elf_file.file(index).?.object.claimUnresolvedObject(elf_file);
281 elf_file.file(index).?.object.claimUnresolvedRelocatable(elf_file);
288282 }
289283}
290284
291285fn initSections(elf_file: *Elf) !void {
286 if (elf_file.zigObjectPtr()) |zo| {
287 try zo.initRelaSections(elf_file);
288 }
292289 for (elf_file.objects.items) |index| {
293290 const object = elf_file.file(index).?.object;
294291 try object.initOutputSections(elf_file);
......@@ -300,12 +297,17 @@ fn initSections(elf_file: *Elf) !void {
300297 try msec.initOutputSection(elf_file);
301298 }
302299
303 const needs_eh_frame = for (elf_file.objects.items) |index| {
304 if (elf_file.file(index).?.object.cies.items.len > 0) break true;
305 } else false;
300 const needs_eh_frame = blk: {
301 if (elf_file.zigObjectPtr()) |zo|
302 if (zo.eh_frame_index != null) break :blk true;
303 break :blk for (elf_file.objects.items) |index| {
304 if (elf_file.file(index).?.object.cies.items.len > 0) break true;
305 } else false;
306 };
306307 if (needs_eh_frame) {
307308 if (elf_file.eh_frame_section_index == null) {
308 elf_file.eh_frame_section_index = try elf_file.addSection(.{
309 elf_file.eh_frame_section_index = elf_file.sectionByName(".eh_frame") orelse
310 try elf_file.addSection(.{
309311 .name = try elf_file.insertShString(".eh_frame"),
310312 .type = if (elf_file.getTarget().cpu.arch == .x86_64)
311313 elf.SHT_X86_64_UNWIND
......@@ -316,7 +318,8 @@ fn initSections(elf_file: *Elf) !void {
316318 .offset = std.math.maxInt(u64),
317319 });
318320 }
319 elf_file.eh_frame_rela_section_index = try elf_file.addRelaShdr(
321 elf_file.eh_frame_rela_section_index = elf_file.sectionByName(".rela.eh_frame") orelse
322 try elf_file.addRelaShdr(
320323 try elf_file.insertShString(".rela.eh_frame"),
321324 elf_file.eh_frame_section_index.?,
322325 );
......@@ -351,36 +354,28 @@ fn initComdatGroups(elf_file: *Elf) !void {
351354
352355fn updateSectionSizes(elf_file: *Elf) !void {
353356 const slice = elf_file.sections.slice();
357 for (slice.items(.atom_list_2)) |*atom_list| {
358 if (atom_list.atoms.items.len == 0) continue;
359 atom_list.updateSize(elf_file);
360 try atom_list.allocate(elf_file);
361 }
362
354363 for (slice.items(.shdr), 0..) |*shdr, shndx| {
355364 const atom_list = slice.items(.atom_list)[shndx];
356 if (shdr.sh_type != elf.SHT_RELA) {
357 for (atom_list.items) |ref| {
358 const atom_ptr = elf_file.atom(ref) orelse continue;
359 if (!atom_ptr.alive) continue;
360 const offset = atom_ptr.alignment.forward(shdr.sh_size);
361 const padding = offset - shdr.sh_size;
362 atom_ptr.value = @intCast(offset);
363 shdr.sh_size += padding + atom_ptr.size;
364 shdr.sh_addralign = @max(shdr.sh_addralign, atom_ptr.alignment.toByteUnits() orelse 1);
365 }
366 } else {
367 for (atom_list.items) |ref| {
368 const atom_ptr = elf_file.atom(ref) orelse continue;
369 if (!atom_ptr.alive) continue;
370 const relocs = atom_ptr.relocs(elf_file);
371 shdr.sh_size += shdr.sh_entsize * relocs.len;
372 }
373
374 if (shdr.sh_size == 0) shdr.sh_offset = 0;
365 if (shdr.sh_type != elf.SHT_RELA) continue;
366 if (@as(u32, @intCast(shndx)) == elf_file.eh_frame_section_index) continue;
367 for (atom_list.items) |ref| {
368 const atom_ptr = elf_file.atom(ref) orelse continue;
369 if (!atom_ptr.alive) continue;
370 const relocs = atom_ptr.relocs(elf_file);
371 shdr.sh_size += shdr.sh_entsize * relocs.len;
375372 }
373
374 if (shdr.sh_size == 0) shdr.sh_offset = 0;
376375 }
377376
378377 if (elf_file.eh_frame_section_index) |index| {
379 slice.items(.shdr)[index].sh_size = existing_size: {
380 const zo = elf_file.zigObjectPtr() orelse break :existing_size 0;
381 const sym = zo.symbol(zo.eh_frame_index orelse break :existing_size 0);
382 break :existing_size sym.atom(elf_file).?.size;
383 } + try eh_frame.calcEhFrameSize(elf_file);
378 slice.items(.shdr)[index].sh_size = try eh_frame.calcEhFrameSize(elf_file);
384379 }
385380 if (elf_file.eh_frame_rela_section_index) |index| {
386381 const shdr = &slice.items(.shdr)[index];
......@@ -405,7 +400,7 @@ fn updateComdatGroupsSizes(elf_file: *Elf) void {
405400
406401/// Allocates alloc sections when merging relocatable objects files together.
407402fn allocateAllocSections(elf_file: *Elf) !void {
408 for (elf_file.sections.items(.shdr)) |*shdr| {
403 for (elf_file.sections.items(.shdr), 0..) |*shdr, shndx| {
409404 if (shdr.sh_type == elf.SHT_NULL) continue;
410405 if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue;
411406 if (shdr.sh_type == elf.SHT_NOBITS) {
......@@ -416,6 +411,34 @@ fn allocateAllocSections(elf_file: *Elf) !void {
416411 if (needed_size > elf_file.allocatedSize(shdr.sh_offset)) {
417412 shdr.sh_size = 0;
418413 const new_offset = try elf_file.findFreeSpace(needed_size, shdr.sh_addralign);
414
415 if (elf_file.zigObjectPtr()) |zo| blk: {
416 const existing_size = for ([_]?Symbol.Index{
417 zo.text_index,
418 zo.rodata_index,
419 zo.data_relro_index,
420 zo.data_index,
421 zo.tdata_index,
422 zo.eh_frame_index,
423 }) |maybe_sym_index| {
424 const sect_sym_index = maybe_sym_index orelse continue;
425 const sect_atom_ptr = zo.symbol(sect_sym_index).atom(elf_file).?;
426 if (sect_atom_ptr.output_section_index == shndx) break sect_atom_ptr.size;
427 } else break :blk;
428 log.debug("moving {s} from 0x{x} to 0x{x}", .{
429 elf_file.getShString(shdr.sh_name),
430 shdr.sh_offset,
431 new_offset,
432 });
433 const amt = try elf_file.base.file.?.copyRangeAll(
434 shdr.sh_offset,
435 elf_file.base.file.?,
436 new_offset,
437 existing_size,
438 );
439 if (amt != existing_size) return error.InputOutput;
440 }
441
419442 shdr.sh_offset = new_offset;
420443 shdr.sh_size = needed_size;
421444 }
......@@ -424,73 +447,15 @@ fn allocateAllocSections(elf_file: *Elf) !void {
424447
425448fn writeAtoms(elf_file: *Elf) !void {
426449 const gpa = elf_file.base.comp.gpa;
427 const slice = elf_file.sections.slice();
428
429 // TODO iterate over `output_sections` directly
430 for (slice.items(.shdr), slice.items(.atom_list), 0..) |shdr, atom_list, shndx| {
431 if (shdr.sh_type == elf.SHT_NULL) continue;
432 if (shdr.sh_type == elf.SHT_NOBITS) continue;
433 if (shdr.sh_type == elf.SHT_RELA) continue;
434 if (atom_list.items.len == 0) continue;
435
436 log.debug("writing atoms in '{s}' section", .{elf_file.getShString(shdr.sh_name)});
437
438 // TODO really, really handle debug section separately
439 const base_offset = if (elf_file.isDebugSection(@intCast(shndx))) blk: {
440 const zo = elf_file.zigObjectPtr().?;
441 break :blk for ([_]Symbol.Index{
442 zo.debug_info_index.?,
443 zo.debug_abbrev_index.?,
444 zo.debug_aranges_index.?,
445 zo.debug_str_index.?,
446 zo.debug_line_index.?,
447 zo.debug_line_str_index.?,
448 zo.debug_loclists_index.?,
449 zo.debug_rnglists_index.?,
450 }) |sym_index| {
451 const sym = zo.symbol(sym_index);
452 const atom_ptr = sym.atom(elf_file).?;
453 if (atom_ptr.output_section_index == shndx) break atom_ptr.size;
454 } else 0;
455 } else 0;
456 const sh_offset = shdr.sh_offset + base_offset;
457 const sh_size = math.cast(usize, shdr.sh_size - base_offset) orelse return error.Overflow;
458
459 const buffer = try gpa.alloc(u8, sh_size);
460 defer gpa.free(buffer);
461 const padding_byte: u8 = if (shdr.sh_type == elf.SHT_PROGBITS and
462 shdr.sh_flags & elf.SHF_EXECINSTR != 0)
463 0xcc // int3
464 else
465 0;
466 @memset(buffer, padding_byte);
467
468 for (atom_list.items) |ref| {
469 const atom_ptr = elf_file.atom(ref).?;
470 assert(atom_ptr.alive);
471
472 const offset = math.cast(usize, atom_ptr.value - @as(i64, @intCast(shdr.sh_addr - base_offset))) orelse
473 return error.Overflow;
474 const size = math.cast(usize, atom_ptr.size) orelse return error.Overflow;
475450
476 log.debug("writing atom({}) from 0x{x} to 0x{x}", .{
477 ref,
478 sh_offset + offset,
479 sh_offset + offset + size,
480 });
481
482 // TODO decompress directly into provided buffer
483 const out_code = buffer[offset..][0..size];
484 const in_code = switch (atom_ptr.file(elf_file).?) {
485 .object => |x| try x.codeDecompressAlloc(elf_file, ref.index),
486 .zig_object => |x| try x.codeAlloc(elf_file, ref.index),
487 else => unreachable,
488 };
489 defer gpa.free(in_code);
490 @memcpy(out_code, in_code);
491 }
451 var buffer = std.ArrayList(u8).init(gpa);
452 defer buffer.deinit();
492453
493 try elf_file.base.file.?.pwriteAll(buffer, sh_offset);
454 const slice = elf_file.sections.slice();
455 for (slice.items(.shdr), slice.items(.atom_list_2)) |shdr, atom_list| {
456 if (shdr.sh_type == elf.SHT_NOBITS) continue;
457 if (atom_list.atoms.items.len == 0) continue;
458 try atom_list.writeRelocatable(&buffer, elf_file);
494459 }
495460}
496461
......@@ -498,9 +463,10 @@ fn writeSyntheticSections(elf_file: *Elf) !void {
498463 const gpa = elf_file.base.comp.gpa;
499464 const slice = elf_file.sections.slice();
500465
501 for (slice.items(.shdr), slice.items(.atom_list)) |shdr, atom_list| {
466 for (slice.items(.shdr), slice.items(.atom_list), 0..) |shdr, atom_list, shndx| {
502467 if (shdr.sh_type != elf.SHT_RELA) continue;
503468 if (atom_list.items.len == 0) continue;
469 if (@as(u32, @intCast(shndx)) == elf_file.eh_frame_section_index) continue;
504470
505471 const num_relocs = math.cast(usize, @divExact(shdr.sh_size, shdr.sh_entsize)) orelse
506472 return error.Overflow;
......@@ -542,7 +508,7 @@ fn writeSyntheticSections(elf_file: *Elf) !void {
542508 const sh_size = math.cast(usize, shdr.sh_size) orelse return error.Overflow;
543509 var buffer = try std.ArrayList(u8).initCapacity(gpa, @intCast(sh_size - existing_size));
544510 defer buffer.deinit();
545 try eh_frame.writeEhFrameObject(elf_file, buffer.writer());
511 try eh_frame.writeEhFrameRelocatable(elf_file, buffer.writer());
546512 log.debug("writing .eh_frame from 0x{x} to 0x{x}", .{
547513 shdr.sh_offset + existing_size,
548514 shdr.sh_offset + sh_size,
test/link/elf.zig+2
......@@ -55,6 +55,7 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step {
5555
5656 // Exercise linker in ar mode
5757 elf_step.dependOn(testEmitStaticLib(b, .{ .target = musl_target }));
58 elf_step.dependOn(testEmitStaticLibZig(b, .{ .target = musl_target }));
5859
5960 // Exercise linker with LLVM backend
6061 // musl tests
......@@ -66,6 +67,7 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step {
6667 elf_step.dependOn(testEmptyObject(b, .{ .target = musl_target }));
6768 elf_step.dependOn(testEntryPoint(b, .{ .target = musl_target }));
6869 elf_step.dependOn(testGcSections(b, .{ .target = musl_target }));
70 elf_step.dependOn(testGcSectionsZig(b, .{ .target = musl_target }));
6971 elf_step.dependOn(testImageBase(b, .{ .target = musl_target }));
7072 elf_step.dependOn(testInitArrayOrder(b, .{ .target = musl_target }));
7173 elf_step.dependOn(testLargeAlignmentExe(b, .{ .target = musl_target }));