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...@@ -600,6 +600,7 @@ set(ZIG_STAGE2_SOURCES
600 src/link/Elf.zig600 src/link/Elf.zig
601 src/link/Elf/Archive.zig601 src/link/Elf/Archive.zig
602 src/link/Elf/Atom.zig602 src/link/Elf/Atom.zig
603 src/link/Elf/AtomList.zig
603 src/link/Elf/LdScript.zig604 src/link/Elf/LdScript.zig
604 src/link/Elf/LinkerDefined.zig605 src/link/Elf/LinkerDefined.zig
605 src/link/Elf/Object.zig606 src/link/Elf/Object.zig
src/link/Dwarf.zig+81-63
...@@ -261,7 +261,6 @@ pub const Section = struct {...@@ -261,7 +261,6 @@ pub const Section = struct {
261 index: u32,261 index: u32,
262 first: Unit.Index.Optional,262 first: Unit.Index.Optional,
263 last: Unit.Index.Optional,263 last: Unit.Index.Optional,
264 off: u64,
265 len: u64,264 len: u64,
266 units: std.ArrayListUnmanaged(Unit),265 units: std.ArrayListUnmanaged(Unit),
267266
...@@ -284,9 +283,8 @@ pub const Section = struct {...@@ -284,9 +283,8 @@ pub const Section = struct {
284 .index = std.math.maxInt(u32),283 .index = std.math.maxInt(u32),
285 .first = .none,284 .first = .none,
286 .last = .none,285 .last = .none,
287 .off = 0,
288 .len = 0,
289 .units = .{},286 .units = .{},
287 .len = 0,
290 };288 };
291289
292 fn deinit(sec: *Section, gpa: std.mem.Allocator) void {290 fn deinit(sec: *Section, gpa: std.mem.Allocator) void {
...@@ -295,6 +293,20 @@ pub const Section = struct {...@@ -295,6 +293,20 @@ pub const Section = struct {
295 sec.* = undefined;293 sec.* = undefined;
296 }294 }
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
298 fn addUnit(sec: *Section, header_len: u32, trailer_len: u32, dwarf: *Dwarf) UpdateError!Unit.Index {310 fn addUnit(sec: *Section, header_len: u32, trailer_len: u32, dwarf: *Dwarf) UpdateError!Unit.Index {
299 const unit: Unit.Index = @enumFromInt(sec.units.items.len);311 const unit: Unit.Index = @enumFromInt(sec.units.items.len);
300 const unit_ptr = try sec.units.addOne(dwarf.gpa);312 const unit_ptr = try sec.units.addOne(dwarf.gpa);
...@@ -306,9 +318,9 @@ pub const Section = struct {...@@ -306,9 +318,9 @@ pub const Section = struct {
306 .next = .none,318 .next = .none,
307 .first = .none,319 .first = .none,
308 .last = .none,320 .last = .none,
309 .off = 0,
310 .header_len = aligned_header_len,321 .header_len = aligned_header_len,
311 .trailer_len = aligned_trailer_len,322 .trailer_len = aligned_trailer_len,
323 .off = 0,
312 .len = aligned_header_len + aligned_trailer_len,324 .len = aligned_header_len + aligned_trailer_len,
313 .entries = .{},325 .entries = .{},
314 .cross_unit_relocs = .{},326 .cross_unit_relocs = .{},
...@@ -375,12 +387,16 @@ pub const Section = struct {...@@ -375,12 +387,16 @@ pub const Section = struct {
375 fn resize(sec: *Section, dwarf: *Dwarf, len: u64) UpdateError!void {387 fn resize(sec: *Section, dwarf: *Dwarf, len: u64) UpdateError!void {
376 if (len <= sec.len) return;388 if (len <= sec.len) return;
377 if (dwarf.bin_file.cast(.elf)) |elf_file| {389 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;
378 if (sec == &dwarf.debug_frame.section)393 if (sec == &dwarf.debug_frame.section)
379 try elf_file.growAllocSection(sec.index, len)394 try elf_file.growAllocSection(shndx, len, sec.alignment.toByteUnits().?)
380 else395 else
381 try elf_file.growNonAllocSection(sec.index, len, @intCast(sec.alignment.toByteUnits().?), true);396 try elf_file.growNonAllocSection(shndx, len, sec.alignment.toByteUnits().?, true);
382 const shdr = &elf_file.sections.items(.shdr)[sec.index];397 const shdr = elf_file.sections.items(.shdr)[shndx];
383 sec.off = shdr.sh_offset;398 atom.size = shdr.sh_size;
399 atom.alignment = InternPool.Alignment.fromNonzeroByteUnits(shdr.sh_addralign);
384 sec.len = shdr.sh_size;400 sec.len = shdr.sh_size;
385 } else if (dwarf.bin_file.cast(.macho)) |macho_file| {401 } else if (dwarf.bin_file.cast(.macho)) |macho_file| {
386 const header = if (macho_file.d_sym) |*d_sym| header: {402 const header = if (macho_file.d_sym) |*d_sym| header: {
...@@ -390,7 +406,6 @@ pub const Section = struct {...@@ -390,7 +406,6 @@ pub const Section = struct {
390 try macho_file.growSection(@intCast(sec.index), len);406 try macho_file.growSection(@intCast(sec.index), len);
391 break :header &macho_file.sections.items(.header)[sec.index];407 break :header &macho_file.sections.items(.header)[sec.index];
392 };408 };
393 sec.off = header.offset;
394 sec.len = header.size;409 sec.len = header.size;
395 }410 }
396 }411 }
...@@ -399,18 +414,21 @@ pub const Section = struct {...@@ -399,18 +414,21 @@ pub const Section = struct {
399 const len = sec.getUnit(sec.first.unwrap() orelse return).off;414 const len = sec.getUnit(sec.first.unwrap() orelse return).off;
400 if (len == 0) return;415 if (len == 0) return;
401 for (sec.units.items) |*unit| unit.off -= len;416 for (sec.units.items) |*unit| unit.off -= len;
402 sec.off += len;
403 sec.len -= len;417 sec.len -= len;
404 if (dwarf.bin_file.cast(.elf)) |elf_file| {418 if (dwarf.bin_file.cast(.elf)) |elf_file| {
405 const shdr = &elf_file.sections.items(.shdr)[sec.index];419 const zo = elf_file.zigObjectPtr().?;
406 shdr.sh_offset = sec.off;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;
407 shdr.sh_size = sec.len;425 shdr.sh_size = sec.len;
408 } else if (dwarf.bin_file.cast(.macho)) |macho_file| {426 } else if (dwarf.bin_file.cast(.macho)) |macho_file| {
409 const header = if (macho_file.d_sym) |*d_sym|427 const header = if (macho_file.d_sym) |*d_sym|
410 &d_sym.sections.items[sec.index]428 &d_sym.sections.items[sec.index]
411 else429 else
412 &macho_file.sections.items(.header)[sec.index];430 &macho_file.sections.items(.header)[sec.index];
413 header.offset = @intCast(sec.off);431 header.offset += @intCast(len);
414 header.size = sec.len;432 header.size = sec.len;
415 }433 }
416 }434 }
...@@ -539,9 +557,9 @@ const Unit = struct {...@@ -539,9 +557,9 @@ const Unit = struct {
539 fn move(unit: *Unit, sec: *Section, dwarf: *Dwarf, new_off: u32) UpdateError!void {557 fn move(unit: *Unit, sec: *Section, dwarf: *Dwarf, new_off: u32) UpdateError!void {
540 if (unit.off == new_off) return;558 if (unit.off == new_off) return;
541 if (try dwarf.getFile().?.copyRangeAll(559 if (try dwarf.getFile().?.copyRangeAll(
542 sec.off + unit.off,560 sec.off(dwarf) + unit.off,
543 dwarf.getFile().?,561 dwarf.getFile().?,
544 sec.off + new_off,562 sec.off(dwarf) + new_off,
545 unit.len,563 unit.len,
546 ) != unit.len) return error.InputOutput;564 ) != unit.len) return error.InputOutput;
547 unit.off = new_off;565 unit.off = new_off;
...@@ -573,7 +591,7 @@ const Unit = struct {...@@ -573,7 +591,7 @@ const Unit = struct {
573591
574 fn replaceHeader(unit: *Unit, sec: *Section, dwarf: *Dwarf, contents: []const u8) UpdateError!void {592 fn replaceHeader(unit: *Unit, sec: *Section, dwarf: *Dwarf, contents: []const u8) UpdateError!void {
575 assert(contents.len == unit.header_len);593 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);
577 }595 }
578596
579 fn writeTrailer(unit: *Unit, sec: *Section, dwarf: *Dwarf) UpdateError!void {597 fn writeTrailer(unit: *Unit, sec: *Section, dwarf: *Dwarf) UpdateError!void {
...@@ -605,7 +623,7 @@ const Unit = struct {...@@ -605,7 +623,7 @@ const Unit = struct {
605 assert(fbs.pos == extended_op_bytes + op_len_bytes);623 assert(fbs.pos == extended_op_bytes + op_len_bytes);
606 writer.writeByte(DW.LNE.padding) catch unreachable;624 writer.writeByte(DW.LNE.padding) catch unreachable;
607 assert(fbs.pos >= unit.trailer_len and fbs.pos <= len);625 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);
609 }627 }
610 var trailer = try std.ArrayList(u8).initCapacity(dwarf.gpa, len);628 var trailer = try std.ArrayList(u8).initCapacity(dwarf.gpa, len);
611 defer trailer.deinit();629 defer trailer.deinit();
...@@ -664,11 +682,11 @@ const Unit = struct {...@@ -664,11 +682,11 @@ const Unit = struct {
664 assert(trailer.items.len == unit.trailer_len);682 assert(trailer.items.len == unit.trailer_len);
665 trailer.appendNTimesAssumeCapacity(fill_byte, len - unit.trailer_len);683 trailer.appendNTimesAssumeCapacity(fill_byte, len - unit.trailer_len);
666 assert(trailer.items.len == len);684 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);
668 }686 }
669687
670 fn resolveRelocs(unit: *Unit, sec: *Section, dwarf: *Dwarf) RelocError!void {688 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;
672 for (unit.cross_unit_relocs.items) |reloc| {690 for (unit.cross_unit_relocs.items) |reloc| {
673 const target_unit = sec.getUnit(reloc.target_unit);691 const target_unit = sec.getUnit(reloc.target_unit);
674 try dwarf.resolveReloc(692 try dwarf.resolveReloc(
...@@ -755,12 +773,12 @@ const Entry = struct {...@@ -755,12 +773,12 @@ const Entry = struct {
755 dwarf.writeInt(unit_len[0..dwarf.sectionOffsetBytes()], len - dwarf.unitLengthBytes());773 dwarf.writeInt(unit_len[0..dwarf.sectionOffsetBytes()], len - dwarf.unitLengthBytes());
756 try dwarf.getFile().?.pwriteAll(774 try dwarf.getFile().?.pwriteAll(
757 unit_len[0..dwarf.sectionOffsetBytes()],775 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,
759 );777 );
760 const buf = try dwarf.gpa.alloc(u8, len - entry.len);778 const buf = try dwarf.gpa.alloc(u8, len - entry.len);
761 defer dwarf.gpa.free(buf);779 defer dwarf.gpa.free(buf);
762 @memset(buf, DW.CFA.nop);780 @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);
764 return;782 return;
765 }783 }
766 const len = unit.getEntry(entry.next.unwrap() orelse return).off - start;784 const len = unit.getEntry(entry.next.unwrap() orelse return).off - start;
...@@ -816,7 +834,7 @@ const Entry = struct {...@@ -816,7 +834,7 @@ const Entry = struct {
816 },834 },
817 } else assert(!sec.pad_to_ideal and len == 0);835 } else assert(!sec.pad_to_ideal and len == 0);
818 assert(fbs.pos <= len);836 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);
820 }838 }
821839
822 fn resize(entry_ptr: *Entry, unit: *Unit, sec: *Section, dwarf: *Dwarf, len: u32) UpdateError!void {840 fn resize(entry_ptr: *Entry, unit: *Unit, sec: *Section, dwarf: *Dwarf, len: u32) UpdateError!void {
...@@ -851,15 +869,15 @@ const Entry = struct {...@@ -851,15 +869,15 @@ const Entry = struct {
851869
852 fn replace(entry_ptr: *Entry, unit: *Unit, sec: *Section, dwarf: *Dwarf, contents: []const u8) UpdateError!void {870 fn replace(entry_ptr: *Entry, unit: *Unit, sec: *Section, dwarf: *Dwarf, contents: []const u8) UpdateError!void {
853 assert(contents.len == entry_ptr.len);871 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);
855 if (false) {873 if (false) {
856 const buf = try dwarf.gpa.alloc(u8, sec.len);874 const buf = try dwarf.gpa.alloc(u8, sec.len);
857 defer dwarf.gpa.free(buf);875 defer dwarf.gpa.free(buf);
858 _ = try dwarf.getFile().?.preadAll(buf, sec.off);876 _ = try dwarf.getFile().?.preadAll(buf, sec.off(dwarf));
859 log.info("Section{{ .first = {}, .last = {}, .off = 0x{x}, .len = 0x{x} }}", .{877 log.info("Section{{ .first = {}, .last = {}, .off = 0x{x}, .len = 0x{x} }}", .{
860 @intFromEnum(sec.first),878 @intFromEnum(sec.first),
861 @intFromEnum(sec.last),879 @intFromEnum(sec.last),
862 sec.off,880 sec.off(dwarf),
863 sec.len,881 sec.len,
864 });882 });
865 for (sec.units.items) |*unit_ptr| {883 for (sec.units.items) |*unit_ptr| {
...@@ -891,9 +909,11 @@ const Entry = struct {...@@ -891,9 +909,11 @@ const Entry = struct {
891 if (std.debug.runtime_safety) {909 if (std.debug.runtime_safety) {
892 log.err("missing {} from {s}", .{910 log.err("missing {} from {s}", .{
893 @as(Entry.Index, @enumFromInt(entry - unit.entries.items.ptr)),911 @as(Entry.Index, @enumFromInt(entry - unit.entries.items.ptr)),
894 std.mem.sliceTo(if (dwarf.bin_file.cast(.elf)) |elf_file|912 std.mem.sliceTo(if (dwarf.bin_file.cast(.elf)) |elf_file| sh_name: {
895 elf_file.shstrtab.items[elf_file.sections.items(.shdr)[sec.index].sh_name..]913 const zo = elf_file.zigObjectPtr().?;
896 else if (dwarf.bin_file.cast(.macho)) |macho_file|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|
897 if (macho_file.d_sym) |*d_sym|917 if (macho_file.d_sym) |*d_sym|
898 &d_sym.sections.items[sec.index].segname918 &d_sym.sections.items[sec.index].segname
899 else919 else
...@@ -924,7 +944,7 @@ const Entry = struct {...@@ -924,7 +944,7 @@ const Entry = struct {
924 }944 }
925945
926 fn resolveRelocs(entry: *Entry, unit: *Unit, sec: *Section, dwarf: *Dwarf) RelocError!void {946 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;
928 for (entry.cross_entry_relocs.items) |reloc| {948 for (entry.cross_entry_relocs.items) |reloc| {
929 try dwarf.resolveReloc(949 try dwarf.resolveReloc(
930 entry_off + reloc.source_off,950 entry_off + reloc.source_off,
...@@ -961,7 +981,8 @@ const Entry = struct {...@@ -961,7 +981,8 @@ const Entry = struct {
961 .none, .debug_frame => {},981 .none, .debug_frame => {},
962 .eh_frame => return if (dwarf.bin_file.cast(.elf)) |elf_file| {982 .eh_frame => return if (dwarf.bin_file.cast(.elf)) |elf_file| {
963 const zo = elf_file.zigObjectPtr().?;983 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);
965 for (entry.external_relocs.items) |reloc| {986 for (entry.external_relocs.items) |reloc| {
966 const symbol = zo.symbol(reloc.target_sym);987 const symbol = zo.symbol(reloc.target_sym);
967 try dwarf.resolveReloc(988 try dwarf.resolveReloc(
...@@ -1877,34 +1898,7 @@ pub fn init(lf: *link.File, format: DW.Format) Dwarf {...@@ -1877,34 +1898,7 @@ pub fn init(lf: *link.File, format: DW.Format) Dwarf {
1877}1898}
18781899
1879pub fn reloadSectionMetadata(dwarf: *Dwarf) void {1900pub fn reloadSectionMetadata(dwarf: *Dwarf) void {
1880 if (dwarf.bin_file.cast(.elf)) |elf_file| {1901 if (dwarf.bin_file.cast(.macho)) |macho_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| {
1908 if (macho_file.d_sym) |*d_sym| {1902 if (macho_file.d_sym) |*d_sym| {
1909 for ([_]*Section{1903 for ([_]*Section{
1910 &dwarf.debug_abbrev.section,1904 &dwarf.debug_abbrev.section,
...@@ -1927,7 +1921,6 @@ pub fn reloadSectionMetadata(dwarf: *Dwarf) void {...@@ -1927,7 +1921,6 @@ pub fn reloadSectionMetadata(dwarf: *Dwarf) void {
1927 }) |sec, sect_index| {1921 }) |sec, sect_index| {
1928 const header = &d_sym.sections.items[sect_index];1922 const header = &d_sym.sections.items[sect_index];
1929 sec.index = sect_index;1923 sec.index = sect_index;
1930 sec.off = header.offset;
1931 sec.len = header.size;1924 sec.len = header.size;
1932 }1925 }
1933 } else {1926 } else {
...@@ -1952,7 +1945,6 @@ pub fn reloadSectionMetadata(dwarf: *Dwarf) void {...@@ -1952,7 +1945,6 @@ pub fn reloadSectionMetadata(dwarf: *Dwarf) void {
1952 }) |sec, sect_index| {1945 }) |sec, sect_index| {
1953 const header = &macho_file.sections.items(.header)[sect_index];1946 const header = &macho_file.sections.items(.header)[sect_index];
1954 sec.index = sect_index;1947 sec.index = sect_index;
1955 sec.off = header.offset;
1956 sec.len = header.size;1948 sec.len = header.size;
1957 }1949 }
1958 }1950 }
...@@ -1960,6 +1952,32 @@ pub fn reloadSectionMetadata(dwarf: *Dwarf) void {...@@ -1960,6 +1952,32 @@ pub fn reloadSectionMetadata(dwarf: *Dwarf) void {
1960}1952}
19611953
1962pub fn initMetadata(dwarf: *Dwarf) UpdateError!void {1954pub 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 }
1963 dwarf.reloadSectionMetadata();1981 dwarf.reloadSectionMetadata();
19641982
1965 dwarf.debug_abbrev.section.pad_to_ideal = false;1983 dwarf.debug_abbrev.section.pad_to_ideal = false;
...@@ -2523,7 +2541,7 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool...@@ -2523,7 +2541,7 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool
2523 var abbrev_code_buf: [AbbrevCode.decl_bytes]u8 = undefined;2541 var abbrev_code_buf: [AbbrevCode.decl_bytes]u8 = undefined;
2524 if (try dwarf.getFile().?.preadAll(2542 if (try dwarf.getFile().?.preadAll(
2525 &abbrev_code_buf,2543 &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,
2527 ) != abbrev_code_buf.len) return error.InputOutput;2545 ) != abbrev_code_buf.len) return error.InputOutput;
2528 var abbrev_code_fbs = std.io.fixedBufferStream(&abbrev_code_buf);2546 var abbrev_code_fbs = std.io.fixedBufferStream(&abbrev_code_buf);
2529 const abbrev_code: AbbrevCode = @enumFromInt(2547 const abbrev_code: AbbrevCode = @enumFromInt(
...@@ -3934,7 +3952,7 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {...@@ -3934,7 +3952,7 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {
3934 if (dwarf.debug_str.section.dirty) {3952 if (dwarf.debug_str.section.dirty) {
3935 const contents = dwarf.debug_str.contents.items;3953 const contents = dwarf.debug_str.contents.items;
3936 try dwarf.debug_str.section.resize(dwarf, contents.len);3954 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));
3938 dwarf.debug_str.section.dirty = false;3956 dwarf.debug_str.section.dirty = false;
3939 }3957 }
3940 if (dwarf.debug_line.section.dirty) {3958 if (dwarf.debug_line.section.dirty) {
...@@ -4040,7 +4058,7 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {...@@ -4040,7 +4058,7 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {
4040 if (dwarf.debug_line_str.section.dirty) {4058 if (dwarf.debug_line_str.section.dirty) {
4041 const contents = dwarf.debug_line_str.contents.items;4059 const contents = dwarf.debug_line_str.contents.items;
4042 try dwarf.debug_line_str.section.resize(dwarf, contents.len);4060 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));
4044 dwarf.debug_line_str.section.dirty = false;4062 dwarf.debug_line_str.section.dirty = false;
4045 }4063 }
4046 if (dwarf.debug_loclists.section.dirty) {4064 if (dwarf.debug_loclists.section.dirty) {
src/link/Elf.zig+328-293
...@@ -54,16 +54,6 @@ shdr_table_offset: ?u64 = null,...@@ -54,16 +54,6 @@ shdr_table_offset: ?u64 = null,
54/// Same order as in the file.54/// Same order as in the file.
55phdrs: std.ArrayListUnmanaged(elf.Elf64_Phdr) = .{},55phdrs: 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
67/// Special program headers57/// Special program headers
68/// PT_PHDR58/// PT_PHDR
69phdr_table_index: ?u16 = null,59phdr_table_index: ?u16 = null,
...@@ -124,22 +114,6 @@ rela_plt: std.ArrayListUnmanaged(elf.Elf64_Rela) = .{},...@@ -124,22 +114,6 @@ rela_plt: std.ArrayListUnmanaged(elf.Elf64_Rela) = .{},
124/// Applies only to a relocatable.114/// Applies only to a relocatable.
125comdat_group_sections: std.ArrayListUnmanaged(ComdatGroupSection) = .{},115comdat_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
143copy_rel_section_index: ?u32 = null,117copy_rel_section_index: ?u32 = null,
144dynamic_section_index: ?u32 = null,118dynamic_section_index: ?u32 = null,
145dynstrtab_section_index: ?u32 = null,119dynstrtab_section_index: ?u32 = null,
...@@ -419,7 +393,8 @@ pub fn deinit(self: *Elf) void {...@@ -419,7 +393,8 @@ pub fn deinit(self: *Elf) void {
419 self.objects.deinit(gpa);393 self.objects.deinit(gpa);
420 self.shared_objects.deinit(gpa);394 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);
423 atoms.deinit(gpa);398 atoms.deinit(gpa);
424 free_list.deinit(gpa);399 free_list.deinit(gpa);
425 }400 }
...@@ -554,7 +529,7 @@ pub fn findFreeSpace(self: *Elf, object_size: u64, min_alignment: u64) !u64 {...@@ -554,7 +529,7 @@ pub fn findFreeSpace(self: *Elf, object_size: u64, min_alignment: u64) !u64 {
554 return start;529 return start;
555}530}
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 {
558 const slice = self.sections.slice();533 const slice = self.sections.slice();
559 const shdr = &slice.items(.shdr)[shdr_index];534 const shdr = &slice.items(.shdr)[shdr_index];
560 assert(shdr.sh_flags & elf.SHF_ALLOC != 0);535 assert(shdr.sh_flags & elf.SHF_ALLOC != 0);
...@@ -573,8 +548,7 @@ pub fn growAllocSection(self: *Elf, shdr_index: u32, needed_size: u64) !void {...@@ -573,8 +548,7 @@ pub fn growAllocSection(self: *Elf, shdr_index: u32, needed_size: u64) !void {
573 const existing_size = shdr.sh_size;548 const existing_size = shdr.sh_size;
574 shdr.sh_size = 0;549 shdr.sh_size = 0;
575 // Must move the entire section.550 // Must move the entire section.
576 const alignment = if (maybe_phdr) |phdr| phdr.p_align else shdr.sh_addralign;551 const new_offset = try self.findFreeSpace(needed_size, min_alignment);
577 const new_offset = try self.findFreeSpace(needed_size, alignment);
578552
579 log.debug("new '{s}' file offset 0x{x} to 0x{x}", .{553 log.debug("new '{s}' file offset 0x{x} to 0x{x}", .{
580 self.getShString(shdr.sh_name),554 self.getShString(shdr.sh_name),
...@@ -614,7 +588,7 @@ pub fn growNonAllocSection(...@@ -614,7 +588,7 @@ pub fn growNonAllocSection(
614 self: *Elf,588 self: *Elf,
615 shdr_index: u32,589 shdr_index: u32,
616 needed_size: u64,590 needed_size: u64,
617 min_alignment: u32,591 min_alignment: u64,
618 requires_file_copy: bool,592 requires_file_copy: bool,
619) !void {593) !void {
620 const shdr = &self.sections.items(.shdr)[shdr_index];594 const shdr = &self.sections.items(.shdr)[shdr_index];
...@@ -648,33 +622,124 @@ pub fn growNonAllocSection(...@@ -648,33 +622,124 @@ pub fn growNonAllocSection(
648 try self.base.file.?.setEndPos(shdr.sh_offset + needed_size);622 try self.base.file.?.setEndPos(shdr.sh_offset + needed_size);
649 }623 }
650 shdr.sh_size = needed_size;624 shdr.sh_size = needed_size;
651
652 self.markDirty(shdr_index);625 self.markDirty(shdr_index);
653}626}
654627
655pub fn markDirty(self: *Elf, shdr_index: u32) void {628pub fn markDirty(self: *Elf, shdr_index: u32) void {
656 const zig_object = self.zigObjectPtr().?;629 if (self.zigObjectPtr()) |zo| {
657 if (zig_object.dwarf) |_| {630 for ([_]?Symbol.Index{
658 if (self.debug_info_section_index.? == shdr_index) {631 zo.debug_info_index,
659 zig_object.debug_info_section_dirty = true;632 zo.debug_abbrev_index,
660 } else if (self.debug_abbrev_section_index.? == shdr_index) {633 zo.debug_aranges_index,
661 zig_object.debug_abbrev_section_dirty = true;634 zo.debug_str_index,
662 } else if (self.debug_str_section_index.? == shdr_index) {635 zo.debug_line_index,
663 zig_object.debug_str_section_dirty = true;636 zo.debug_line_str_index,
664 } else if (self.debug_aranges_section_index.? == shdr_index) {637 zo.debug_loclists_index,
665 zig_object.debug_aranges_section_dirty = true;638 zo.debug_rnglists_index,
666 } else if (self.debug_line_section_index.? == shdr_index) {639 }, [_]*bool{
667 zig_object.debug_line_section_dirty = true;640 &zo.debug_info_section_dirty,
668 } else if (self.debug_line_str_section_index.? == shdr_index) {641 &zo.debug_abbrev_section_dirty,
669 zig_object.debug_line_str_section_dirty = true;642 &zo.debug_aranges_section_dirty,
670 } else if (self.debug_loclists_section_index.? == shdr_index) {643 &zo.debug_str_section_dirty,
671 zig_object.debug_loclists_section_dirty = true;644 &zo.debug_line_section_dirty,
672 } else if (self.debug_rnglists_section_index.? == shdr_index) {645 &zo.debug_line_str_section_dirty,
673 zig_object.debug_rnglists_section_dirty = true;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 }
674 }654 }
675 }655 }
676}656}
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
678pub fn flush(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void {743pub fn flush(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void {
679 const use_lld = build_options.have_llvm and self.base.comp.config.use_lld;744 const use_lld = build_options.have_llvm and self.base.comp.config.use_lld;
680 if (use_lld) {745 if (use_lld) {
...@@ -972,14 +1037,13 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod...@@ -972,14 +1037,13 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
972 try self.initSyntheticSections();1037 try self.initSyntheticSections();
973 try self.initSpecialPhdrs();1038 try self.initSpecialPhdrs();
974 try self.sortShdrs();1039 try self.sortShdrs();
975 for (self.objects.items) |index| {1040
976 try self.file(index).?.object.addAtomsToOutputSections(self);
977 }
978 try self.sortInitFini();
979 try self.setDynamicSection(rpath_table.keys());1041 try self.setDynamicSection(rpath_table.keys());
980 self.sortDynamicSymtab();1042 self.sortDynamicSymtab();
981 try self.setHashSections();1043 try self.setHashSections();
982 try self.setVersionSymtab();1044 try self.setVersionSymtab();
1045
1046 try self.sortInitFini();
983 try self.updateMergeSectionSizes();1047 try self.updateMergeSectionSizes();
984 try self.updateSectionSizes();1048 try self.updateSectionSizes();
9851049
...@@ -1010,7 +1074,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod...@@ -1010,7 +1074,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
1010 if (shdr.sh_type == elf.SHT_NOBITS) continue;1074 if (shdr.sh_type == elf.SHT_NOBITS) continue;
1011 const code = try zo.codeAlloc(self, atom_index);1075 const code = try zo.codeAlloc(self, atom_index);
1012 defer gpa.free(code);1076 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);
1014 atom_ptr.resolveRelocsAlloc(self, code) catch |err| switch (err) {1078 atom_ptr.resolveRelocsAlloc(self, code) catch |err| switch (err) {
1015 error.RelocFailure, error.RelaxFailure => has_reloc_errors = true,1079 error.RelocFailure, error.RelaxFailure => has_reloc_errors = true,
1016 error.UnsupportedCpuArch => {1080 error.UnsupportedCpuArch => {
...@@ -1750,6 +1814,59 @@ fn scanRelocs(self: *Elf) !void {...@@ -1750,6 +1814,59 @@ fn scanRelocs(self: *Elf) !void {
1750 }1814 }
1751}1815}
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
1753fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) !void {1870fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) !void {
1754 dev.check(.lld_linker);1871 dev.check(.lld_linker);
17551872
...@@ -2783,12 +2900,16 @@ fn initSyntheticSections(self: *Elf) !void {...@@ -2783,12 +2900,16 @@ fn initSyntheticSections(self: *Elf) !void {
2783 const target = self.getTarget();2900 const target = self.getTarget();
2784 const ptr_size = self.ptrWidthBytes();2901 const ptr_size = self.ptrWidthBytes();
27852902
2786 const needs_eh_frame = for (self.objects.items) |index| {2903 const needs_eh_frame = blk: {
2787 if (self.file(index).?.object.cies.items.len > 0) break true;2904 if (self.zigObjectPtr()) |zo|
2788 } else false;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 };
2789 if (needs_eh_frame) {2910 if (needs_eh_frame) {
2790 if (self.eh_frame_section_index == null) {2911 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(.{
2792 .name = try self.insertShString(".eh_frame"),2913 .name = try self.insertShString(".eh_frame"),
2793 .type = if (target.cpu.arch == .x86_64)2914 .type = if (target.cpu.arch == .x86_64)
2794 elf.SHT_X86_64_UNWIND2915 elf.SHT_X86_64_UNWIND
...@@ -3084,8 +3205,9 @@ fn sortInitFini(self: *Elf) !void {...@@ -3084,8 +3205,9 @@ fn sortInitFini(self: *Elf) !void {
3084 }3205 }
3085 };3206 };
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| {
3088 if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue;3209 if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue;
3210 if (atom_list.atoms.items.len == 0) continue;
30893211
3090 var is_init_fini = false;3212 var is_init_fini = false;
3091 var is_ctor_dtor = false;3213 var is_ctor_dtor = false;
...@@ -3099,15 +3221,13 @@ fn sortInitFini(self: *Elf) !void {...@@ -3099,15 +3221,13 @@ fn sortInitFini(self: *Elf) !void {
3099 is_ctor_dtor = mem.indexOf(u8, name, ".ctors") != null or mem.indexOf(u8, name, ".dtors") != null;3221 is_ctor_dtor = mem.indexOf(u8, name, ".ctors") != null or mem.indexOf(u8, name, ".dtors") != null;
3100 },3222 },
3101 }3223 }
3102
3103 if (!is_init_fini and !is_ctor_dtor) continue;3224 if (!is_init_fini and !is_ctor_dtor) continue;
3104 if (atom_list.items.len == 0) continue;
31053225
3106 var entries = std.ArrayList(Entry).init(gpa);3226 var entries = std.ArrayList(Entry).init(gpa);
3107 try entries.ensureTotalCapacityPrecise(atom_list.items.len);3227 try entries.ensureTotalCapacityPrecise(atom_list.atoms.items.len);
3108 defer entries.deinit();3228 defer entries.deinit();
31093229
3110 for (atom_list.items) |ref| {3230 for (atom_list.atoms.items) |ref| {
3111 const atom_ptr = self.atom(ref).?;3231 const atom_ptr = self.atom(ref).?;
3112 const object = atom_ptr.file(self).?.object;3232 const object = atom_ptr.file(self).?.object;
3113 const priority = blk: {3233 const priority = blk: {
...@@ -3126,9 +3246,9 @@ fn sortInitFini(self: *Elf) !void {...@@ -3126,9 +3246,9 @@ fn sortInitFini(self: *Elf) !void {
31263246
3127 mem.sort(Entry, entries.items, self, Entry.lessThan);3247 mem.sort(Entry, entries.items, self, Entry.lessThan);
31283248
3129 atom_list.clearRetainingCapacity();3249 atom_list.atoms.clearRetainingCapacity();
3130 for (entries.items) |entry| {3250 for (entries.items) |entry| {
3131 atom_list.appendAssumeCapacity(entry.atom_ref);3251 atom_list.atoms.appendAssumeCapacity(entry.atom_ref);
3132 }3252 }
3133 }3253 }
3134}3254}
...@@ -3233,9 +3353,6 @@ fn sortPhdrs(self: *Elf) error{OutOfMemory}!void {...@@ -3233,9 +3353,6 @@ fn sortPhdrs(self: *Elf) error{OutOfMemory}!void {
3233 }3353 }
32343354
3235 for (&[_]*?u16{3355 for (&[_]*?u16{
3236 &self.phdr_zig_load_re_index,
3237 &self.phdr_zig_load_ro_index,
3238 &self.phdr_zig_load_zerofill_index,
3239 &self.phdr_table_index,3356 &self.phdr_table_index,
3240 &self.phdr_table_load_index,3357 &self.phdr_table_load_index,
3241 &self.phdr_interp_index,3358 &self.phdr_interp_index,
...@@ -3272,33 +3389,36 @@ fn shdrRank(self: *Elf, shndx: u32) u8 {...@@ -3272,33 +3389,36 @@ fn shdrRank(self: *Elf, shndx: u32) u8 {
3272 elf.SHT_PREINIT_ARRAY,3389 elf.SHT_PREINIT_ARRAY,
3273 elf.SHT_INIT_ARRAY,3390 elf.SHT_INIT_ARRAY,
3274 elf.SHT_FINI_ARRAY,3391 elf.SHT_FINI_ARRAY,
3275 => return 0xf2,3392 => return 0xf1,
32763393
3277 elf.SHT_DYNAMIC => return 0xf3,3394 elf.SHT_DYNAMIC => return 0xf2,
32783395
3279 elf.SHT_RELA, elf.SHT_GROUP => return 0xf,3396 elf.SHT_RELA, elf.SHT_GROUP => return 0xf,
32803397
3281 elf.SHT_PROGBITS => if (flags & elf.SHF_ALLOC != 0) {3398 elf.SHT_PROGBITS => if (flags & elf.SHF_ALLOC != 0) {
3282 if (flags & elf.SHF_EXECINSTR != 0) {3399 if (flags & elf.SHF_EXECINSTR != 0) {
3283 return 0xf1;3400 return 0xf0;
3284 } else if (flags & elf.SHF_WRITE != 0) {3401 } 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;
3286 } else if (mem.eql(u8, name, ".interp")) {3403 } else if (mem.eql(u8, name, ".interp")) {
3287 return 1;3404 return 1;
3405 } else if (mem.startsWith(u8, name, ".eh_frame")) {
3406 return 0xe1;
3288 } else {3407 } else {
3289 return 0xf0;3408 return 0xe0;
3290 }3409 }
3291 } else {3410 } else {
3292 if (mem.startsWith(u8, name, ".debug")) {3411 if (mem.startsWith(u8, name, ".debug")) {
3293 return 0xf8;3412 return 0xf7;
3294 } else {3413 } else {
3295 return 0xf9;3414 return 0xf8;
3296 }3415 }
3297 },3416 },
3417 elf.SHT_X86_64_UNWIND => return 0xe1,
32983418
3299 elf.SHT_NOBITS => return if (flags & elf.SHF_TLS != 0) 0xf5 else 0xf7,3419 elf.SHT_NOBITS => return if (flags & elf.SHF_TLS != 0) 0xf4 else 0xf6,
3300 elf.SHT_SYMTAB => return 0xfa,3420 elf.SHT_SYMTAB => return 0xf9,
3301 elf.SHT_STRTAB => return if (mem.eql(u8, name, ".dynstr")) 0x4 else 0xfb,3421 elf.SHT_STRTAB => return if (mem.eql(u8, name, ".dynstr")) 0x4 else 0xfa,
3302 else => return 0xff,3422 else => return 0xff,
3303 }3423 }
3304}3424}
...@@ -3361,18 +3481,6 @@ fn resetShdrIndexes(self: *Elf, backlinks: []const u32) void {...@@ -3361,18 +3481,6 @@ fn resetShdrIndexes(self: *Elf, backlinks: []const u32) void {
3361 &self.copy_rel_section_index,3481 &self.copy_rel_section_index,
3362 &self.versym_section_index,3482 &self.versym_section_index,
3363 &self.verneed_section_index,3483 &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,
3376 }) |maybe_index| {3484 }) |maybe_index| {
3377 if (maybe_index.*) |*index| {3485 if (maybe_index.*) |*index| {
3378 index.* = backlinks[index.*];3486 index.* = backlinks[index.*];
...@@ -3383,13 +3491,19 @@ fn resetShdrIndexes(self: *Elf, backlinks: []const u32) void {...@@ -3383,13 +3491,19 @@ fn resetShdrIndexes(self: *Elf, backlinks: []const u32) void {
3383 msec.output_section_index = backlinks[msec.output_section_index];3491 msec.output_section_index = backlinks[msec.output_section_index];
3384 }3492 }
33853493
3386 for (self.sections.items(.shdr)) |*shdr| {3494 const slice = self.sections.slice();
3387 if (shdr.sh_type != elf.SHT_RELA) continue;3495 for (slice.items(.shdr), slice.items(.atom_list_2)) |*shdr, *atom_list| {
3388 // FIXME:JK we should spin up .symtab potentially earlier, or set all non-dynamic RELA sections3496 atom_list.output_section_index = backlinks[atom_list.output_section_index];
3389 // to point at symtab3497 for (atom_list.atoms.items) |ref| {
3390 // shdr.sh_link = backlinks[shdr.sh_link];3498 self.atom(ref).?.output_section_index = atom_list.output_section_index;
3391 shdr.sh_link = self.symtab_section_index.?;3499 }
3392 shdr.sh_info = backlinks[shdr.sh_info];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 }
3393 }3507 }
33943508
3395 if (self.zigObjectPtr()) |zo| {3509 if (self.zigObjectPtr()) |zo| {
...@@ -3397,7 +3511,6 @@ fn resetShdrIndexes(self: *Elf, backlinks: []const u32) void {...@@ -3397,7 +3511,6 @@ fn resetShdrIndexes(self: *Elf, backlinks: []const u32) void {
3397 const atom_ptr = zo.atom(atom_index) orelse continue;3511 const atom_ptr = zo.atom(atom_index) orelse continue;
3398 atom_ptr.output_section_index = backlinks[atom_ptr.output_section_index];3512 atom_ptr.output_section_index = backlinks[atom_ptr.output_section_index];
3399 }3513 }
3400 if (zo.dwarf) |*dwarf| dwarf.reloadSectionMetadata();
3401 }3514 }
34023515
3403 for (self.comdat_group_sections.items) |*cg| {3516 for (self.comdat_group_sections.items) |*cg| {
...@@ -3405,53 +3518,53 @@ fn resetShdrIndexes(self: *Elf, backlinks: []const u32) void {...@@ -3405,53 +3518,53 @@ fn resetShdrIndexes(self: *Elf, backlinks: []const u32) void {
3405 }3518 }
34063519
3407 if (self.symtab_section_index) |index| {3520 if (self.symtab_section_index) |index| {
3408 const shdr = &self.sections.items(.shdr)[index];3521 const shdr = &slice.items(.shdr)[index];
3409 shdr.sh_link = self.strtab_section_index.?;3522 shdr.sh_link = self.strtab_section_index.?;
3410 }3523 }
34113524
3412 if (self.dynamic_section_index) |index| {3525 if (self.dynamic_section_index) |index| {
3413 const shdr = &self.sections.items(.shdr)[index];3526 const shdr = &slice.items(.shdr)[index];
3414 shdr.sh_link = self.dynstrtab_section_index.?;3527 shdr.sh_link = self.dynstrtab_section_index.?;
3415 }3528 }
34163529
3417 if (self.dynsymtab_section_index) |index| {3530 if (self.dynsymtab_section_index) |index| {
3418 const shdr = &self.sections.items(.shdr)[index];3531 const shdr = &slice.items(.shdr)[index];
3419 shdr.sh_link = self.dynstrtab_section_index.?;3532 shdr.sh_link = self.dynstrtab_section_index.?;
3420 }3533 }
34213534
3422 if (self.hash_section_index) |index| {3535 if (self.hash_section_index) |index| {
3423 const shdr = &self.sections.items(.shdr)[index];3536 const shdr = &slice.items(.shdr)[index];
3424 shdr.sh_link = self.dynsymtab_section_index.?;3537 shdr.sh_link = self.dynsymtab_section_index.?;
3425 }3538 }
34263539
3427 if (self.gnu_hash_section_index) |index| {3540 if (self.gnu_hash_section_index) |index| {
3428 const shdr = &self.sections.items(.shdr)[index];3541 const shdr = &slice.items(.shdr)[index];
3429 shdr.sh_link = self.dynsymtab_section_index.?;3542 shdr.sh_link = self.dynsymtab_section_index.?;
3430 }3543 }
34313544
3432 if (self.versym_section_index) |index| {3545 if (self.versym_section_index) |index| {
3433 const shdr = &self.sections.items(.shdr)[index];3546 const shdr = &slice.items(.shdr)[index];
3434 shdr.sh_link = self.dynsymtab_section_index.?;3547 shdr.sh_link = self.dynsymtab_section_index.?;
3435 }3548 }
34363549
3437 if (self.verneed_section_index) |index| {3550 if (self.verneed_section_index) |index| {
3438 const shdr = &self.sections.items(.shdr)[index];3551 const shdr = &slice.items(.shdr)[index];
3439 shdr.sh_link = self.dynstrtab_section_index.?;3552 shdr.sh_link = self.dynstrtab_section_index.?;
3440 }3553 }
34413554
3442 if (self.rela_dyn_section_index) |index| {3555 if (self.rela_dyn_section_index) |index| {
3443 const shdr = &self.sections.items(.shdr)[index];3556 const shdr = &slice.items(.shdr)[index];
3444 shdr.sh_link = self.dynsymtab_section_index orelse 0;3557 shdr.sh_link = self.dynsymtab_section_index orelse 0;
3445 }3558 }
34463559
3447 if (self.rela_plt_section_index) |index| {3560 if (self.rela_plt_section_index) |index| {
3448 const shdr = &self.sections.items(.shdr)[index];3561 const shdr = &slice.items(.shdr)[index];
3449 shdr.sh_link = self.dynsymtab_section_index.?;3562 shdr.sh_link = self.dynsymtab_section_index.?;
3450 shdr.sh_info = self.plt_section_index.?;3563 shdr.sh_info = self.plt_section_index.?;
3451 }3564 }
34523565
3453 if (self.eh_frame_rela_section_index) |index| {3566 if (self.eh_frame_rela_section_index) |index| {
3454 const shdr = &self.sections.items(.shdr)[index];3567 const shdr = &slice.items(.shdr)[index];
3455 shdr.sh_link = self.symtab_section_index.?;3568 shdr.sh_link = self.symtab_section_index.?;
3456 shdr.sh_info = self.eh_frame_section_index.?;3569 shdr.sh_info = self.eh_frame_section_index.?;
3457 }3570 }
...@@ -3459,37 +3572,32 @@ fn resetShdrIndexes(self: *Elf, backlinks: []const u32) void {...@@ -3459,37 +3572,32 @@ fn resetShdrIndexes(self: *Elf, backlinks: []const u32) void {
34593572
3460fn updateSectionSizes(self: *Elf) !void {3573fn updateSectionSizes(self: *Elf) !void {
3461 const slice = self.sections.slice();3574 const slice = self.sections.slice();
3462 for (slice.items(.shdr), slice.items(.atom_list)) |*shdr, atom_list| {3575 for (slice.items(.shdr), slice.items(.atom_list_2)) |shdr, *atom_list| {
3463 if (atom_list.items.len == 0) continue;3576 if (atom_list.atoms.items.len == 0) continue;
3464 if (self.requiresThunks() and shdr.sh_flags & elf.SHF_EXECINSTR != 0) continue;3577 if (self.requiresThunks() and shdr.sh_flags & elf.SHF_EXECINSTR != 0) continue;
3465 for (atom_list.items) |ref| {3578 atom_list.updateSize(self);
3466 const atom_ptr = self.atom(ref) orelse continue;3579 try atom_list.allocate(self);
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 }
3474 }3580 }
34753581
3476 if (self.requiresThunks()) {3582 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| {
3478 if (shdr.sh_flags & elf.SHF_EXECINSTR == 0) continue;3584 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
3481 // Create jump/branch range extenders if needed.3587 // 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;
3483 }3595 }
3484 }3596 }
34853597
3486 const shdrs = slice.items(.shdr);3598 const shdrs = slice.items(.shdr);
3487 if (self.eh_frame_section_index) |index| {3599 if (self.eh_frame_section_index) |index| {
3488 shdrs[index].sh_size = existing_size: {3600 shdrs[index].sh_size = try eh_frame.calcEhFrameSize(self);
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);
3493 }3601 }
34943602
3495 if (self.eh_frame_hdr_section_index) |index| {3603 if (self.eh_frame_hdr_section_index) |index| {
...@@ -3587,13 +3695,11 @@ fn shdrToPhdrFlags(sh_flags: u64) u32 {...@@ -3587,13 +3695,11 @@ fn shdrToPhdrFlags(sh_flags: u64) u32 {
3587/// (This is an upper bound so that we can reserve enough space for the header and progam header3695/// (This is an upper bound so that we can reserve enough space for the header and progam header
3588/// table without running out of space and being forced to move things around.)3696/// table without running out of space and being forced to move things around.)
3589fn getMaxNumberOfPhdrs() u64 {3697fn getMaxNumberOfPhdrs() u64 {
3590 // First, assume we compile Zig's source incrementally, this gives us:3698 // The estimated maximum number of segments the linker can emit for input sections are:
3591 var num: u64 = number_of_zig_segments;3699 var num: u64 = max_number_of_object_segments;
3592 // Next, the estimated maximum number of segments the linker can emit for input sections are:3700 // Any other non-loadable program headers, including TLS, DYNAMIC, GNU_STACK, GNU_EH_FRAME, INTERP:
3593 num += max_number_of_object_segments;
3594 // Next, any other non-loadable program headers, including TLS, DYNAMIC, GNU_STACK, GNU_EH_FRAME, INTERP:
3595 num += max_number_of_special_phdrs;3701 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:
3597 num += 2;3703 num += 2;
3598 return num;3704 return num;
3599}3705}
...@@ -3603,10 +3709,9 @@ fn getMaxNumberOfPhdrs() u64 {...@@ -3603,10 +3709,9 @@ fn getMaxNumberOfPhdrs() u64 {
3603/// We permit a maximum of 3**2 number of segments.3709/// We permit a maximum of 3**2 number of segments.
3604fn calcNumberOfSegments(self: *Elf) usize {3710fn calcNumberOfSegments(self: *Elf) usize {
3605 var covers: [9]bool = [_]bool{false} ** 9;3711 var covers: [9]bool = [_]bool{false} ** 9;
3606 for (self.sections.items(.shdr), 0..) |shdr, shndx| {3712 for (self.sections.items(.shdr)) |shdr| {
3607 if (shdr.sh_type == elf.SHT_NULL) continue;3713 if (shdr.sh_type == elf.SHT_NULL) continue;
3608 if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue;3714 if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue;
3609 if (self.isZigSection(@intCast(shndx))) continue;
3610 const flags = shdrToPhdrFlags(shdr.sh_flags);3715 const flags = shdrToPhdrFlags(shdr.sh_flags);
3611 covers[flags - 1] = true;3716 covers[flags - 1] = true;
3612 }3717 }
...@@ -3704,7 +3809,6 @@ pub fn allocateAllocSections(self: *Elf) !void {...@@ -3704,7 +3809,6 @@ pub fn allocateAllocSections(self: *Elf) !void {
3704 for (slice.items(.shdr), 0..) |shdr, shndx| {3809 for (slice.items(.shdr), 0..) |shdr, shndx| {
3705 if (shdr.sh_type == elf.SHT_NULL) continue;3810 if (shdr.sh_type == elf.SHT_NULL) continue;
3706 if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue;3811 if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue;
3707 if (self.isZigSection(@intCast(shndx))) continue;
3708 const flags = shdrToPhdrFlags(shdr.sh_flags);3812 const flags = shdrToPhdrFlags(shdr.sh_flags);
3709 try covers[flags - 1].append(@intCast(shndx));3813 try covers[flags - 1].append(@intCast(shndx));
3710 }3814 }
...@@ -3794,10 +3898,20 @@ pub fn allocateAllocSections(self: *Elf) !void {...@@ -3794,10 +3898,20 @@ pub fn allocateAllocSections(self: *Elf) !void {
3794 }3898 }
3795 new_offset = alignment.@"align"(shndx, shdr.sh_addralign, new_offset);3899 new_offset = alignment.@"align"(shndx, shdr.sh_addralign, new_offset);
37963900
3797 if (shndx == self.eh_frame_section_index) eh_frame: {3901 if (self.zigObjectPtr()) |zo| blk: {
3798 const zo = self.zigObjectPtr() orelse break :eh_frame;3902 const existing_size = for ([_]?Symbol.Index{
3799 const sym = zo.symbol(zo.eh_frame_index orelse break :eh_frame);3903 zo.text_index,
3800 const existing_size = sym.atom(self).?.size;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;
3801 log.debug("moving {s} from 0x{x} to 0x{x}", .{3915 log.debug("moving {s} from 0x{x} to 0x{x}", .{
3802 self.getShString(shdr.sh_name),3916 self.getShString(shdr.sh_name),
3803 shdr.sh_offset,3917 shdr.sh_offset,
...@@ -3830,27 +3944,27 @@ pub fn allocateNonAllocSections(self: *Elf) !void {...@@ -3830,27 +3944,27 @@ pub fn allocateNonAllocSections(self: *Elf) !void {
3830 shdr.sh_size = 0;3944 shdr.sh_size = 0;
3831 const new_offset = try self.findFreeSpace(needed_size, shdr.sh_addralign);3945 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;
3834 log.debug("moving {s} from 0x{x} to 0x{x}", .{3963 log.debug("moving {s} from 0x{x} to 0x{x}", .{
3835 self.getShString(shdr.sh_name),3964 self.getShString(shdr.sh_name),
3836 shdr.sh_offset,3965 shdr.sh_offset,
3837 new_offset,3966 new_offset,
3838 });3967 });
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;
3854 const amt = try self.base.file.?.copyRangeAll(3968 const amt = try self.base.file.?.copyRangeAll(
3855 shdr.sh_offset,3969 shdr.sh_offset,
3856 self.base.file.?,3970 self.base.file.?,
...@@ -3934,91 +4048,28 @@ fn writeAtoms(self: *Elf) !void {...@@ -3934,91 +4048,28 @@ fn writeAtoms(self: *Elf) !void {
3934 undefs.deinit();4048 undefs.deinit();
3935 }4049 }
39364050
3937 var has_reloc_errors = false;4051 var buffer = std.ArrayList(u8).init(gpa);
4052 defer buffer.deinit();
4053
3938 const slice = self.sections.slice();4054 const slice = self.sections.slice();
3939 for (slice.items(.shdr), slice.items(.atom_list), 0..) |shdr, atom_list, shndx| {4055 var has_reloc_errors = false;
3940 if (shdr.sh_type == elf.SHT_NULL) continue;4056 for (slice.items(.shdr), slice.items(.atom_list_2)) |shdr, atom_list| {
3941 if (shdr.sh_type == elf.SHT_NOBITS) continue;4057 if (shdr.sh_type == elf.SHT_NOBITS) continue;
3942 if (atom_list.items.len == 0) continue;4058 if (atom_list.atoms.items.len == 0) continue;
39434059 atom_list.write(&buffer, &undefs, self) catch |err| switch (err) {
3944 log.debug("writing atoms in '{s}' section", .{self.getShString(shdr.sh_name)});4060 error.UnsupportedCpuArch => {
39454061 try self.reportUnsupportedCpuArch();
3946 // TODO really, really handle debug section separately4062 return error.FlushFailure;
3947 const base_offset = if (self.isDebugSection(@intCast(shndx))) base_offset: {4063 },
3948 const zo = self.zigObjectPtr().?;4064 error.RelocFailure, error.RelaxFailure => has_reloc_errors = true,
3949 for ([_]Symbol.Index{4065 else => |e| return e,
3950 zo.debug_info_index.?,4066 };
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);
4016 }4067 }
40174068
4018 if (self.requiresThunks()) {4069 try self.reportUndefinedSymbols(&undefs);
4019 var buffer = std.ArrayList(u8).init(gpa);4070 if (has_reloc_errors) return error.FlushFailure;
4020 defer buffer.deinit();
40214071
4072 if (self.requiresThunks()) {
4022 for (self.thunks.items) |th| {4073 for (self.thunks.items) |th| {
4023 const thunk_size = th.size(self);4074 const thunk_size = th.size(self);
4024 try buffer.ensureUnusedCapacity(thunk_size);4075 try buffer.ensureUnusedCapacity(thunk_size);
...@@ -4030,10 +4081,6 @@ fn writeAtoms(self: *Elf) !void {...@@ -4030,10 +4081,6 @@ fn writeAtoms(self: *Elf) !void {
4030 buffer.clearRetainingCapacity();4081 buffer.clearRetainingCapacity();
4031 }4082 }
4032 }4083 }
4033
4034 try self.reportUndefinedSymbols(&undefs);
4035
4036 if (has_reloc_errors) return error.FlushFailure;
4037}4084}
40384085
4039pub fn updateSymtabSize(self: *Elf) !void {4086pub fn updateSymtabSize(self: *Elf) !void {
...@@ -4667,34 +4714,6 @@ pub fn isEffectivelyDynLib(self: Elf) bool {...@@ -4667,34 +4714,6 @@ pub fn isEffectivelyDynLib(self: Elf) bool {
4667 };4714 };
4668}4715}
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
4698pub fn addPhdr(self: *Elf, opts: struct {4717pub fn addPhdr(self: *Elf, opts: struct {
4699 type: u32 = 0,4718 type: u32 = 0,
4700 flags: u32 = 0,4719 flags: u32 = 0,
...@@ -5070,7 +5089,7 @@ fn reportMissingLibraryError(...@@ -5070,7 +5089,7 @@ fn reportMissingLibraryError(
5070 }5089 }
5071}5090}
50725091
5073pub fn reportUnsupportedCpuArch(self: *Elf) error{OutOfMemory}!void {5092fn reportUnsupportedCpuArch(self: *Elf) error{OutOfMemory}!void {
5074 var err = try self.base.addErrorWithNotes(0);5093 var err = try self.base.addErrorWithNotes(0);
5075 try err.addMsg("fatal linker error: unsupported CPU architecture {s}", .{5094 try err.addMsg("fatal linker error: unsupported CPU architecture {s}", .{
5076 @tagName(self.getTarget().cpu.arch),5095 @tagName(self.getTarget().cpu.arch),
...@@ -5282,6 +5301,14 @@ fn fmtDumpState(...@@ -5282,6 +5301,14 @@ fn fmtDumpState(
5282 try writer.print("{}\n", .{linker_defined.fmtSymtab(self)});5301 try writer.print("{}\n", .{linker_defined.fmtSymtab(self)});
5283 }5302 }
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
5285 if (self.requiresThunks()) {5312 if (self.requiresThunks()) {
5286 try writer.writeAll("thunks\n");5313 try writer.writeAll("thunks\n");
5287 for (self.thunks.items, 0..) |th, index| {5314 for (self.thunks.items, 0..) |th, index| {
...@@ -5303,7 +5330,7 @@ fn fmtDumpState(...@@ -5303,7 +5330,7 @@ fn fmtDumpState(
5303 }5330 }
53045331
5305 try writer.writeAll("\nOutput shdrs\n");5332 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| {
5307 try writer.print(" shdr({d}) : phdr({?d}) : {}\n", .{5334 try writer.print(" shdr({d}) : phdr({?d}) : {}\n", .{
5308 shndx,5335 shndx,
5309 phndx,5336 phndx,
...@@ -5373,7 +5400,6 @@ fn requiresThunks(self: Elf) bool {...@@ -5373,7 +5400,6 @@ fn requiresThunks(self: Elf) bool {
5373/// so that we reserve enough space for the program header table up-front.5400/// so that we reserve enough space for the program header table up-front.
5374/// Bump these numbers when adding or deleting a Zig specific pre-allocated segment, or adding5401/// Bump these numbers when adding or deleting a Zig specific pre-allocated segment, or adding
5375/// more special-purpose program headers.5402/// more special-purpose program headers.
5376pub const number_of_zig_segments = 4;
5377const max_number_of_object_segments = 9;5403const max_number_of_object_segments = 9;
5378const max_number_of_special_phdrs = 5;5404const max_number_of_special_phdrs = 5;
53795405
...@@ -5558,8 +5584,14 @@ const Section = struct {...@@ -5558,8 +5584,14 @@ const Section = struct {
5558 phndx: ?u32 = null,5584 phndx: ?u32 = null,
55595585
5560 /// List of atoms contributing to this section.5586 /// 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.
5561 atom_list: std.ArrayListUnmanaged(Ref) = .{},5589 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
5563 /// Index of the last allocated atom in this section.5595 /// Index of the last allocated atom in this section.
5564 last_atom: Ref = .{ .index = 0, .file = 0 },5596 last_atom: Ref = .{ .index = 0, .file = 0 },
55655597
...@@ -5588,9 +5620,10 @@ fn defaultEntrySymbolName(cpu_arch: std.Target.Cpu.Arch) []const u8 {...@@ -5588,9 +5620,10 @@ fn defaultEntrySymbolName(cpu_arch: std.Target.Cpu.Arch) []const u8 {
5588 };5620 };
5589}5621}
55905622
5591fn createThunks(elf_file: *Elf, shdr: *elf.Elf64_Shdr, shndx: u32) !void {5623fn createThunks(elf_file: *Elf, atom_list: *AtomList) !void {
5592 const gpa = elf_file.base.comp.gpa;5624 const gpa = elf_file.base.comp.gpa;
5593 const cpu_arch = elf_file.getTarget().cpu.arch;5625 const cpu_arch = elf_file.getTarget().cpu.arch;
5626
5594 // A branch will need an extender if its target is larger than5627 // A branch will need an extender if its target is larger than
5595 // `2^(jump_bits - 1) - margin` where margin is some arbitrary number.5628 // `2^(jump_bits - 1) - margin` where margin is some arbitrary number.
5596 const max_distance = switch (cpu_arch) {5629 const max_distance = switch (cpu_arch) {
...@@ -5598,36 +5631,44 @@ fn createThunks(elf_file: *Elf, shdr: *elf.Elf64_Shdr, shndx: u32) !void {...@@ -5598,36 +5631,44 @@ fn createThunks(elf_file: *Elf, shdr: *elf.Elf64_Shdr, shndx: u32) !void {
5598 .x86_64, .riscv64 => unreachable,5631 .x86_64, .riscv64 => unreachable,
5599 else => @panic("unhandled arch"),5632 else => @panic("unhandled arch"),
5600 };5633 };
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| {
5605 elf_file.atom(ref).?.value = -1;5646 elf_file.atom(ref).?.value = -1;
5606 }5647 }
56075648
5608 var i: usize = 0;5649 var i: usize = 0;
5609 while (i < atoms.len) {5650 while (i < atom_list.atoms.items.len) {
5610 const start = i;5651 const start = i;
5611 const start_atom = elf_file.atom(atoms[start]).?;5652 const start_atom = elf_file.atom(atom_list.atoms.items[start]).?;
5612 assert(start_atom.alive);5653 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);
5614 i += 1;5655 i += 1;
56155656
5616 while (i < atoms.len) : (i += 1) {5657 while (i < atom_list.atoms.items.len) : (i += 1) {
5617 const atom_ptr = elf_file.atom(atoms[i]).?;5658 const atom_ptr = elf_file.atom(atom_list.atoms.items[i]).?;
5618 assert(atom_ptr.alive);5659 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)
5620 break;5661 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);
5622 }5663 }
56235664
5624 // Insert a thunk at the group end5665 // Insert a thunk at the group end
5625 const thunk_index = try elf_file.addThunk();5666 const thunk_index = try elf_file.addThunk();
5626 const thunk_ptr = elf_file.thunk(thunk_index);5667 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
5629 // Scan relocs in the group and create trampolines for any unreachable callsite5670 // 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| {
5631 const atom_ptr = elf_file.atom(ref).?;5672 const atom_ptr = elf_file.atom(ref).?;
5632 const file_ptr = atom_ptr.file(elf_file).?;5673 const file_ptr = atom_ptr.file(elf_file).?;
5633 log.debug("atom({}) {s}", .{ ref, atom_ptr.name(elf_file) });5674 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 {...@@ -5657,18 +5698,11 @@ fn createThunks(elf_file: *Elf, shdr: *elf.Elf64_Shdr, shndx: u32) !void {
5657 atom_ptr.addExtra(.{ .thunk = thunk_index }, elf_file);5698 atom_ptr.addExtra(.{ .thunk = thunk_index }, elf_file);
5658 }5699 }
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
5662 log.debug("thunk({d}) : {}", .{ thunk_index, thunk_ptr.fmt(elf_file) });5703 log.debug("thunk({d}) : {}", .{ thunk_index, thunk_ptr.fmt(elf_file) });
5663 }5704 }
5664}5705}
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
5673const std = @import("std");5707const std = @import("std");
5674const build_options = @import("build_options");5708const build_options = @import("build_options");
...@@ -5699,6 +5733,7 @@ const Air = @import("../Air.zig");...@@ -5699,6 +5733,7 @@ const Air = @import("../Air.zig");
5699const Allocator = std.mem.Allocator;5733const Allocator = std.mem.Allocator;
5700const Archive = @import("Elf/Archive.zig");5734const Archive = @import("Elf/Archive.zig");
5701pub const Atom = @import("Elf/Atom.zig");5735pub const Atom = @import("Elf/Atom.zig");
5736const AtomList = @import("Elf/AtomList.zig");
5702const Cache = std.Build.Cache;5737const Cache = std.Build.Cache;
5703const Path = Cache.Path;5738const Path = Cache.Path;
5704const Compilation = @import("../Compilation.zig");5739const Compilation = @import("../Compilation.zig");
src/link/Elf/Atom.zig+15-144
...@@ -51,6 +51,11 @@ pub fn address(self: Atom, elf_file: *Elf) i64 {...@@ -51,6 +51,11 @@ pub fn address(self: Atom, elf_file: *Elf) i64 {
51 return @as(i64, @intCast(shdr.sh_addr)) + self.value;51 return @as(i64, @intCast(shdr.sh_addr)) + self.value;
52}52}
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
54pub fn ref(self: Atom) Elf.Ref {59pub fn ref(self: Atom) Elf.Ref {
55 return .{ .index = self.atom_index, .file = self.file_index };60 return .{ .index = self.atom_index, .file = self.file_index };
56}61}
...@@ -123,140 +128,6 @@ pub fn freeListEligible(self: Atom, elf_file: *Elf) bool {...@@ -123,140 +128,6 @@ pub fn freeListEligible(self: Atom, elf_file: *Elf) bool {
123 return surplus >= Elf.min_text_capacity;128 return surplus >= Elf.min_text_capacity;
124}129}
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
260pub fn free(self: *Atom, elf_file: *Elf) void {131pub fn free(self: *Atom, elf_file: *Elf) void {
261 log.debug("freeAtom atom({}) ({s})", .{ self.ref(), self.name(elf_file) });132 log.debug("freeAtom atom({}) ({s})", .{ self.ref(), self.name(elf_file) });
262133
...@@ -1807,7 +1678,7 @@ const aarch64 = struct {...@@ -1807,7 +1678,7 @@ const aarch64 = struct {
1807 => {1678 => {
1808 // TODO: NC means no overflow check1679 // TODO: NC means no overflow check
1809 const taddr = @as(u64, @intCast(S + A));1680 const taddr = @as(u64, @intCast(S + A));
1810 const offset: u12 = switch (r_type) {1681 const off: u12 = switch (r_type) {
1811 .LDST8_ABS_LO12_NC => @truncate(taddr),1682 .LDST8_ABS_LO12_NC => @truncate(taddr),
1812 .LDST16_ABS_LO12_NC => @divExact(@as(u12, @truncate(taddr)), 2),1683 .LDST16_ABS_LO12_NC => @divExact(@as(u12, @truncate(taddr)), 2),
1813 .LDST32_ABS_LO12_NC => @divExact(@as(u12, @truncate(taddr)), 4),1684 .LDST32_ABS_LO12_NC => @divExact(@as(u12, @truncate(taddr)), 4),
...@@ -1815,7 +1686,7 @@ const aarch64 = struct {...@@ -1815,7 +1686,7 @@ const aarch64 = struct {
1815 .LDST128_ABS_LO12_NC => @divExact(@as(u12, @truncate(taddr)), 16),1686 .LDST128_ABS_LO12_NC => @divExact(@as(u12, @truncate(taddr)), 16),
1816 else => unreachable,1687 else => unreachable,
1817 };1688 };
1818 aarch64_util.writeLoadStoreRegInst(offset, code);1689 aarch64_util.writeLoadStoreRegInst(off, code);
1819 },1690 },
18201691
1821 .TLSLE_ADD_TPREL_HI12 => {1692 .TLSLE_ADD_TPREL_HI12 => {
...@@ -1839,8 +1710,8 @@ const aarch64 = struct {...@@ -1839,8 +1710,8 @@ const aarch64 = struct {
1839 .TLSIE_LD64_GOTTPREL_LO12_NC => {1710 .TLSIE_LD64_GOTTPREL_LO12_NC => {
1840 const S_ = target.gotTpAddress(elf_file);1711 const S_ = target.gotTpAddress(elf_file);
1841 relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });1712 relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });
1842 const offset: u12 = try math.divExact(u12, @truncate(@as(u64, @bitCast(S_ + A))), 8);1713 const off: u12 = try math.divExact(u12, @truncate(@as(u64, @bitCast(S_ + A))), 8);
1843 aarch64_util.writeLoadStoreRegInst(offset, code);1714 aarch64_util.writeLoadStoreRegInst(off, code);
1844 },1715 },
18451716
1846 .TLSGD_ADR_PAGE21 => {1717 .TLSGD_ADR_PAGE21 => {
...@@ -1853,8 +1724,8 @@ const aarch64 = struct {...@@ -1853,8 +1724,8 @@ const aarch64 = struct {
1853 .TLSGD_ADD_LO12_NC => {1724 .TLSGD_ADD_LO12_NC => {
1854 const S_ = target.tlsGdAddress(elf_file);1725 const S_ = target.tlsGdAddress(elf_file);
1855 relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });1726 relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });
1856 const offset: u12 = @truncate(@as(u64, @bitCast(S_ + A)));1727 const off: u12 = @truncate(@as(u64, @bitCast(S_ + A)));
1857 aarch64_util.writeAddImmInst(offset, code);1728 aarch64_util.writeAddImmInst(off, code);
1858 },1729 },
18591730
1860 .TLSDESC_ADR_PAGE21 => {1731 .TLSDESC_ADR_PAGE21 => {
...@@ -1873,8 +1744,8 @@ const aarch64 = struct {...@@ -1873,8 +1744,8 @@ const aarch64 = struct {
1873 if (target.flags.has_tlsdesc) {1744 if (target.flags.has_tlsdesc) {
1874 const S_ = target.tlsDescAddress(elf_file);1745 const S_ = target.tlsDescAddress(elf_file);
1875 relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });1746 relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });
1876 const offset: u12 = try math.divExact(u12, @truncate(@as(u64, @bitCast(S_ + A))), 8);1747 const off: u12 = try math.divExact(u12, @truncate(@as(u64, @bitCast(S_ + A))), 8);
1877 aarch64_util.writeLoadStoreRegInst(offset, code);1748 aarch64_util.writeLoadStoreRegInst(off, code);
1878 } else {1749 } else {
1879 relocs_log.debug(" relaxing ldr => nop", .{});1750 relocs_log.debug(" relaxing ldr => nop", .{});
1880 mem.writeInt(u32, code, Instruction.nop().toU32(), .little);1751 mem.writeInt(u32, code, Instruction.nop().toU32(), .little);
...@@ -1885,8 +1756,8 @@ const aarch64 = struct {...@@ -1885,8 +1756,8 @@ const aarch64 = struct {
1885 if (target.flags.has_tlsdesc) {1756 if (target.flags.has_tlsdesc) {
1886 const S_ = target.tlsDescAddress(elf_file);1757 const S_ = target.tlsDescAddress(elf_file);
1887 relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });1758 relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });
1888 const offset: u12 = @truncate(@as(u64, @bitCast(S_ + A)));1759 const off: u12 = @truncate(@as(u64, @bitCast(S_ + A)));
1889 aarch64_util.writeAddImmInst(offset, code);1760 aarch64_util.writeAddImmInst(off, code);
1890 } else {1761 } else {
1891 const old_inst = Instruction{1762 const old_inst = Instruction{
1892 .add_subtract_immediate = mem.bytesToValue(std.meta.TagPayload(1763 .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:...@@ -311,58 +311,6 @@ fn initAtoms(self: *Object, allocator: Allocator, handle: std.fs.File, elf_file:
311 };311 };
312}312}
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
366fn skipShdr(self: *Object, index: u32, elf_file: *Elf) bool {314fn skipShdr(self: *Object, index: u32, elf_file: *Elf) bool {
367 const comp = elf_file.base.comp;315 const comp = elf_file.base.comp;
368 const shdr = self.shdrs.items[index];316 const shdr = self.shdrs.items[index];
...@@ -438,15 +386,24 @@ fn parseEhFrame(self: *Object, allocator: Allocator, handle: std.fs.File, shndx:...@@ -438,15 +386,24 @@ fn parseEhFrame(self: *Object, allocator: Allocator, handle: std.fs.File, shndx:
438 .input_section_index = shndx,386 .input_section_index = shndx,
439 .file_index = self.index,387 .file_index = self.index,
440 }),388 }),
441 .fde => try self.fdes.append(allocator, .{389 .fde => {
442 .offset = data_start + rec.offset,390 if (rel_range.len == 0) {
443 .size = rec.size,391 // No relocs for an FDE means we cannot associate this FDE to an Atom
444 .cie_index = undefined,392 // so we skip it. According to mold source code
445 .rel_index = rel_start + @as(u32, @intCast(rel_range.start)),393 // (https://github.com/rui314/mold/blob/a3e69502b0eaf1126d6093e8ea5e6fdb95219811/src/input-files.cc#L525-L528)
446 .rel_num = @as(u32, @intCast(rel_range.len)),394 // this can happen for object files built with -r flag by the linker.
447 .input_section_index = shndx,395 continue;
448 .file_index = self.index,396 }
449 }),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 },
450 }407 }
451 }408 }
452409
...@@ -622,7 +579,7 @@ pub fn claimUnresolved(self: *Object, elf_file: *Elf) void {...@@ -622,7 +579,7 @@ pub fn claimUnresolved(self: *Object, elf_file: *Elf) void {
622 }579 }
623}580}
624581
625pub fn claimUnresolvedObject(self: *Object, elf_file: *Elf) void {582pub fn claimUnresolvedRelocatable(self: *Object, elf_file: *Elf) void {
626 const first_global = self.first_global orelse return;583 const first_global = self.first_global orelse return;
627 for (self.globals(), 0..) |*sym, i| {584 for (self.globals(), 0..) |*sym, i| {
628 const esym_index = @as(u32, @intCast(first_global + i));585 const esym_index = @as(u32, @intCast(first_global + i));
...@@ -985,21 +942,14 @@ pub fn initOutputSections(self: *Object, elf_file: *Elf) !void {...@@ -985,21 +942,14 @@ pub fn initOutputSections(self: *Object, elf_file: *Elf) !void {
985 const atom_ptr = self.atom(atom_index) orelse continue;942 const atom_ptr = self.atom(atom_index) orelse continue;
986 if (!atom_ptr.alive) continue;943 if (!atom_ptr.alive) continue;
987 const shdr = atom_ptr.inputShdr(elf_file);944 const shdr = atom_ptr.inputShdr(elf_file);
988 _ = try self.initOutputSection(elf_file, shdr);945 const osec = try elf_file.initOutputSection(.{
989 }946 .name = self.getString(shdr.sh_name),
990}947 .flags = shdr.sh_flags,
991948 .type = shdr.sh_type,
992pub fn addAtomsToOutputSections(self: *Object, elf_file: *Elf) !void {949 });
993 for (self.atoms_indexes.items) |atom_index| {950 const atom_list = &elf_file.sections.items(.atom_list_2)[osec];
994 const atom_ptr = self.atom(atom_index) orelse continue;951 atom_list.output_section_index = osec;
995 if (!atom_ptr.alive) continue;952 try atom_list.atoms.append(elf_file.base.comp.gpa, atom_ptr.ref());
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 });
1003 }953 }
1004}954}
1005955
...@@ -1007,9 +957,14 @@ pub fn initRelaSections(self: *Object, elf_file: *Elf) !void {...@@ -1007,9 +957,14 @@ pub fn initRelaSections(self: *Object, elf_file: *Elf) !void {
1007 for (self.atoms_indexes.items) |atom_index| {957 for (self.atoms_indexes.items) |atom_index| {
1008 const atom_ptr = self.atom(atom_index) orelse continue;958 const atom_ptr = self.atom(atom_index) orelse continue;
1009 if (!atom_ptr.alive) continue;959 if (!atom_ptr.alive) continue;
960 if (atom_ptr.output_section_index == elf_file.eh_frame_section_index) continue;
1010 const shndx = atom_ptr.relocsShndx() orelse continue;961 const shndx = atom_ptr.relocsShndx() orelse continue;
1011 const shdr = self.shdrs.items[shndx];962 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 });
1013 const out_shdr = &elf_file.sections.items(.shdr)[out_shndx];968 const out_shdr = &elf_file.sections.items(.shdr)[out_shndx];
1014 out_shdr.sh_type = elf.SHT_RELA;969 out_shdr.sh_type = elf.SHT_RELA;
1015 out_shdr.sh_addralign = @alignOf(elf.Elf64_Rela);970 out_shdr.sh_addralign = @alignOf(elf.Elf64_Rela);
...@@ -1022,10 +977,15 @@ pub fn addAtomsToRelaSections(self: *Object, elf_file: *Elf) !void {...@@ -1022,10 +977,15 @@ pub fn addAtomsToRelaSections(self: *Object, elf_file: *Elf) !void {
1022 for (self.atoms_indexes.items) |atom_index| {977 for (self.atoms_indexes.items) |atom_index| {
1023 const atom_ptr = self.atom(atom_index) orelse continue;978 const atom_ptr = self.atom(atom_index) orelse continue;
1024 if (!atom_ptr.alive) continue;979 if (!atom_ptr.alive) continue;
980 if (atom_ptr.output_section_index == elf_file.eh_frame_section_index) continue;
1025 const shndx = blk: {981 const shndx = blk: {
1026 const shndx = atom_ptr.relocsShndx() orelse continue;982 const shndx = atom_ptr.relocsShndx() orelse continue;
1027 const shdr = self.shdrs.items[shndx];983 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;
1029 };989 };
1030 const slice = elf_file.sections.slice();990 const slice = elf_file.sections.slice();
1031 const shdr = &slice.items(.shdr)[shndx];991 const shdr = &slice.items(.shdr)[shndx];
...@@ -1538,12 +1498,12 @@ fn formatComdatGroups(...@@ -1538,12 +1498,12 @@ fn formatComdatGroups(
1538 }1498 }
1539}1499}
15401500
1541pub fn fmtPath(self: *Object) std.fmt.Formatter(formatPath) {1501pub fn fmtPath(self: Object) std.fmt.Formatter(formatPath) {
1542 return .{ .data = self };1502 return .{ .data = self };
1543}1503}
15441504
1545fn formatPath(1505fn formatPath(
1546 object: *Object,1506 object: Object,
1547 comptime unused_fmt_string: []const u8,1507 comptime unused_fmt_string: []const u8,
1548 options: std.fmt.FormatOptions,1508 options: std.fmt.FormatOptions,
1549 writer: anytype,1509 writer: anytype,
...@@ -1578,6 +1538,7 @@ const mem = std.mem;...@@ -1578,6 +1538,7 @@ const mem = std.mem;
1578const Allocator = mem.Allocator;1538const Allocator = mem.Allocator;
1579const Archive = @import("Archive.zig");1539const Archive = @import("Archive.zig");
1580const Atom = @import("Atom.zig");1540const Atom = @import("Atom.zig");
1541const AtomList = @import("AtomList.zig");
1581const Cie = eh_frame.Cie;1542const Cie = eh_frame.Cie;
1582const Elf = @import("../Elf.zig");1543const Elf = @import("../Elf.zig");
1583const Fde = eh_frame.Fde;1544const Fde = eh_frame.Fde;
src/link/Elf/ZigObject.zig+358-287
...@@ -51,6 +51,14 @@ debug_loclists_section_dirty: bool = false,...@@ -51,6 +51,14 @@ debug_loclists_section_dirty: bool = false,
51debug_rnglists_section_dirty: bool = false,51debug_rnglists_section_dirty: bool = false,
52eh_frame_section_dirty: bool = false,52eh_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,
54debug_info_index: ?Symbol.Index = null,62debug_info_index: ?Symbol.Index = null,
55debug_abbrev_index: ?Symbol.Index = null,63debug_abbrev_index: ?Symbol.Index = null,
56debug_aranges_index: ?Symbol.Index = null,64debug_aranges_index: ?Symbol.Index = null,
...@@ -59,7 +67,6 @@ debug_line_index: ?Symbol.Index = null,...@@ -59,7 +67,6 @@ debug_line_index: ?Symbol.Index = null,
59debug_line_str_index: ?Symbol.Index = null,67debug_line_str_index: ?Symbol.Index = null,
60debug_loclists_index: ?Symbol.Index = null,68debug_loclists_index: ?Symbol.Index = null,
61debug_rnglists_index: ?Symbol.Index = null,69debug_rnglists_index: ?Symbol.Index = null,
62eh_frame_index: ?Symbol.Index = null,
6370
64pub const global_symbol_bit: u32 = 0x80000000;71pub const global_symbol_bit: u32 = 0x80000000;
65pub const symbol_mask: u32 = 0x7fffffff;72pub const symbol_mask: u32 = 0x7fffffff;
...@@ -71,6 +78,7 @@ const InitOptions = struct {...@@ -71,6 +78,7 @@ const InitOptions = struct {
71};78};
7279
73pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {80pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {
81 _ = options;
74 const comp = elf_file.base.comp;82 const comp = elf_file.base.comp;
75 const gpa = comp.gpa;83 const gpa = comp.gpa;
76 const ptr_size = elf_file.ptrWidthBytes();84 const ptr_size = elf_file.ptrWidthBytes();
...@@ -88,190 +96,13 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {...@@ -88,190 +96,13 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {
88 esym.st_shndx = elf.SHN_ABS;96 esym.st_shndx = elf.SHN_ABS;
89 }97 }
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
248 switch (comp.config.debug_format) {99 switch (comp.config.debug_format) {
249 .strip => {},100 .strip => {},
250 .dwarf => |v| {101 .dwarf => |v| {
251 var dwarf = Dwarf.init(&elf_file.base, v);102 var dwarf = Dwarf.init(&elf_file.base, v);
252103
253 const addSectionSymbol = struct {104 if (self.debug_str_index == null) {
254 fn addSectionSymbol(105 const osec = try elf_file.addSection(.{
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(.{
275 .name = try elf_file.insertShString(".debug_str"),106 .name = try elf_file.insertShString(".debug_str"),
276 .flags = elf.SHF_MERGE | elf.SHF_STRINGS,107 .flags = elf.SHF_MERGE | elf.SHF_STRINGS,
277 .entsize = 1,108 .entsize = 1,
...@@ -279,51 +110,56 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {...@@ -279,51 +110,56 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {
279 .addralign = 1,110 .addralign = 1,
280 });111 });
281 self.debug_str_section_dirty = true;112 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;
283 }115 }
284116
285 if (elf_file.debug_info_section_index == null) {117 if (self.debug_info_index == null) {
286 elf_file.debug_info_section_index = try elf_file.addSection(.{118 const osec = try elf_file.addSection(.{
287 .name = try elf_file.insertShString(".debug_info"),119 .name = try elf_file.insertShString(".debug_info"),
288 .type = elf.SHT_PROGBITS,120 .type = elf.SHT_PROGBITS,
289 .addralign = 1,121 .addralign = 1,
290 });122 });
291 self.debug_info_section_dirty = true;123 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;
293 }126 }
294127
295 if (elf_file.debug_abbrev_section_index == null) {128 if (self.debug_abbrev_index == null) {
296 elf_file.debug_abbrev_section_index = try elf_file.addSection(.{129 const osec = try elf_file.addSection(.{
297 .name = try elf_file.insertShString(".debug_abbrev"),130 .name = try elf_file.insertShString(".debug_abbrev"),
298 .type = elf.SHT_PROGBITS,131 .type = elf.SHT_PROGBITS,
299 .addralign = 1,132 .addralign = 1,
300 });133 });
301 self.debug_abbrev_section_dirty = true;134 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;
303 }137 }
304138
305 if (elf_file.debug_aranges_section_index == null) {139 if (self.debug_aranges_index == null) {
306 elf_file.debug_aranges_section_index = try elf_file.addSection(.{140 const osec = try elf_file.addSection(.{
307 .name = try elf_file.insertShString(".debug_aranges"),141 .name = try elf_file.insertShString(".debug_aranges"),
308 .type = elf.SHT_PROGBITS,142 .type = elf.SHT_PROGBITS,
309 .addralign = 16,143 .addralign = 16,
310 });144 });
311 self.debug_aranges_section_dirty = true;145 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;
313 }148 }
314149
315 if (elf_file.debug_line_section_index == null) {150 if (self.debug_line_index == null) {
316 elf_file.debug_line_section_index = try elf_file.addSection(.{151 const osec = try elf_file.addSection(.{
317 .name = try elf_file.insertShString(".debug_line"),152 .name = try elf_file.insertShString(".debug_line"),
318 .type = elf.SHT_PROGBITS,153 .type = elf.SHT_PROGBITS,
319 .addralign = 1,154 .addralign = 1,
320 });155 });
321 self.debug_line_section_dirty = true;156 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;
323 }159 }
324160
325 if (elf_file.debug_line_str_section_index == null) {161 if (self.debug_line_str_index == null) {
326 elf_file.debug_line_str_section_index = try elf_file.addSection(.{162 const osec = try elf_file.addSection(.{
327 .name = try elf_file.insertShString(".debug_line_str"),163 .name = try elf_file.insertShString(".debug_line_str"),
328 .flags = elf.SHF_MERGE | elf.SHF_STRINGS,164 .flags = elf.SHF_MERGE | elf.SHF_STRINGS,
329 .entsize = 1,165 .entsize = 1,
...@@ -331,31 +167,34 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {...@@ -331,31 +167,34 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {
331 .addralign = 1,167 .addralign = 1,
332 });168 });
333 self.debug_line_str_section_dirty = true;169 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;
335 }172 }
336173
337 if (elf_file.debug_loclists_section_index == null) {174 if (self.debug_loclists_index == null) {
338 elf_file.debug_loclists_section_index = try elf_file.addSection(.{175 const osec = try elf_file.addSection(.{
339 .name = try elf_file.insertShString(".debug_loclists"),176 .name = try elf_file.insertShString(".debug_loclists"),
340 .type = elf.SHT_PROGBITS,177 .type = elf.SHT_PROGBITS,
341 .addralign = 1,178 .addralign = 1,
342 });179 });
343 self.debug_loclists_section_dirty = true;180 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;
345 }183 }
346184
347 if (elf_file.debug_rnglists_section_index == null) {185 if (self.debug_rnglists_index == null) {
348 elf_file.debug_rnglists_section_index = try elf_file.addSection(.{186 const osec = try elf_file.addSection(.{
349 .name = try elf_file.insertShString(".debug_rnglists"),187 .name = try elf_file.insertShString(".debug_rnglists"),
350 .type = elf.SHT_PROGBITS,188 .type = elf.SHT_PROGBITS,
351 .addralign = 1,189 .addralign = 1,
352 });190 });
353 self.debug_rnglists_section_dirty = true;191 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;
355 }194 }
356195
357 if (elf_file.eh_frame_section_index == null) {196 if (self.eh_frame_index == null) {
358 elf_file.eh_frame_section_index = try elf_file.addSection(.{197 const osec = try elf_file.addSection(.{
359 .name = try elf_file.insertShString(".eh_frame"),198 .name = try elf_file.insertShString(".eh_frame"),
360 .type = if (elf_file.getTarget().cpu.arch == .x86_64)199 .type = if (elf_file.getTarget().cpu.arch == .x86_64)
361 elf.SHT_X86_64_UNWIND200 elf.SHT_X86_64_UNWIND
...@@ -365,7 +204,8 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {...@@ -365,7 +204,8 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {
365 .addralign = ptr_size,204 .addralign = ptr_size,
366 });205 });
367 self.eh_frame_section_dirty = true;206 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;
369 }209 }
370210
371 try dwarf.initMetadata();211 try dwarf.initMetadata();
...@@ -404,10 +244,6 @@ pub fn deinit(self: *ZigObject, allocator: Allocator) void {...@@ -404,10 +244,6 @@ pub fn deinit(self: *ZigObject, allocator: Allocator) void {
404 meta.exports.deinit(allocator);244 meta.exports.deinit(allocator);
405 }245 }
406 self.uavs.deinit(allocator);246 self.uavs.deinit(allocator);
407
408 for (self.tls_variables.values()) |*tlv| {
409 tlv.deinit(allocator);
410 }
411 self.tls_variables.deinit(allocator);247 self.tls_variables.deinit(allocator);
412248
413 if (self.dwarf) |*dwarf| {249 if (self.dwarf) |*dwarf| {
...@@ -499,12 +335,6 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi...@@ -499,12 +335,6 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi
499 const sym = self.symbol(sym_index);335 const sym = self.symbol(sym_index);
500 const atom_ptr = self.atom(sym.ref.index).?;336 const atom_ptr = self.atom(sym.ref.index).?;
501 if (!atom_ptr.alive) continue;337 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
509 log.debug("parsing relocs in {s}", .{sym.name(elf_file)});339 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...@@ -665,14 +495,6 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi
665 }495 }
666 }496 }
667 }497 }
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 }
676 }498 }
677499
678 self.debug_abbrev_section_dirty = false;500 self.debug_abbrev_section_dirty = false;
...@@ -835,7 +657,7 @@ pub fn claimUnresolved(self: *ZigObject, elf_file: *Elf) void {...@@ -835,7 +657,7 @@ pub fn claimUnresolved(self: *ZigObject, elf_file: *Elf) void {
835 }657 }
836}658}
837659
838pub fn claimUnresolvedObject(self: ZigObject, elf_file: *Elf) void {660pub fn claimUnresolvedRelocatable(self: ZigObject, elf_file: *Elf) void {
839 for (self.global_symbols.items, 0..) |index, i| {661 for (self.global_symbols.items, 0..) |index, i| {
840 const global = &self.symbols.items[index];662 const global = &self.symbols.items[index];
841 const esym = self.symtab.items(.elf_sym)[index];663 const esym = self.symtab.items(.elf_sym)[index];
...@@ -990,21 +812,48 @@ pub fn writeAr(self: ZigObject, writer: anytype) !void {...@@ -990,21 +812,48 @@ pub fn writeAr(self: ZigObject, writer: anytype) !void {
990 try writer.writeAll(self.data.items);812 try writer.writeAll(self.data.items);
991}813}
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
993pub fn addAtomsToRelaSections(self: *ZigObject, elf_file: *Elf) !void {836pub fn addAtomsToRelaSections(self: *ZigObject, elf_file: *Elf) !void {
837 const gpa = elf_file.base.comp.gpa;
994 for (self.atoms_indexes.items) |atom_index| {838 for (self.atoms_indexes.items) |atom_index| {
995 const atom_ptr = self.atom(atom_index) orelse continue;839 const atom_ptr = self.atom(atom_index) orelse continue;
996 if (!atom_ptr.alive) continue;840 if (!atom_ptr.alive) continue;
841 if (atom_ptr.output_section_index == elf_file.eh_frame_section_index) continue;
997 const rela_shndx = atom_ptr.relocsShndx() orelse continue;842 const rela_shndx = atom_ptr.relocsShndx() orelse continue;
998 // TODO this check will become obsolete when we rework our relocs mechanism at the ZigObject level843 // TODO this check will become obsolete when we rework our relocs mechanism at the ZigObject level
999 if (self.relocs.items[rela_shndx].items.len == 0) continue;844 if (self.relocs.items[rela_shndx].items.len == 0) continue;
1000 const out_shndx = atom_ptr.output_section_index;845 const out_shndx = atom_ptr.output_section_index;
1001 const out_shdr = elf_file.sections.items(.shdr)[out_shndx];846 const out_shdr = elf_file.sections.items(.shdr)[out_shndx];
1002 if (out_shdr.sh_type == elf.SHT_NOBITS) continue;847 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| {848 const rela_sect_name = try std.fmt.allocPrintZ(gpa, ".rela{s}", .{
1004 if (out_rela_shdr.sh_type == elf.SHT_RELA and out_rela_shdr.sh_info == out_shndx) break out_rela_shndx;849 elf_file.getShString(out_shdr.sh_name),
1005 } else unreachable;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.?;
1006 const atom_list = &elf_file.sections.items(.atom_list)[out_rela_shndx];856 const atom_list = &elf_file.sections.items(.atom_list)[out_rela_shndx];
1007 const gpa = elf_file.base.comp.gpa;
1008 try atom_list.append(gpa, .{ .index = atom_index, .file = self.index });857 try atom_list.append(gpa, .{ .index = atom_index, .file = self.index });
1009 }858 }
1010}859}
...@@ -1075,15 +924,7 @@ pub fn writeSymtab(self: ZigObject, elf_file: *Elf) void {...@@ -1075,15 +924,7 @@ pub fn writeSymtab(self: ZigObject, elf_file: *Elf) void {
1075pub fn codeAlloc(self: *ZigObject, elf_file: *Elf, atom_index: Atom.Index) ![]u8 {924pub fn codeAlloc(self: *ZigObject, elf_file: *Elf, atom_index: Atom.Index) ![]u8 {
1076 const gpa = elf_file.base.comp.gpa;925 const gpa = elf_file.base.comp.gpa;
1077 const atom_ptr = self.atom(atom_index).?;926 const atom_ptr = self.atom(atom_index).?;
1078 const shdr = &elf_file.sections.items(.shdr)[atom_ptr.output_section_index];927 const file_offset = atom_ptr.offset(elf_file);
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));
1087 const size = std.math.cast(usize, atom_ptr.size) orelse return error.Overflow;928 const size = std.math.cast(usize, atom_ptr.size) orelse return error.Overflow;
1088 const code = try gpa.alloc(u8, size);929 const code = try gpa.alloc(u8, size);
1089 errdefer gpa.free(code);930 errdefer gpa.free(code);
...@@ -1168,6 +1009,20 @@ pub fn lowerUav(...@@ -1168,6 +1009,20 @@ pub fn lowerUav(
1168 return .{ .mcv = .{ .load_symbol = metadata.symbol_index } };1009 return .{ .mcv = .{ .load_symbol = metadata.symbol_index } };
1169 }1010 }
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
1171 var name_buf: [32]u8 = undefined;1026 var name_buf: [32]u8 = undefined;
1172 const name = std.fmt.bufPrint(&name_buf, "__anon_{d}", .{1027 const name = std.fmt.bufPrint(&name_buf, "__anon_{d}", .{
1173 @intFromEnum(uav),1028 @intFromEnum(uav),
...@@ -1178,7 +1033,7 @@ pub fn lowerUav(...@@ -1178,7 +1033,7 @@ pub fn lowerUav(
1178 name,1033 name,
1179 val,1034 val,
1180 uav_alignment,1035 uav_alignment,
1181 elf_file.zig_data_rel_ro_section_index.?,1036 osec,
1182 src_loc,1037 src_loc,
1183 ) catch |err| switch (err) {1038 ) catch |err| switch (err) {
1184 error.OutOfMemory => return error.OutOfMemory,1039 error.OutOfMemory => return error.OutOfMemory,
...@@ -1270,6 +1125,27 @@ pub fn getOrCreateMetadataForNav(...@@ -1270,6 +1125,27 @@ pub fn getOrCreateMetadataForNav(
1270 return gop.value_ptr.symbol_index;1125 return gop.value_ptr.symbol_index;
1271}1126}
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
1273fn getNavShdrIndex(1149fn getNavShdrIndex(
1274 self: *ZigObject,1150 self: *ZigObject,
1275 elf_file: *Elf,1151 elf_file: *Elf,
...@@ -1278,10 +1154,24 @@ fn getNavShdrIndex(...@@ -1278,10 +1154,24 @@ fn getNavShdrIndex(
1278 sym_index: Symbol.Index,1154 sym_index: Symbol.Index,
1279 code: []const u8,1155 code: []const u8,
1280) error{OutOfMemory}!u32 {1156) error{OutOfMemory}!u32 {
1157 const gpa = elf_file.base.comp.gpa;
1158 const ptr_size = elf_file.ptrWidthBytes();
1281 const ip = &zcu.intern_pool;1159 const ip = &zcu.intern_pool;
1282 const any_non_single_threaded = elf_file.base.comp.config.any_non_single_threaded;1160 const any_non_single_threaded = elf_file.base.comp.config.any_non_single_threaded;
1283 const nav_val = zcu.navValue(nav_index);1161 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 }
1285 const is_const, const is_threadlocal, const nav_init = switch (ip.indexToKey(nav_val.toIntern())) {1175 const is_const, const is_threadlocal, const nav_init = switch (ip.indexToKey(nav_val.toIntern())) {
1286 .variable => |variable| .{ false, variable.is_threadlocal, variable.init },1176 .variable => |variable| .{ false, variable.is_threadlocal, variable.init },
1287 .@"extern" => |@"extern"| .{ @"extern".is_const, @"extern".is_threadlocal, .none },1177 .@"extern" => |@"extern"| .{ @"extern".is_const, @"extern".is_threadlocal, .none },
...@@ -1292,30 +1182,107 @@ fn getNavShdrIndex(...@@ -1292,30 +1182,107 @@ fn getNavShdrIndex(
1292 const is_bss = !has_relocs and for (code) |byte| {1182 const is_bss = !has_relocs and for (code) |byte| {
1293 if (byte != 0) break false;1183 if (byte != 0) break false;
1294 } else true;1184 } else true;
1295 if (is_bss) return elf_file.sectionByName(".tbss") orelse try elf_file.addSection(.{1185 if (is_bss) {
1296 .type = elf.SHT_NOBITS,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,
1297 .flags = elf.SHF_ALLOC | elf.SHF_WRITE | elf.SHF_TLS,1201 .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,
1299 .offset = std.math.maxInt(u64),1204 .offset = std.math.maxInt(u64),
1300 });1205 });
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"),
1302 .type = elf.SHT_PROGBITS,1214 .type = elf.SHT_PROGBITS,
1303 .flags = elf.SHF_ALLOC | elf.SHF_WRITE | elf.SHF_TLS,1215 .addralign = 1,
1304 .name = try elf_file.insertShString(".tdata"),1216 .flags = elf.SHF_ALLOC | elf.SHF_WRITE,
1305 .offset = std.math.maxInt(u64),1217 .offset = std.math.maxInt(u64),
1306 });1218 });
1219 self.data_relro_index = try self.addSectionSymbol(gpa, ".data.rel.ro", .@"1", osec);
1220 return osec;
1307 }1221 }
1308 if (is_const) return elf_file.zig_data_rel_ro_section_index.?;
1309 if (nav_init != .none and Value.fromInterned(nav_init).isUndefDeep(zcu))1222 if (nav_init != .none and Value.fromInterned(nav_init).isUndefDeep(zcu))
1310 return switch (zcu.navFileScope(nav_index).mod.optimize_mode) {1223 return switch (zcu.navFileScope(nav_index).mod.optimize_mode) {
1311 .Debug, .ReleaseSafe => elf_file.zig_data_section_index.?,1224 .Debug, .ReleaseSafe => {
1312 .ReleaseFast, .ReleaseSmall => elf_file.zig_bss_section_index.?,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 },
1313 };1254 };
1314 const is_bss = !has_relocs and for (code) |byte| {1255 const is_bss = !has_relocs and for (code) |byte| {
1315 if (byte != 0) break false;1256 if (byte != 0) break false;
1316 } else true;1257 } else true;
1317 if (is_bss) return elf_file.zig_bss_section_index.?;1258 if (is_bss) {
1318 return elf_file.zig_data_section_index.?;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;
1319}1286}
13201287
1321fn updateNavCode(1288fn updateNavCode(
...@@ -1362,19 +1329,18 @@ fn updateNavCode(...@@ -1362,19 +1329,18 @@ fn updateNavCode(
1362 const capacity = atom_ptr.capacity(elf_file);1329 const capacity = atom_ptr.capacity(elf_file);
1363 const need_realloc = code.len > capacity or !required_alignment.check(@intCast(atom_ptr.value));1330 const need_realloc = code.len > capacity or !required_alignment.check(@intCast(atom_ptr.value));
1364 if (need_realloc) {1331 if (need_realloc) {
1365 try atom_ptr.grow(elf_file);1332 try self.growAtom(atom_ptr, elf_file);
1366 log.debug("growing {} from 0x{x} to 0x{x}", .{ nav.fqn.fmt(ip), old_vaddr, atom_ptr.value });1333 log.debug("growing {} from 0x{x} to 0x{x}", .{ nav.fqn.fmt(ip), old_vaddr, atom_ptr.value });
1367 if (old_vaddr != atom_ptr.value) {1334 if (old_vaddr != atom_ptr.value) {
1368 sym.value = 0;1335 sym.value = 0;
1369 esym.st_value = 0;1336 esym.st_value = 0;
1370 }1337 }
1371 } else if (code.len < old_size) {1338 } else if (code.len < old_size) {
1372 atom_ptr.shrink(elf_file);1339 // TODO shrink section size
1373 }1340 }
1374 } else {1341 } else {
1375 try atom_ptr.allocate(elf_file);1342 try self.allocateAtom(atom_ptr, elf_file);
1376 errdefer self.freeNavMetadata(elf_file, sym_index);1343 errdefer self.freeNavMetadata(elf_file, sym_index);
1377
1378 sym.value = 0;1344 sym.value = 0;
1379 esym.st_value = 0;1345 esym.st_value = 0;
1380 }1346 }
...@@ -1404,7 +1370,7 @@ fn updateNavCode(...@@ -1404,7 +1370,7 @@ fn updateNavCode(
14041370
1405 const shdr = elf_file.sections.items(.shdr)[shdr_index];1371 const shdr = elf_file.sections.items(.shdr)[shdr_index];
1406 if (shdr.sh_type != elf.SHT_NOBITS) {1372 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);
1408 try elf_file.base.file.?.pwriteAll(code, file_offset);1374 try elf_file.base.file.?.pwriteAll(code, file_offset);
1409 log.debug("writing {} from 0x{x} to 0x{x}", .{ nav.fqn.fmt(ip), file_offset, file_offset + code.len });1375 log.debug("writing {} from 0x{x} to 0x{x}", .{ nav.fqn.fmt(ip), file_offset, file_offset + code.len });
1410 }1376 }
...@@ -1433,15 +1399,11 @@ fn updateTlv(...@@ -1433,15 +1399,11 @@ fn updateTlv(
1433 const atom_ptr = sym.atom(elf_file).?;1399 const atom_ptr = sym.atom(elf_file).?;
1434 const name_offset = try self.strtab.insert(gpa, nav.fqn.toSlice(ip));1400 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;
1440 atom_ptr.alive = true;1402 atom_ptr.alive = true;
1441 atom_ptr.name_offset = name_offset;1403 atom_ptr.name_offset = name_offset;
1404 atom_ptr.output_section_index = shndx;
14421405
1443 sym.name_offset = name_offset;1406 sym.name_offset = name_offset;
1444 esym.st_value = 0;
1445 esym.st_name = name_offset;1407 esym.st_name = name_offset;
1446 esym.st_info = elf.STT_TLS;1408 esym.st_info = elf.STT_TLS;
1447 esym.st_size = code.len;1409 esym.st_size = code.len;
...@@ -1449,21 +1411,25 @@ fn updateTlv(...@@ -1449,21 +1411,25 @@ fn updateTlv(
1449 atom_ptr.alignment = required_alignment;1411 atom_ptr.alignment = required_alignment;
1450 atom_ptr.size = code.len;1412 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 {1417 try self.allocateAtom(atom_ptr, elf_file);
1455 const gop = try self.tls_variables.getOrPut(gpa, atom_ptr.atom_index);1418 sym.value = 0;
1456 assert(!gop.found_existing); // TODO incremental updates1419 esym.st_value = 0;
1457 gop.value_ptr.* = .{ .symbol_index = sym_index };
14581420
1459 // We only store the data for the TLV if it's non-zerofill.1421 self.navs.getPtr(nav_index).?.allocated = true;
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 }
14641422
1465 const atom_list = &elf_file.sections.items(.atom_list)[atom_ptr.output_section_index];1423 const shdr = elf_file.sections.items(.shdr)[shndx];
1466 try atom_list.append(gpa, .{ .index = atom_ptr.atom_index, .file = self.index });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 }
1467}1433}
14681434
1469pub fn updateFunc(1435pub fn updateFunc(
...@@ -1558,6 +1524,19 @@ pub fn updateFunc(...@@ -1558,6 +1524,19 @@ pub fn updateFunc(
1558 self.symbol(sym_index).name(elf_file),1524 self.symbol(sym_index).name(elf_file),
1559 });1525 });
1560 defer gpa.free(name);1526 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 };
1561 const name_off = try self.addString(gpa, name);1540 const name_off = try self.addString(gpa, name);
1562 const tr_size = trampolineSize(elf_file.getTarget().cpu.arch);1541 const tr_size = trampolineSize(elf_file.getTarget().cpu.arch);
1563 const tr_sym_index = try self.newSymbolWithAtom(gpa, name_off);1542 const tr_sym_index = try self.newSymbolWithAtom(gpa, name_off);
...@@ -1569,7 +1548,7 @@ pub fn updateFunc(...@@ -1569,7 +1548,7 @@ pub fn updateFunc(
1569 tr_atom_ptr.value = old_rva;1548 tr_atom_ptr.value = old_rva;
1570 tr_atom_ptr.alive = true;1549 tr_atom_ptr.alive = true;
1571 tr_atom_ptr.alignment = old_alignment;1550 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;
1573 tr_atom_ptr.size = tr_size;1552 tr_atom_ptr.size = tr_size;
1574 const target_sym = self.symbol(sym_index);1553 const target_sym = self.symbol(sym_index);
1575 target_sym.addExtra(.{ .trampoline = tr_sym_index }, elf_file);1554 target_sym.addExtra(.{ .trampoline = tr_sym_index }, elf_file);
...@@ -1723,8 +1702,32 @@ fn updateLazySymbol(...@@ -1723,8 +1702,32 @@ fn updateLazySymbol(
1723 };1702 };
17241703
1725 const output_section_index = switch (sym.kind) {1704 const output_section_index = switch (sym.kind) {
1726 .code => elf_file.zig_text_section_index.?,1705 .code => if (self.text_index) |sym_index|
1727 .const_data => elf_file.zig_data_rel_ro_section_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 },
1728 };1731 };
1729 const local_sym = self.symbol(symbol_index);1732 const local_sym = self.symbol(symbol_index);
1730 local_sym.name_offset = name_str_index;1733 local_sym.name_offset = name_str_index;
...@@ -1739,15 +1742,13 @@ fn updateLazySymbol(...@@ -1739,15 +1742,13 @@ fn updateLazySymbol(
1739 atom_ptr.size = code.len;1742 atom_ptr.size = code.len;
1740 atom_ptr.output_section_index = output_section_index;1743 atom_ptr.output_section_index = output_section_index;
17411744
1742 try atom_ptr.allocate(elf_file);1745 try self.allocateAtom(atom_ptr, elf_file);
1743 errdefer self.freeNavMetadata(elf_file, symbol_index);1746 errdefer self.freeNavMetadata(elf_file, symbol_index);
17441747
1745 local_sym.value = 0;1748 local_sym.value = 0;
1746 local_esym.st_value = 0;1749 local_esym.st_value = 0;
17471750
1748 const shdr = elf_file.sections.items(.shdr)[output_section_index];1751 try elf_file.base.file.?.pwriteAll(code, atom_ptr.offset(elf_file));
1749 const file_offset = shdr.sh_offset + @as(u64, @intCast(atom_ptr.value));
1750 try elf_file.base.file.?.pwriteAll(code, file_offset);
1751}1752}
17521753
1753const LowerConstResult = union(enum) {1754const LowerConstResult = union(enum) {
...@@ -1797,13 +1798,10 @@ fn lowerConst(...@@ -1797,13 +1798,10 @@ fn lowerConst(
1797 atom_ptr.size = code.len;1798 atom_ptr.size = code.len;
1798 atom_ptr.output_section_index = output_section_index;1799 atom_ptr.output_section_index = output_section_index;
17991800
1800 try atom_ptr.allocate(elf_file);1801 try self.allocateAtom(atom_ptr, elf_file);
1801 // TODO rename and re-audit this method
1802 errdefer self.freeNavMetadata(elf_file, sym_index);1802 errdefer self.freeNavMetadata(elf_file, sym_index);
18031803
1804 const shdr = elf_file.sections.items(.shdr)[output_section_index];1804 try elf_file.base.file.?.pwriteAll(code, atom_ptr.offset(elf_file));
1805 const file_offset = shdr.sh_offset + @as(u64, @intCast(atom_ptr.value));
1806 try elf_file.base.file.?.pwriteAll(code, file_offset);
18071805
1808 return .{ .ok = sym_index };1806 return .{ .ok = sym_index };
1809}1807}
...@@ -1965,8 +1963,7 @@ fn trampolineSize(cpu_arch: std.Target.Cpu.Arch) u64 {...@@ -1965,8 +1963,7 @@ fn trampolineSize(cpu_arch: std.Target.Cpu.Arch) u64 {
19651963
1966fn writeTrampoline(tr_sym: Symbol, target: Symbol, elf_file: *Elf) !void {1964fn writeTrampoline(tr_sym: Symbol, target: Symbol, elf_file: *Elf) !void {
1967 const atom_ptr = tr_sym.atom(elf_file).?;1965 const atom_ptr = tr_sym.atom(elf_file).?;
1968 const shdr = elf_file.sections.items(.shdr)[atom_ptr.output_section_index];1966 const fileoff = atom_ptr.offset(elf_file);
1969 const fileoff = shdr.sh_offset + @as(u64, @intCast(atom_ptr.value));
1970 const source_addr = tr_sym.address(.{}, elf_file);1967 const source_addr = tr_sym.address(.{}, elf_file);
1971 const target_addr = target.address(.{ .trampoline = false }, elf_file);1968 const target_addr = target.address(.{ .trampoline = false }, elf_file);
1972 var buf: [max_trampoline_len]u8 = undefined;1969 var buf: [max_trampoline_len]u8 = undefined;
...@@ -1998,6 +1995,80 @@ fn writeTrampoline(tr_sym: Symbol, target: Symbol, elf_file: *Elf) !void {...@@ -1998,6 +1995,80 @@ fn writeTrampoline(tr_sym: Symbol, target: Symbol, elf_file: *Elf) !void {
1998 }1995 }
1999}1996}
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
2001pub fn asFile(self: *ZigObject) File {2072pub fn asFile(self: *ZigObject) File {
2002 return .{ .zig_object = self };2073 return .{ .zig_object = self };
2003}2074}
...@@ -2271,7 +2342,7 @@ const AtomList = std.ArrayListUnmanaged(Atom.Index);...@@ -2271,7 +2342,7 @@ const AtomList = std.ArrayListUnmanaged(Atom.Index);
2271const NavTable = std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, AvMetadata);2342const NavTable = std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, AvMetadata);
2272const UavTable = std.AutoArrayHashMapUnmanaged(InternPool.Index, AvMetadata);2343const UavTable = std.AutoArrayHashMapUnmanaged(InternPool.Index, AvMetadata);
2273const LazySymbolTable = std.AutoArrayHashMapUnmanaged(InternPool.Index, LazySymbolMetadata);2344const LazySymbolTable = std.AutoArrayHashMapUnmanaged(InternPool.Index, LazySymbolMetadata);
2274const TlsTable = std.AutoArrayHashMapUnmanaged(Atom.Index, TlsVariable);2345const TlsTable = std.AutoArrayHashMapUnmanaged(Atom.Index, void);
22752346
2276const x86_64 = struct {2347const x86_64 = struct {
2277 fn writeTrampolineCode(source_addr: i64, target_addr: i64, buf: *[max_trampoline_len]u8) ![]u8 {2348 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 {...@@ -233,7 +233,10 @@ pub fn calcEhFrameSize(elf_file: *Elf) !usize {
233 const comp = elf_file.base.comp;233 const comp = elf_file.base.comp;
234 const gpa = comp.gpa;234 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
238 var cies = std.ArrayList(Cie).init(gpa);241 var cies = std.ArrayList(Cie).init(gpa);
239 defer cies.deinit();242 defer cies.deinit();
...@@ -288,6 +291,13 @@ pub fn calcEhFrameHdrSize(elf_file: *Elf) usize {...@@ -288,6 +291,13 @@ pub fn calcEhFrameHdrSize(elf_file: *Elf) usize {
288291
289pub fn calcEhFrameRelocs(elf_file: *Elf) usize {292pub fn calcEhFrameRelocs(elf_file: *Elf) usize {
290 var count: usize = 0;293 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 }
291 for (elf_file.objects.items) |index| {301 for (elf_file.objects.items) |index| {
292 const object = elf_file.file(index).?.object;302 const object = elf_file.file(index).?.object;
293 for (object.cies.items) |cie| {303 for (object.cies.items) |cie| {
...@@ -386,7 +396,7 @@ pub fn writeEhFrame(elf_file: *Elf, writer: anytype) !void {...@@ -386,7 +396,7 @@ pub fn writeEhFrame(elf_file: *Elf, writer: anytype) !void {
386 if (has_reloc_errors) return error.RelocFailure;396 if (has_reloc_errors) return error.RelocFailure;
387}397}
388398
389pub fn writeEhFrameObject(elf_file: *Elf, writer: anytype) !void {399pub fn writeEhFrameRelocatable(elf_file: *Elf, writer: anytype) !void {
390 for (elf_file.objects.items) |index| {400 for (elf_file.objects.items) |index| {
391 const object = elf_file.file(index).?.object;401 const object = elf_file.file(index).?.object;
392402
...@@ -416,9 +426,8 @@ pub fn writeEhFrameObject(elf_file: *Elf, writer: anytype) !void {...@@ -416,9 +426,8 @@ pub fn writeEhFrameObject(elf_file: *Elf, writer: anytype) !void {
416 }426 }
417}427}
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 {
420 const cpu_arch = elf_file.getTarget().cpu.arch;430 const cpu_arch = elf_file.getTarget().cpu.arch;
421 const r_offset = rec.address(elf_file) + rel.r_offset - rec.offset;
422 const r_type = rel.r_type();431 const r_type = rel.r_type();
423 var r_addend = rel.r_addend;432 var r_addend = rel.r_addend;
424 var r_sym: u32 = 0;433 var r_sym: u32 = 0;
...@@ -452,6 +461,19 @@ pub fn writeEhFrameRelocs(elf_file: *Elf, writer: anytype) !void {...@@ -452,6 +461,19 @@ pub fn writeEhFrameRelocs(elf_file: *Elf, writer: anytype) !void {
452 elf_file.sections.items(.shdr)[elf_file.eh_frame_section_index.?].sh_addr,461 elf_file.sections.items(.shdr)[elf_file.eh_frame_section_index.?].sh_addr,
453 });462 });
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
455 for (elf_file.objects.items) |index| {477 for (elf_file.objects.items) |index| {
456 const object = elf_file.file(index).?.object;478 const object = elf_file.file(index).?.object;
457479
...@@ -460,7 +482,8 @@ pub fn writeEhFrameRelocs(elf_file: *Elf, writer: anytype) !void {...@@ -460,7 +482,8 @@ pub fn writeEhFrameRelocs(elf_file: *Elf, writer: anytype) !void {
460 for (cie.relocs(elf_file)) |rel| {482 for (cie.relocs(elf_file)) |rel| {
461 const ref = object.resolveSymbol(rel.r_sym(), elf_file);483 const ref = object.resolveSymbol(rel.r_sym(), elf_file);
462 const sym = elf_file.symbol(ref).?;484 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);
464 try writer.writeStruct(out_rel);487 try writer.writeStruct(out_rel);
465 }488 }
466 }489 }
...@@ -470,7 +493,8 @@ pub fn writeEhFrameRelocs(elf_file: *Elf, writer: anytype) !void {...@@ -470,7 +493,8 @@ pub fn writeEhFrameRelocs(elf_file: *Elf, writer: anytype) !void {
470 for (fde.relocs(elf_file)) |rel| {493 for (fde.relocs(elf_file)) |rel| {
471 const ref = object.resolveSymbol(rel.r_sym(), elf_file);494 const ref = object.resolveSymbol(rel.r_sym(), elf_file);
472 const sym = elf_file.symbol(ref).?;495 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);
474 try writer.writeStruct(out_rel);498 try writer.writeStruct(out_rel);
475 }499 }
476 }500 }
src/link/Elf/relocatable.zig+80-114
...@@ -18,7 +18,7 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]co...@@ -18,7 +18,7 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]co
18 }18 }
1919
20 for (positionals.items) |obj| {20 for (positionals.items) |obj| {
21 parsePositional(elf_file, obj.path) catch |err| switch (err) {21 parsePositionalStaticLib(elf_file, obj.path) catch |err| switch (err) {
22 error.MalformedObject,22 error.MalformedObject,
23 error.MalformedArchive,23 error.MalformedArchive,
24 error.InvalidMachineType,24 error.InvalidMachineType,
...@@ -38,17 +38,12 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]co...@@ -38,17 +38,12 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]co
38 // First, we flush relocatable object file generated with our backends.38 // First, we flush relocatable object file generated with our backends.
39 if (elf_file.zigObjectPtr()) |zig_object| {39 if (elf_file.zigObjectPtr()) |zig_object| {
40 try zig_object.resolveSymbols(elf_file);40 try zig_object.resolveSymbols(elf_file);
41 elf_file.markEhFrameAtomsDead();
41 try elf_file.addCommentString();42 try elf_file.addCommentString();
42 try elf_file.finalizeMergeSections();43 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 try initSections(elf_file);
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();
52 try elf_file.sortShdrs();47 try elf_file.sortShdrs();
53 try zig_object.addAtomsToRelaSections(elf_file);48 try zig_object.addAtomsToRelaSections(elf_file);
54 try elf_file.updateMergeSectionSizes();49 try elf_file.updateMergeSectionSizes();
...@@ -208,7 +203,6 @@ pub fn flushObject(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]const...@@ -208,7 +203,6 @@ pub fn flushObject(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]const
208 }203 }
209 for (elf_file.objects.items) |index| {204 for (elf_file.objects.items) |index| {
210 const object = elf_file.file(index).?.object;205 const object = elf_file.file(index).?.object;
211 try object.addAtomsToOutputSections(elf_file);
212 try object.addAtomsToRelaSections(elf_file);206 try object.addAtomsToRelaSections(elf_file);
213 }207 }
214 try elf_file.updateMergeSectionSizes();208 try elf_file.updateMergeSectionSizes();
...@@ -230,17 +224,17 @@ pub fn flushObject(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]const...@@ -230,17 +224,17 @@ pub fn flushObject(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]const
230 if (elf_file.base.hasErrors()) return error.FlushFailure;224 if (elf_file.base.hasErrors()) return error.FlushFailure;
231}225}
232226
233fn parsePositional(elf_file: *Elf, path: []const u8) Elf.ParseError!void {227fn parsePositionalStaticLib(elf_file: *Elf, path: []const u8) Elf.ParseError!void {
234 if (try Object.isObject(path)) {228 if (try Object.isObject(path)) {
235 try parseObject(elf_file, path);229 try parseObjectStaticLib(elf_file, path);
236 } else if (try Archive.isArchive(path)) {230 } else if (try Archive.isArchive(path)) {
237 try parseArchive(elf_file, path);231 try parseArchiveStaticLib(elf_file, path);
238 } else return error.UnknownFileType;232 } else return error.UnknownFileType;
239 // TODO: should we check for LD script?233 // TODO: should we check for LD script?
240 // Actually, should we even unpack an archive?234 // Actually, should we even unpack an archive?
241}235}
242236
243fn parseObject(elf_file: *Elf, path: []const u8) Elf.ParseError!void {237fn parseObjectStaticLib(elf_file: *Elf, path: []const u8) Elf.ParseError!void {
244 const gpa = elf_file.base.comp.gpa;238 const gpa = elf_file.base.comp.gpa;
245 const handle = try std.fs.cwd().openFile(path, .{});239 const handle = try std.fs.cwd().openFile(path, .{});
246 const fh = try elf_file.addFileHandle(handle);240 const fh = try elf_file.addFileHandle(handle);
...@@ -257,7 +251,7 @@ fn parseObject(elf_file: *Elf, path: []const u8) Elf.ParseError!void {...@@ -257,7 +251,7 @@ fn parseObject(elf_file: *Elf, path: []const u8) Elf.ParseError!void {
257 try object.parseAr(elf_file);251 try object.parseAr(elf_file);
258}252}
259253
260fn parseArchive(elf_file: *Elf, path: []const u8) Elf.ParseError!void {254fn parseArchiveStaticLib(elf_file: *Elf, path: []const u8) Elf.ParseError!void {
261 const gpa = elf_file.base.comp.gpa;255 const gpa = elf_file.base.comp.gpa;
262 const handle = try std.fs.cwd().openFile(path, .{});256 const handle = try std.fs.cwd().openFile(path, .{});
263 const fh = try elf_file.addFileHandle(handle);257 const fh = try elf_file.addFileHandle(handle);
...@@ -281,14 +275,17 @@ fn parseArchive(elf_file: *Elf, path: []const u8) Elf.ParseError!void {...@@ -281,14 +275,17 @@ fn parseArchive(elf_file: *Elf, path: []const u8) Elf.ParseError!void {
281275
282fn claimUnresolved(elf_file: *Elf) void {276fn claimUnresolved(elf_file: *Elf) void {
283 if (elf_file.zigObjectPtr()) |zig_object| {277 if (elf_file.zigObjectPtr()) |zig_object| {
284 zig_object.claimUnresolvedObject(elf_file);278 zig_object.claimUnresolvedRelocatable(elf_file);
285 }279 }
286 for (elf_file.objects.items) |index| {280 for (elf_file.objects.items) |index| {
287 elf_file.file(index).?.object.claimUnresolvedObject(elf_file);281 elf_file.file(index).?.object.claimUnresolvedRelocatable(elf_file);
288 }282 }
289}283}
290284
291fn initSections(elf_file: *Elf) !void {285fn initSections(elf_file: *Elf) !void {
286 if (elf_file.zigObjectPtr()) |zo| {
287 try zo.initRelaSections(elf_file);
288 }
292 for (elf_file.objects.items) |index| {289 for (elf_file.objects.items) |index| {
293 const object = elf_file.file(index).?.object;290 const object = elf_file.file(index).?.object;
294 try object.initOutputSections(elf_file);291 try object.initOutputSections(elf_file);
...@@ -300,12 +297,17 @@ fn initSections(elf_file: *Elf) !void {...@@ -300,12 +297,17 @@ fn initSections(elf_file: *Elf) !void {
300 try msec.initOutputSection(elf_file);297 try msec.initOutputSection(elf_file);
301 }298 }
302299
303 const needs_eh_frame = for (elf_file.objects.items) |index| {300 const needs_eh_frame = blk: {
304 if (elf_file.file(index).?.object.cies.items.len > 0) break true;301 if (elf_file.zigObjectPtr()) |zo|
305 } else false;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 };
306 if (needs_eh_frame) {307 if (needs_eh_frame) {
307 if (elf_file.eh_frame_section_index == null) {308 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(.{
309 .name = try elf_file.insertShString(".eh_frame"),311 .name = try elf_file.insertShString(".eh_frame"),
310 .type = if (elf_file.getTarget().cpu.arch == .x86_64)312 .type = if (elf_file.getTarget().cpu.arch == .x86_64)
311 elf.SHT_X86_64_UNWIND313 elf.SHT_X86_64_UNWIND
...@@ -316,7 +318,8 @@ fn initSections(elf_file: *Elf) !void {...@@ -316,7 +318,8 @@ fn initSections(elf_file: *Elf) !void {
316 .offset = std.math.maxInt(u64),318 .offset = std.math.maxInt(u64),
317 });319 });
318 }320 }
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(
320 try elf_file.insertShString(".rela.eh_frame"),323 try elf_file.insertShString(".rela.eh_frame"),
321 elf_file.eh_frame_section_index.?,324 elf_file.eh_frame_section_index.?,
322 );325 );
...@@ -351,36 +354,28 @@ fn initComdatGroups(elf_file: *Elf) !void {...@@ -351,36 +354,28 @@ fn initComdatGroups(elf_file: *Elf) !void {
351354
352fn updateSectionSizes(elf_file: *Elf) !void {355fn updateSectionSizes(elf_file: *Elf) !void {
353 const slice = elf_file.sections.slice();356 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
354 for (slice.items(.shdr), 0..) |*shdr, shndx| {363 for (slice.items(.shdr), 0..) |*shdr, shndx| {
355 const atom_list = slice.items(.atom_list)[shndx];364 const atom_list = slice.items(.atom_list)[shndx];
356 if (shdr.sh_type != elf.SHT_RELA) {365 if (shdr.sh_type != elf.SHT_RELA) continue;
357 for (atom_list.items) |ref| {366 if (@as(u32, @intCast(shndx)) == elf_file.eh_frame_section_index) continue;
358 const atom_ptr = elf_file.atom(ref) orelse continue;367 for (atom_list.items) |ref| {
359 if (!atom_ptr.alive) continue;368 const atom_ptr = elf_file.atom(ref) orelse continue;
360 const offset = atom_ptr.alignment.forward(shdr.sh_size);369 if (!atom_ptr.alive) continue;
361 const padding = offset - shdr.sh_size;370 const relocs = atom_ptr.relocs(elf_file);
362 atom_ptr.value = @intCast(offset);371 shdr.sh_size += shdr.sh_entsize * relocs.len;
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;
375 }372 }
373
374 if (shdr.sh_size == 0) shdr.sh_offset = 0;
376 }375 }
377376
378 if (elf_file.eh_frame_section_index) |index| {377 if (elf_file.eh_frame_section_index) |index| {
379 slice.items(.shdr)[index].sh_size = existing_size: {378 slice.items(.shdr)[index].sh_size = try eh_frame.calcEhFrameSize(elf_file);
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);
384 }379 }
385 if (elf_file.eh_frame_rela_section_index) |index| {380 if (elf_file.eh_frame_rela_section_index) |index| {
386 const shdr = &slice.items(.shdr)[index];381 const shdr = &slice.items(.shdr)[index];
...@@ -405,7 +400,7 @@ fn updateComdatGroupsSizes(elf_file: *Elf) void {...@@ -405,7 +400,7 @@ fn updateComdatGroupsSizes(elf_file: *Elf) void {
405400
406/// Allocates alloc sections when merging relocatable objects files together.401/// Allocates alloc sections when merging relocatable objects files together.
407fn allocateAllocSections(elf_file: *Elf) !void {402fn allocateAllocSections(elf_file: *Elf) !void {
408 for (elf_file.sections.items(.shdr)) |*shdr| {403 for (elf_file.sections.items(.shdr), 0..) |*shdr, shndx| {
409 if (shdr.sh_type == elf.SHT_NULL) continue;404 if (shdr.sh_type == elf.SHT_NULL) continue;
410 if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue;405 if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue;
411 if (shdr.sh_type == elf.SHT_NOBITS) {406 if (shdr.sh_type == elf.SHT_NOBITS) {
...@@ -416,6 +411,34 @@ fn allocateAllocSections(elf_file: *Elf) !void {...@@ -416,6 +411,34 @@ fn allocateAllocSections(elf_file: *Elf) !void {
416 if (needed_size > elf_file.allocatedSize(shdr.sh_offset)) {411 if (needed_size > elf_file.allocatedSize(shdr.sh_offset)) {
417 shdr.sh_size = 0;412 shdr.sh_size = 0;
418 const new_offset = try elf_file.findFreeSpace(needed_size, shdr.sh_addralign);413 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
419 shdr.sh_offset = new_offset;442 shdr.sh_offset = new_offset;
420 shdr.sh_size = needed_size;443 shdr.sh_size = needed_size;
421 }444 }
...@@ -424,73 +447,15 @@ fn allocateAllocSections(elf_file: *Elf) !void {...@@ -424,73 +447,15 @@ fn allocateAllocSections(elf_file: *Elf) !void {
424447
425fn writeAtoms(elf_file: *Elf) !void {448fn writeAtoms(elf_file: *Elf) !void {
426 const gpa = elf_file.base.comp.gpa;449 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}", .{451 var buffer = std.ArrayList(u8).init(gpa);
477 ref,452 defer buffer.deinit();
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 }
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);
494 }459 }
495}460}
496461
...@@ -498,9 +463,10 @@ fn writeSyntheticSections(elf_file: *Elf) !void {...@@ -498,9 +463,10 @@ fn writeSyntheticSections(elf_file: *Elf) !void {
498 const gpa = elf_file.base.comp.gpa;463 const gpa = elf_file.base.comp.gpa;
499 const slice = elf_file.sections.slice();464 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| {
502 if (shdr.sh_type != elf.SHT_RELA) continue;467 if (shdr.sh_type != elf.SHT_RELA) continue;
503 if (atom_list.items.len == 0) continue;468 if (atom_list.items.len == 0) continue;
469 if (@as(u32, @intCast(shndx)) == elf_file.eh_frame_section_index) continue;
504470
505 const num_relocs = math.cast(usize, @divExact(shdr.sh_size, shdr.sh_entsize)) orelse471 const num_relocs = math.cast(usize, @divExact(shdr.sh_size, shdr.sh_entsize)) orelse
506 return error.Overflow;472 return error.Overflow;
...@@ -542,7 +508,7 @@ fn writeSyntheticSections(elf_file: *Elf) !void {...@@ -542,7 +508,7 @@ fn writeSyntheticSections(elf_file: *Elf) !void {
542 const sh_size = math.cast(usize, shdr.sh_size) orelse return error.Overflow;508 const sh_size = math.cast(usize, shdr.sh_size) orelse return error.Overflow;
543 var buffer = try std.ArrayList(u8).initCapacity(gpa, @intCast(sh_size - existing_size));509 var buffer = try std.ArrayList(u8).initCapacity(gpa, @intCast(sh_size - existing_size));
544 defer buffer.deinit();510 defer buffer.deinit();
545 try eh_frame.writeEhFrameObject(elf_file, buffer.writer());511 try eh_frame.writeEhFrameRelocatable(elf_file, buffer.writer());
546 log.debug("writing .eh_frame from 0x{x} to 0x{x}", .{512 log.debug("writing .eh_frame from 0x{x} to 0x{x}", .{
547 shdr.sh_offset + existing_size,513 shdr.sh_offset + existing_size,
548 shdr.sh_offset + sh_size,514 shdr.sh_offset + sh_size,
test/link/elf.zig+2
...@@ -55,6 +55,7 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step {...@@ -55,6 +55,7 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step {
5555
56 // Exercise linker in ar mode56 // Exercise linker in ar mode
57 elf_step.dependOn(testEmitStaticLib(b, .{ .target = musl_target }));57 elf_step.dependOn(testEmitStaticLib(b, .{ .target = musl_target }));
58 elf_step.dependOn(testEmitStaticLibZig(b, .{ .target = musl_target }));
5859
59 // Exercise linker with LLVM backend60 // Exercise linker with LLVM backend
60 // musl tests61 // musl tests
...@@ -66,6 +67,7 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step {...@@ -66,6 +67,7 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step {
66 elf_step.dependOn(testEmptyObject(b, .{ .target = musl_target }));67 elf_step.dependOn(testEmptyObject(b, .{ .target = musl_target }));
67 elf_step.dependOn(testEntryPoint(b, .{ .target = musl_target }));68 elf_step.dependOn(testEntryPoint(b, .{ .target = musl_target }));
68 elf_step.dependOn(testGcSections(b, .{ .target = musl_target }));69 elf_step.dependOn(testGcSections(b, .{ .target = musl_target }));
70 elf_step.dependOn(testGcSectionsZig(b, .{ .target = musl_target }));
69 elf_step.dependOn(testImageBase(b, .{ .target = musl_target }));71 elf_step.dependOn(testImageBase(b, .{ .target = musl_target }));
70 elf_step.dependOn(testInitArrayOrder(b, .{ .target = musl_target }));72 elf_step.dependOn(testInitArrayOrder(b, .{ .target = musl_target }));
71 elf_step.dependOn(testLargeAlignmentExe(b, .{ .target = musl_target }));73 elf_step.dependOn(testLargeAlignmentExe(b, .{ .target = musl_target }));