authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-10-09 17:43:17-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-10-09 17:43:17-07:00
log2e2927735d26fc6047343f0c620f20e9048ebaa5
treeb405962660ed41a6c2682e912cb9ccbcfe3748c9
parent5d7ed6110391bc8f6ff7fb9fa225bfa03fd19191
parent73c3b9b8ab056c3bcbde3a7a9b893b8814553c45
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #21629 from ziglang/elf-incr

elf: more incremental progress

10 files changed, 384 insertions(+), 414 deletions(-)

src/link/Dwarf.zig+16-19
......@@ -389,15 +389,10 @@ pub const Section = struct {
389389 if (dwarf.bin_file.cast(.elf)) |elf_file| {
390390 const zo = elf_file.zigObjectPtr().?;
391391 const atom = zo.symbol(sec.index).atom(elf_file).?;
392 const shndx = atom.output_section_index;
393 if (sec == &dwarf.debug_frame.section)
394 try elf_file.growAllocSection(shndx, len, sec.alignment.toByteUnits().?)
395 else
396 try elf_file.growNonAllocSection(shndx, len, sec.alignment.toByteUnits().?, true);
397 const shdr = elf_file.sections.items(.shdr)[shndx];
398 atom.size = shdr.sh_size;
399 atom.alignment = InternPool.Alignment.fromNonzeroByteUnits(shdr.sh_addralign);
400 sec.len = shdr.sh_size;
392 atom.size = len;
393 atom.alignment = sec.alignment;
394 sec.len = len;
395 try zo.allocateAtom(atom, false, elf_file);
401396 } else if (dwarf.bin_file.cast(.macho)) |macho_file| {
402397 const header = if (macho_file.d_sym) |*d_sym| header: {
403398 try d_sym.growSection(@intCast(sec.index), len, true, macho_file);
......@@ -418,11 +413,15 @@ pub const Section = struct {
418413 if (dwarf.bin_file.cast(.elf)) |elf_file| {
419414 const zo = elf_file.zigObjectPtr().?;
420415 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;
425 shdr.sh_size = sec.len;
416 if (atom.prevAtom(elf_file)) |_| {
417 // FIXME:JK trimming/shrinking has to be reworked on ZigObject/Elf level
418 atom.value += len;
419 } else {
420 const shdr = &elf_file.sections.items(.shdr)[atom.output_section_index];
421 shdr.sh_offset += len;
422 atom.value = 0;
423 }
424 atom.size -= len;
426425 } else if (dwarf.bin_file.cast(.macho)) |macho_file| {
427426 const header = if (macho_file.d_sym) |*d_sym|
428427 &d_sym.sections.items[sec.index]
......@@ -911,11 +910,9 @@ const Entry = struct {
911910 if (std.debug.runtime_safety) {
912911 log.err("missing {} from {s}", .{
913912 @as(Entry.Index, @enumFromInt(entry - unit.entries.items.ptr)),
914 std.mem.sliceTo(if (dwarf.bin_file.cast(.elf)) |elf_file| sh_name: {
915 const zo = elf_file.zigObjectPtr().?;
916 const shndx = zo.symbol(sec.index).atom(elf_file).?.output_section_index;
917 break :sh_name elf_file.shstrtab.items[elf_file.sections.items(.shdr)[shndx].sh_name..];
918 } else if (dwarf.bin_file.cast(.macho)) |macho_file|
913 std.mem.sliceTo(if (dwarf.bin_file.cast(.elf)) |elf_file|
914 elf_file.zigObjectPtr().?.symbol(sec.index).name(elf_file)
915 else if (dwarf.bin_file.cast(.macho)) |macho_file|
919916 if (macho_file.d_sym) |*d_sym|
920917 &d_sym.sections.items[sec.index].segname
921918 else
src/link/Elf.zig+131-195
......@@ -548,16 +548,6 @@ pub fn allocatedSize(self: *Elf, start: u64) u64 {
548548 return min_pos - start;
549549}
550550
551fn allocatedVirtualSize(self: *Elf, start: u64) u64 {
552 if (start == 0) return 0;
553 var min_pos: u64 = std.math.maxInt(u64);
554 for (self.phdrs.items) |phdr| {
555 if (phdr.p_vaddr <= start) continue;
556 if (phdr.p_vaddr < min_pos) min_pos = phdr.p_vaddr;
557 }
558 return min_pos - start;
559}
560
561551pub fn findFreeSpace(self: *Elf, object_size: u64, min_alignment: u64) !u64 {
562552 var start: u64 = 0;
563553 while (try self.detectAllocCollision(start, object_size)) |item_end| {
......@@ -566,90 +556,49 @@ pub fn findFreeSpace(self: *Elf, object_size: u64, min_alignment: u64) !u64 {
566556 return start;
567557}
568558
569pub fn growAllocSection(self: *Elf, shdr_index: u32, needed_size: u64, min_alignment: u64) !void {
570 const slice = self.sections.slice();
571 const shdr = &slice.items(.shdr)[shdr_index];
572 assert(shdr.sh_flags & elf.SHF_ALLOC != 0);
573 const phndx = slice.items(.phndx)[shdr_index];
574 const maybe_phdr = if (phndx) |ndx| &self.phdrs.items[ndx] else null;
575
576 log.debug("allocated size {x} of {s}, needed size {x}", .{
577 self.allocatedSize(shdr.sh_offset),
578 self.getShString(shdr.sh_name),
579 needed_size,
580 });
559pub fn growSection(self: *Elf, shdr_index: u32, needed_size: u64, min_alignment: u64) !void {
560 const shdr = &self.sections.items(.shdr)[shdr_index];
581561
582562 if (shdr.sh_type != elf.SHT_NOBITS) {
583563 const allocated_size = self.allocatedSize(shdr.sh_offset);
564 log.debug("allocated size {x} of '{s}', needed size {x}", .{
565 allocated_size,
566 self.getShString(shdr.sh_name),
567 needed_size,
568 });
569
584570 if (needed_size > allocated_size) {
585571 const existing_size = shdr.sh_size;
586572 shdr.sh_size = 0;
587573 // Must move the entire section.
588574 const new_offset = try self.findFreeSpace(needed_size, min_alignment);
589575
590 log.debug("new '{s}' file offset 0x{x} to 0x{x}", .{
576 log.debug("moving '{s}' from 0x{x} to 0x{x}", .{
591577 self.getShString(shdr.sh_name),
578 shdr.sh_offset,
592579 new_offset,
593 new_offset + existing_size,
594580 });
595581
596 const amt = try self.base.file.?.copyRangeAll(shdr.sh_offset, self.base.file.?, new_offset, existing_size);
597 // TODO figure out what to about this error condition - how to communicate it up.
598 if (amt != existing_size) return error.InputOutput;
599
600 shdr.sh_offset = new_offset;
601 if (maybe_phdr) |phdr| phdr.p_offset = new_offset;
602 } else if (shdr.sh_offset + allocated_size == std.math.maxInt(u64)) {
603 try self.base.file.?.setEndPos(shdr.sh_offset + needed_size);
604 }
605 if (maybe_phdr) |phdr| phdr.p_filesz = needed_size;
606 }
607 shdr.sh_size = needed_size;
608 self.markDirty(shdr_index);
609}
610
611pub fn growNonAllocSection(
612 self: *Elf,
613 shdr_index: u32,
614 needed_size: u64,
615 min_alignment: u64,
616 requires_file_copy: bool,
617) !void {
618 const shdr = &self.sections.items(.shdr)[shdr_index];
619 assert(shdr.sh_flags & elf.SHF_ALLOC == 0);
620
621 const allocated_size = self.allocatedSize(shdr.sh_offset);
622 if (needed_size > allocated_size) {
623 const existing_size = shdr.sh_size;
624 shdr.sh_size = 0;
625 // Move all the symbols to a new file location.
626 const new_offset = try self.findFreeSpace(needed_size, min_alignment);
627
628 log.debug("new '{s}' file offset 0x{x} to 0x{x}", .{
629 self.getShString(shdr.sh_name),
630 new_offset,
631 new_offset + existing_size,
632 });
633
634 if (requires_file_copy) {
635582 const amt = try self.base.file.?.copyRangeAll(
636583 shdr.sh_offset,
637584 self.base.file.?,
638585 new_offset,
639586 existing_size,
640587 );
588 // TODO figure out what to about this error condition - how to communicate it up.
641589 if (amt != existing_size) return error.InputOutput;
642 }
643590
644 shdr.sh_offset = new_offset;
645 } else if (shdr.sh_offset + allocated_size == std.math.maxInt(u64)) {
646 try self.base.file.?.setEndPos(shdr.sh_offset + needed_size);
591 shdr.sh_offset = new_offset;
592 } else if (shdr.sh_offset + allocated_size == std.math.maxInt(u64)) {
593 try self.base.file.?.setEndPos(shdr.sh_offset + needed_size);
594 }
647595 }
596
648597 shdr.sh_size = needed_size;
649598 self.markDirty(shdr_index);
650599}
651600
652pub fn markDirty(self: *Elf, shdr_index: u32) void {
601fn markDirty(self: *Elf, shdr_index: u32) void {
653602 if (self.zigObjectPtr()) |zo| {
654603 for ([_]?Symbol.Index{
655604 zo.debug_info_index,
......@@ -742,25 +691,27 @@ pub fn allocateChunk(self: *Elf, args: struct {
742691 }
743692 };
744693
745 log.debug("allocated chunk (size({x}),align({x})) at 0x{x} (file(0x{x}))", .{
746 args.size,
747 args.alignment.toByteUnits().?,
748 shdr.sh_addr + res.value,
749 shdr.sh_offset + res.value,
750 });
751
752694 const expand_section = if (self.atom(res.placement)) |placement_atom|
753695 placement_atom.nextAtom(self) == null
754696 else
755697 true;
756698 if (expand_section) {
757699 const needed_size = res.value + args.size;
758 if (shdr.sh_flags & elf.SHF_ALLOC != 0)
759 try self.growAllocSection(args.shndx, needed_size, args.alignment.toByteUnits().?)
760 else
761 try self.growNonAllocSection(args.shndx, needed_size, args.alignment.toByteUnits().?, true);
700 try self.growSection(args.shndx, needed_size, args.alignment.toByteUnits().?);
762701 }
763702
703 log.debug("allocated chunk (size({x}),align({x})) in {s} at 0x{x} (file(0x{x}))", .{
704 args.size,
705 args.alignment.toByteUnits().?,
706 self.getShString(shdr.sh_name),
707 shdr.sh_addr + res.value,
708 shdr.sh_offset + res.value,
709 });
710 log.debug(" placement {}, {s}", .{
711 res.placement,
712 if (self.atom(res.placement)) |atom_ptr| atom_ptr.name(self) else "",
713 });
714
764715 return res;
765716}
766717
......@@ -809,8 +760,6 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
809760
810761 const csu = try CsuObjects.init(arena, comp);
811762
812 // Here we will parse object and library files (if referenced).
813
814763 // csu prelude
815764 if (csu.crt0) |path| try parseObjectReportingFailure(self, path);
816765 if (csu.crti) |path| try parseObjectReportingFailure(self, path);
......@@ -1040,6 +989,13 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
1040989
1041990 // Beyond this point, everything has been allocated a virtual address and we can resolve
1042991 // the relocations, and commit objects to file.
992 for (self.objects.items) |index| {
993 self.file(index).?.object.dirty = false;
994 }
995 // TODO: would state tracking be more appropriate here? perhaps even custom relocation type?
996 self.rela_dyn.clearRetainingCapacity();
997 self.rela_plt.clearRetainingCapacity();
998
1043999 if (self.zigObjectPtr()) |zo| {
10441000 var has_reloc_errors = false;
10451001 for (zo.atoms_indexes.items) |atom_index| {
......@@ -1069,6 +1025,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
10691025 try self.writeShdrTable();
10701026 try self.writeAtoms();
10711027 try self.writeMergeSections();
1028
10721029 self.writeSyntheticSections() catch |err| switch (err) {
10731030 error.RelocFailure => return error.FlushFailure,
10741031 error.UnsupportedCpuArch => {
......@@ -1401,7 +1358,6 @@ pub fn parseLibraryReportingFailure(self: *Elf, lib: SystemLib, must_link: bool)
14011358fn parseLibrary(self: *Elf, lib: SystemLib, must_link: bool) ParseError!void {
14021359 const tracy = trace(@src());
14031360 defer tracy.end();
1404
14051361 if (try Archive.isArchive(lib.path)) {
14061362 try self.parseArchive(lib.path, must_link);
14071363 } else if (try SharedObject.isSharedObject(lib.path)) {
......@@ -2801,9 +2757,10 @@ pub fn resolveMergeSections(self: *Elf) !void {
28012757
28022758 var has_errors = false;
28032759 for (self.objects.items) |index| {
2804 const file_ptr = self.file(index).?;
2805 if (!file_ptr.isAlive()) continue;
2806 file_ptr.object.initInputMergeSections(self) catch |err| switch (err) {
2760 const object = self.file(index).?.object;
2761 if (!object.alive) continue;
2762 if (!object.dirty) continue;
2763 object.initInputMergeSections(self) catch |err| switch (err) {
28072764 error.LinkFailure => has_errors = true,
28082765 else => |e| return e,
28092766 };
......@@ -2812,15 +2769,17 @@ pub fn resolveMergeSections(self: *Elf) !void {
28122769 if (has_errors) return error.FlushFailure;
28132770
28142771 for (self.objects.items) |index| {
2815 const file_ptr = self.file(index).?;
2816 if (!file_ptr.isAlive()) continue;
2817 try file_ptr.object.initOutputMergeSections(self);
2772 const object = self.file(index).?.object;
2773 if (!object.alive) continue;
2774 if (!object.dirty) continue;
2775 try object.initOutputMergeSections(self);
28182776 }
28192777
28202778 for (self.objects.items) |index| {
2821 const file_ptr = self.file(index).?;
2822 if (!file_ptr.isAlive()) continue;
2823 file_ptr.object.resolveMergeSubsections(self) catch |err| switch (err) {
2779 const object = self.file(index).?.object;
2780 if (!object.alive) continue;
2781 if (!object.dirty) continue;
2782 object.resolveMergeSubsections(self) catch |err| switch (err) {
28242783 error.LinkFailure => has_errors = true,
28252784 else => |e| return e,
28262785 };
......@@ -2907,7 +2866,6 @@ fn initSyntheticSections(self: *Elf) !void {
29072866 elf.SHT_PROGBITS,
29082867 .flags = elf.SHF_ALLOC,
29092868 .addralign = ptr_size,
2910 .offset = std.math.maxInt(u64),
29112869 });
29122870 }
29132871 if (comp.link_eh_frame_hdr and self.eh_frame_hdr_section_index == null) {
......@@ -2916,7 +2874,6 @@ fn initSyntheticSections(self: *Elf) !void {
29162874 .type = elf.SHT_PROGBITS,
29172875 .flags = elf.SHF_ALLOC,
29182876 .addralign = 4,
2919 .offset = std.math.maxInt(u64),
29202877 });
29212878 }
29222879 }
......@@ -2927,7 +2884,6 @@ fn initSyntheticSections(self: *Elf) !void {
29272884 .type = elf.SHT_PROGBITS,
29282885 .flags = elf.SHF_ALLOC | elf.SHF_WRITE,
29292886 .addralign = ptr_size,
2930 .offset = std.math.maxInt(u64),
29312887 });
29322888 }
29332889
......@@ -2937,7 +2893,6 @@ fn initSyntheticSections(self: *Elf) !void {
29372893 .type = elf.SHT_PROGBITS,
29382894 .flags = elf.SHF_ALLOC | elf.SHF_WRITE,
29392895 .addralign = @alignOf(u64),
2940 .offset = std.math.maxInt(u64),
29412896 });
29422897 }
29432898
......@@ -2959,7 +2914,6 @@ fn initSyntheticSections(self: *Elf) !void {
29592914 .flags = elf.SHF_ALLOC,
29602915 .addralign = @alignOf(elf.Elf64_Rela),
29612916 .entsize = @sizeOf(elf.Elf64_Rela),
2962 .offset = std.math.maxInt(u64),
29632917 });
29642918 }
29652919
......@@ -2970,7 +2924,6 @@ fn initSyntheticSections(self: *Elf) !void {
29702924 .type = elf.SHT_PROGBITS,
29712925 .flags = elf.SHF_ALLOC | elf.SHF_EXECINSTR,
29722926 .addralign = 16,
2973 .offset = std.math.maxInt(u64),
29742927 });
29752928 }
29762929 if (self.rela_plt_section_index == null) {
......@@ -2980,7 +2933,6 @@ fn initSyntheticSections(self: *Elf) !void {
29802933 .flags = elf.SHF_ALLOC,
29812934 .addralign = @alignOf(elf.Elf64_Rela),
29822935 .entsize = @sizeOf(elf.Elf64_Rela),
2983 .offset = std.math.maxInt(u64),
29842936 });
29852937 }
29862938 }
......@@ -2991,7 +2943,6 @@ fn initSyntheticSections(self: *Elf) !void {
29912943 .type = elf.SHT_PROGBITS,
29922944 .flags = elf.SHF_ALLOC | elf.SHF_EXECINSTR,
29932945 .addralign = 16,
2994 .offset = std.math.maxInt(u64),
29952946 });
29962947 }
29972948
......@@ -3000,7 +2951,6 @@ fn initSyntheticSections(self: *Elf) !void {
30002951 .name = try self.insertShString(".copyrel"),
30012952 .type = elf.SHT_NOBITS,
30022953 .flags = elf.SHF_ALLOC | elf.SHF_WRITE,
3003 .offset = std.math.maxInt(u64),
30042954 });
30052955 }
30062956
......@@ -3019,7 +2969,6 @@ fn initSyntheticSections(self: *Elf) !void {
30192969 .type = elf.SHT_PROGBITS,
30202970 .flags = elf.SHF_ALLOC,
30212971 .addralign = 1,
3022 .offset = std.math.maxInt(u64),
30232972 });
30242973 }
30252974
......@@ -3031,7 +2980,6 @@ fn initSyntheticSections(self: *Elf) !void {
30312980 .type = elf.SHT_STRTAB,
30322981 .entsize = 1,
30332982 .addralign = 1,
3034 .offset = std.math.maxInt(u64),
30352983 });
30362984 }
30372985 if (self.dynamic_section_index == null) {
......@@ -3041,7 +2989,6 @@ fn initSyntheticSections(self: *Elf) !void {
30412989 .type = elf.SHT_DYNAMIC,
30422990 .entsize = @sizeOf(elf.Elf64_Dyn),
30432991 .addralign = @alignOf(elf.Elf64_Dyn),
3044 .offset = std.math.maxInt(u64),
30452992 });
30462993 }
30472994 if (self.dynsymtab_section_index == null) {
......@@ -3052,7 +2999,6 @@ fn initSyntheticSections(self: *Elf) !void {
30522999 .addralign = @alignOf(elf.Elf64_Sym),
30533000 .entsize = @sizeOf(elf.Elf64_Sym),
30543001 .info = 1,
3055 .offset = std.math.maxInt(u64),
30563002 });
30573003 }
30583004 if (self.hash_section_index == null) {
......@@ -3062,7 +3008,6 @@ fn initSyntheticSections(self: *Elf) !void {
30623008 .type = elf.SHT_HASH,
30633009 .addralign = 4,
30643010 .entsize = 4,
3065 .offset = std.math.maxInt(u64),
30663011 });
30673012 }
30683013 if (self.gnu_hash_section_index == null) {
......@@ -3071,7 +3016,6 @@ fn initSyntheticSections(self: *Elf) !void {
30713016 .flags = elf.SHF_ALLOC,
30723017 .type = elf.SHT_GNU_HASH,
30733018 .addralign = 8,
3074 .offset = std.math.maxInt(u64),
30753019 });
30763020 }
30773021
......@@ -3087,7 +3031,6 @@ fn initSyntheticSections(self: *Elf) !void {
30873031 .type = elf.SHT_GNU_VERSYM,
30883032 .addralign = @alignOf(elf.Elf64_Versym),
30893033 .entsize = @sizeOf(elf.Elf64_Versym),
3090 .offset = std.math.maxInt(u64),
30913034 });
30923035 }
30933036 if (self.verneed_section_index == null) {
......@@ -3096,7 +3039,6 @@ fn initSyntheticSections(self: *Elf) !void {
30963039 .flags = elf.SHF_ALLOC,
30973040 .type = elf.SHT_GNU_VERNEED,
30983041 .addralign = @alignOf(elf.Elf64_Verneed),
3099 .offset = std.math.maxInt(u64),
31003042 });
31013043 }
31023044 }
......@@ -3117,7 +3059,6 @@ pub fn initSymtab(self: *Elf) !void {
31173059 .type = elf.SHT_SYMTAB,
31183060 .addralign = if (small_ptr) @alignOf(elf.Elf32_Sym) else @alignOf(elf.Elf64_Sym),
31193061 .entsize = if (small_ptr) @sizeOf(elf.Elf32_Sym) else @sizeOf(elf.Elf64_Sym),
3120 .offset = std.math.maxInt(u64),
31213062 });
31223063 }
31233064 if (self.strtab_section_index == null) {
......@@ -3126,7 +3067,6 @@ pub fn initSymtab(self: *Elf) !void {
31263067 .type = elf.SHT_STRTAB,
31273068 .entsize = 1,
31283069 .addralign = 1,
3129 .offset = std.math.maxInt(u64),
31303070 });
31313071 }
31323072}
......@@ -3138,7 +3078,6 @@ pub fn initShStrtab(self: *Elf) !void {
31383078 .type = elf.SHT_STRTAB,
31393079 .entsize = 1,
31403080 .addralign = 1,
3141 .offset = std.math.maxInt(u64),
31423081 });
31433082 }
31443083}
......@@ -3219,7 +3158,7 @@ fn sortInitFini(self: *Elf) !void {
32193158
32203159 for (slice.items(.shdr), slice.items(.atom_list_2)) |shdr, *atom_list| {
32213160 if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue;
3222 if (atom_list.atoms.items.len == 0) continue;
3161 if (atom_list.atoms.keys().len == 0) continue;
32233162
32243163 var is_init_fini = false;
32253164 var is_ctor_dtor = false;
......@@ -3236,10 +3175,10 @@ fn sortInitFini(self: *Elf) !void {
32363175 if (!is_init_fini and !is_ctor_dtor) continue;
32373176
32383177 var entries = std.ArrayList(Entry).init(gpa);
3239 try entries.ensureTotalCapacityPrecise(atom_list.atoms.items.len);
3178 try entries.ensureTotalCapacityPrecise(atom_list.atoms.keys().len);
32403179 defer entries.deinit();
32413180
3242 for (atom_list.atoms.items) |ref| {
3181 for (atom_list.atoms.keys()) |ref| {
32433182 const atom_ptr = self.atom(ref).?;
32443183 const object = atom_ptr.file(self).?.object;
32453184 const priority = blk: {
......@@ -3260,7 +3199,7 @@ fn sortInitFini(self: *Elf) !void {
32603199
32613200 atom_list.atoms.clearRetainingCapacity();
32623201 for (entries.items) |entry| {
3263 atom_list.atoms.appendAssumeCapacity(entry.atom_ref);
3202 _ = atom_list.atoms.getOrPutAssumeCapacity(entry.atom_ref);
32643203 }
32653204 }
32663205}
......@@ -3506,7 +3445,7 @@ fn resetShdrIndexes(self: *Elf, backlinks: []const u32) void {
35063445 const slice = self.sections.slice();
35073446 for (slice.items(.shdr), slice.items(.atom_list_2)) |*shdr, *atom_list| {
35083447 atom_list.output_section_index = backlinks[atom_list.output_section_index];
3509 for (atom_list.atoms.items) |ref| {
3448 for (atom_list.atoms.keys()) |ref| {
35103449 self.atom(ref).?.output_section_index = atom_list.output_section_index;
35113450 }
35123451 if (shdr.sh_type == elf.SHT_RELA) {
......@@ -3518,12 +3457,7 @@ fn resetShdrIndexes(self: *Elf, backlinks: []const u32) void {
35183457 }
35193458 }
35203459
3521 if (self.zigObjectPtr()) |zo| {
3522 for (zo.atoms_indexes.items) |atom_index| {
3523 const atom_ptr = zo.atom(atom_index) orelse continue;
3524 atom_ptr.output_section_index = backlinks[atom_ptr.output_section_index];
3525 }
3526 }
3460 if (self.zigObjectPtr()) |zo| zo.resetShdrIndexes(backlinks);
35273461
35283462 for (self.comdat_group_sections.items) |*cg| {
35293463 cg.shndx = backlinks[cg.shndx];
......@@ -3585,20 +3519,24 @@ fn resetShdrIndexes(self: *Elf, backlinks: []const u32) void {
35853519fn updateSectionSizes(self: *Elf) !void {
35863520 const slice = self.sections.slice();
35873521 for (slice.items(.shdr), slice.items(.atom_list_2)) |shdr, *atom_list| {
3588 if (atom_list.atoms.items.len == 0) continue;
3522 if (atom_list.atoms.keys().len == 0) continue;
3523 if (!atom_list.dirty) continue;
35893524 if (self.requiresThunks() and shdr.sh_flags & elf.SHF_EXECINSTR != 0) continue;
35903525 atom_list.updateSize(self);
35913526 try atom_list.allocate(self);
3527 atom_list.dirty = false;
35923528 }
35933529
35943530 if (self.requiresThunks()) {
35953531 for (slice.items(.shdr), slice.items(.atom_list_2)) |shdr, *atom_list| {
35963532 if (shdr.sh_flags & elf.SHF_EXECINSTR == 0) continue;
3597 if (atom_list.atoms.items.len == 0) continue;
3533 if (atom_list.atoms.keys().len == 0) continue;
3534 if (!atom_list.dirty) continue;
35983535
35993536 // Create jump/branch range extenders if needed.
36003537 try self.createThunks(atom_list);
36013538 try atom_list.allocate(self);
3539 atom_list.dirty = false;
36023540 }
36033541
36043542 // FIXME:JK this will hopefully not be needed once we create a link from Atom/Thunk to AtomList.
......@@ -3882,57 +3820,55 @@ pub fn allocateAllocSections(self: *Elf) !void {
38823820 }
38833821
38843822 const first = slice.items(.shdr)[cover.items[0]];
3885 var new_offset = try self.findFreeSpace(filesz, @"align");
38863823 const phndx = self.getPhdr(.{ .type = elf.PT_LOAD, .flags = shdrToPhdrFlags(first.sh_flags) }).?;
38873824 const phdr = &self.phdrs.items[phndx];
3888 phdr.p_offset = new_offset;
3889 phdr.p_vaddr = first.sh_addr;
3890 phdr.p_paddr = first.sh_addr;
3891 phdr.p_memsz = memsz;
3892 phdr.p_filesz = filesz;
3893 phdr.p_align = @"align";
3825 const allocated_size = self.allocatedSize(phdr.p_offset);
3826 if (filesz > allocated_size) {
3827 const old_offset = phdr.p_offset;
3828 phdr.p_offset = 0;
3829 var new_offset = try self.findFreeSpace(filesz, @"align");
3830 phdr.p_offset = new_offset;
3831
3832 log.debug("moving phdr({d}) from 0x{x} to 0x{x}", .{ phndx, old_offset, new_offset });
3833
3834 for (cover.items) |shndx| {
3835 const shdr = &slice.items(.shdr)[shndx];
3836 slice.items(.phndx)[shndx] = phndx;
3837 if (shdr.sh_type == elf.SHT_NOBITS) {
3838 shdr.sh_offset = 0;
3839 continue;
3840 }
3841 new_offset = alignment.@"align"(shndx, shdr.sh_addralign, new_offset);
38943842
3895 for (cover.items) |shndx| {
3896 const shdr = &slice.items(.shdr)[shndx];
3897 slice.items(.phndx)[shndx] = phndx;
3898 if (shdr.sh_type == elf.SHT_NOBITS) {
3899 shdr.sh_offset = 0;
3900 continue;
3901 }
3902 new_offset = alignment.@"align"(shndx, shdr.sh_addralign, new_offset);
3903
3904 if (self.zigObjectPtr()) |zo| blk: {
3905 const existing_size = for ([_]?Symbol.Index{
3906 zo.text_index,
3907 zo.rodata_index,
3908 zo.data_relro_index,
3909 zo.data_index,
3910 zo.tdata_index,
3911 zo.eh_frame_index,
3912 }) |maybe_sym_index| {
3913 const sect_sym_index = maybe_sym_index orelse continue;
3914 const sect_atom_ptr = zo.symbol(sect_sym_index).atom(self).?;
3915 if (sect_atom_ptr.output_section_index != shndx) continue;
3916 break sect_atom_ptr.size;
3917 } else break :blk;
39183843 log.debug("moving {s} from 0x{x} to 0x{x}", .{
39193844 self.getShString(shdr.sh_name),
39203845 shdr.sh_offset,
39213846 new_offset,
39223847 });
3923 const amt = try self.base.file.?.copyRangeAll(
3924 shdr.sh_offset,
3925 self.base.file.?,
3926 new_offset,
3927 existing_size,
3928 );
3929 if (amt != existing_size) return error.InputOutput;
3930 }
39313848
3932 shdr.sh_offset = new_offset;
3933 new_offset += shdr.sh_size;
3849 if (shdr.sh_offset > 0) {
3850 // Get size actually commited to the output file.
3851 const existing_size = self.sectionSize(shndx);
3852 const amt = try self.base.file.?.copyRangeAll(
3853 shdr.sh_offset,
3854 self.base.file.?,
3855 new_offset,
3856 existing_size,
3857 );
3858 if (amt != existing_size) return error.InputOutput;
3859 }
3860
3861 shdr.sh_offset = new_offset;
3862 new_offset += shdr.sh_size;
3863 }
39343864 }
39353865
3866 phdr.p_vaddr = first.sh_addr;
3867 phdr.p_paddr = first.sh_addr;
3868 phdr.p_memsz = memsz;
3869 phdr.p_filesz = filesz;
3870 phdr.p_align = @"align";
3871
39363872 addr = mem.alignForward(u64, addr, self.page_size);
39373873 }
39383874}
......@@ -3947,27 +3883,14 @@ pub fn allocateNonAllocSections(self: *Elf) !void {
39473883 shdr.sh_size = 0;
39483884 const new_offset = try self.findFreeSpace(needed_size, shdr.sh_addralign);
39493885
3950 if (self.zigObjectPtr()) |zo| blk: {
3951 const existing_size = for ([_]?Symbol.Index{
3952 zo.debug_info_index,
3953 zo.debug_abbrev_index,
3954 zo.debug_aranges_index,
3955 zo.debug_str_index,
3956 zo.debug_line_index,
3957 zo.debug_line_str_index,
3958 zo.debug_loclists_index,
3959 zo.debug_rnglists_index,
3960 }) |maybe_sym_index| {
3961 const sym_index = maybe_sym_index orelse continue;
3962 const sym = zo.symbol(sym_index);
3963 const atom_ptr = sym.atom(self).?;
3964 if (atom_ptr.output_section_index == shndx) break atom_ptr.size;
3965 } else break :blk;
3966 log.debug("moving {s} from 0x{x} to 0x{x}", .{
3967 self.getShString(shdr.sh_name),
3968 shdr.sh_offset,
3969 new_offset,
3970 });
3886 log.debug("moving {s} from 0x{x} to 0x{x}", .{
3887 self.getShString(shdr.sh_name),
3888 shdr.sh_offset,
3889 new_offset,
3890 });
3891
3892 if (shdr.sh_offset > 0) {
3893 const existing_size = self.sectionSize(@intCast(shndx));
39713894 const amt = try self.base.file.?.copyRangeAll(
39723895 shdr.sh_offset,
39733896 self.base.file.?,
......@@ -4058,7 +3981,7 @@ fn writeAtoms(self: *Elf) !void {
40583981 var has_reloc_errors = false;
40593982 for (slice.items(.shdr), slice.items(.atom_list_2)) |shdr, atom_list| {
40603983 if (shdr.sh_type == elf.SHT_NOBITS) continue;
4061 if (atom_list.atoms.items.len == 0) continue;
3984 if (atom_list.atoms.keys().len == 0) continue;
40623985 atom_list.write(&buffer, &undefs, self) catch |err| switch (err) {
40633986 error.UnsupportedCpuArch => {
40643987 try self.reportUnsupportedCpuArch();
......@@ -4816,7 +4739,6 @@ pub fn addRelaShdr(self: *Elf, name: u32, shndx: u32) !u32 {
48164739 .entsize = entsize,
48174740 .info = shndx,
48184741 .addralign = addralign,
4819 .offset = std.math.maxInt(u64),
48204742 });
48214743}
48224744
......@@ -4828,7 +4750,6 @@ pub const AddSectionOpts = struct {
48284750 info: u32 = 0,
48294751 addralign: u64 = 0,
48304752 entsize: u64 = 0,
4831 offset: u64 = 0,
48324753};
48334754
48344755pub fn addSection(self: *Elf, opts: AddSectionOpts) !u32 {
......@@ -4840,7 +4761,7 @@ pub fn addSection(self: *Elf, opts: AddSectionOpts) !u32 {
48404761 .sh_type = opts.type,
48414762 .sh_flags = opts.flags,
48424763 .sh_addr = 0,
4843 .sh_offset = opts.offset,
4764 .sh_offset = 0,
48444765 .sh_size = 0,
48454766 .sh_link = opts.link,
48464767 .sh_info = opts.info,
......@@ -4863,6 +4784,7 @@ const RelaDyn = struct {
48634784 sym: u64 = 0,
48644785 type: u32,
48654786 addend: i64 = 0,
4787 target: ?*const Symbol = null,
48664788};
48674789
48684790pub fn addRelaDyn(self: *Elf, opts: RelaDyn) !void {
......@@ -4871,6 +4793,13 @@ pub fn addRelaDyn(self: *Elf, opts: RelaDyn) !void {
48714793}
48724794
48734795pub fn addRelaDynAssumeCapacity(self: *Elf, opts: RelaDyn) void {
4796 relocs_log.debug(" {s}: [{x} => {d}({s})] + {x}", .{
4797 relocation.fmtRelocType(opts.type, self.getTarget().cpu.arch),
4798 opts.offset,
4799 opts.sym,
4800 if (opts.target) |sym| sym.name(self) else "",
4801 opts.addend,
4802 });
48744803 self.rela_dyn.appendAssumeCapacity(.{
48754804 .r_offset = opts.offset,
48764805 .r_info = (opts.sym << 32) | opts.type,
......@@ -5703,6 +5632,12 @@ const Section = struct {
57035632 free_list: std.ArrayListUnmanaged(Ref) = .empty,
57045633};
57055634
5635pub fn sectionSize(self: *Elf, shndx: u32) u64 {
5636 const last_atom_ref = self.sections.items(.last_atom)[shndx];
5637 const atom_ptr = self.atom(last_atom_ref) orelse return 0;
5638 return @as(u64, @intCast(atom_ptr.value)) + atom_ptr.size;
5639}
5640
57065641fn defaultEntrySymbolName(cpu_arch: std.Target.Cpu.Arch) []const u8 {
57075642 return switch (cpu_arch) {
57085643 .mips, .mipsel, .mips64, .mips64el => "__start",
......@@ -5732,20 +5667,20 @@ fn createThunks(elf_file: *Elf, atom_list: *AtomList) !void {
57325667 }
57335668 }.advance;
57345669
5735 for (atom_list.atoms.items) |ref| {
5670 for (atom_list.atoms.keys()) |ref| {
57365671 elf_file.atom(ref).?.value = -1;
57375672 }
57385673
57395674 var i: usize = 0;
5740 while (i < atom_list.atoms.items.len) {
5675 while (i < atom_list.atoms.keys().len) {
57415676 const start = i;
5742 const start_atom = elf_file.atom(atom_list.atoms.items[start]).?;
5677 const start_atom = elf_file.atom(atom_list.atoms.keys()[start]).?;
57435678 assert(start_atom.alive);
57445679 start_atom.value = try advance(atom_list, start_atom.size, start_atom.alignment);
57455680 i += 1;
57465681
5747 while (i < atom_list.atoms.items.len) : (i += 1) {
5748 const atom_ptr = elf_file.atom(atom_list.atoms.items[i]).?;
5682 while (i < atom_list.atoms.keys().len) : (i += 1) {
5683 const atom_ptr = elf_file.atom(atom_list.atoms.keys()[i]).?;
57495684 assert(atom_ptr.alive);
57505685 if (@as(i64, @intCast(atom_ptr.alignment.forward(atom_list.size))) - start_atom.value >= max_distance)
57515686 break;
......@@ -5758,7 +5693,7 @@ fn createThunks(elf_file: *Elf, atom_list: *AtomList) !void {
57585693 thunk_ptr.output_section_index = atom_list.output_section_index;
57595694
57605695 // Scan relocs in the group and create trampolines for any unreachable callsite
5761 for (atom_list.atoms.items[start..i]) |ref| {
5696 for (atom_list.atoms.keys()[start..i]) |ref| {
57625697 const atom_ptr = elf_file.atom(ref).?;
57635698 const file_ptr = atom_ptr.file(elf_file).?;
57645699 log.debug("atom({}) {s}", .{ ref, atom_ptr.name(elf_file) });
......@@ -5801,6 +5736,7 @@ const assert = std.debug.assert;
58015736const elf = std.elf;
58025737const fs = std.fs;
58035738const log = std.log.scoped(.link);
5739const relocs_log = std.log.scoped(.link_relocs);
58045740const state_log = std.log.scoped(.link_state);
58055741const math = std.math;
58065742const mem = std.mem;
src/link/Elf/Atom.zig+17-2
......@@ -118,10 +118,19 @@ pub fn capacity(self: Atom, elf_file: *Elf) u64 {
118118 return @intCast(next_addr - self.address(elf_file));
119119}
120120
121pub fn fileCapacity(self: Atom, elf_file: *Elf) u64 {
122 const self_off = self.offset(elf_file);
123 const next_off = if (self.nextAtom(elf_file)) |next_atom|
124 next_atom.offset(elf_file)
125 else
126 self_off + elf_file.allocatedSize(self_off);
127 return @intCast(next_off - self_off);
128}
129
121130pub fn freeListEligible(self: Atom, elf_file: *Elf) bool {
122131 // No need to keep a free list node for the last block.
123132 const next = self.nextAtom(elf_file) orelse return false;
124 const cap: u64 = @intCast(next.address(elf_file) - self.address(elf_file));
133 const cap: u64 = @intCast(next.value - self.value);
125134 const ideal_cap = Elf.padToIdeal(self.size);
126135 if (cap <= ideal_cap) return false;
127136 const surplus = cap - ideal_cap;
......@@ -723,6 +732,7 @@ fn resolveDynAbsReloc(
723732 .sym = target.extra(elf_file).dynamic,
724733 .type = relocation.encode(.abs, cpu_arch),
725734 .addend = A,
735 .target = target,
726736 });
727737 try applyDynamicReloc(A, elf_file, writer);
728738 } else {
......@@ -737,6 +747,7 @@ fn resolveDynAbsReloc(
737747 .sym = target.extra(elf_file).dynamic,
738748 .type = relocation.encode(.abs, cpu_arch),
739749 .addend = A,
750 .target = target,
740751 });
741752 try applyDynamicReloc(A, elf_file, writer);
742753 } else {
......@@ -750,6 +761,7 @@ fn resolveDynAbsReloc(
750761 .sym = target.extra(elf_file).dynamic,
751762 .type = relocation.encode(.abs, cpu_arch),
752763 .addend = A,
764 .target = target,
753765 });
754766 try applyDynamicReloc(A, elf_file, writer);
755767 },
......@@ -759,6 +771,7 @@ fn resolveDynAbsReloc(
759771 .offset = P,
760772 .type = relocation.encode(.rel, cpu_arch),
761773 .addend = S + A,
774 .target = target,
762775 });
763776 try applyDynamicReloc(S + A, elf_file, writer);
764777 },
......@@ -769,6 +782,7 @@ fn resolveDynAbsReloc(
769782 .offset = P,
770783 .type = relocation.encode(.irel, cpu_arch),
771784 .addend = S_ + A,
785 .target = target,
772786 });
773787 try applyDynamicReloc(S_ + A, elf_file, writer);
774788 },
......@@ -922,9 +936,10 @@ fn format2(
922936 _ = unused_fmt_string;
923937 const atom = ctx.atom;
924938 const elf_file = ctx.elf_file;
925 try writer.print("atom({d}) : {s} : @{x} : shdr({d}) : align({x}) : size({x})", .{
939 try writer.print("atom({d}) : {s} : @{x} : shdr({d}) : align({x}) : size({x}) : prev({}) : next({})", .{
926940 atom.atom_index, atom.name(elf_file), atom.address(elf_file),
927941 atom.output_section_index, atom.alignment.toByteUnits() orelse 0, atom.size,
942 atom.prev_atom_ref, atom.next_atom_ref,
928943 });
929944 if (atom.fdes(elf_file).len > 0) {
930945 try writer.writeAll(" : fdes{ ");
src/link/Elf/AtomList.zig+27-19
......@@ -2,7 +2,10 @@ value: i64 = 0,
22size: u64 = 0,
33alignment: Atom.Alignment = .@"1",
44output_section_index: u32 = 0,
5atoms: std.ArrayListUnmanaged(Elf.Ref) = .empty,
5// atoms: std.ArrayListUnmanaged(Elf.Ref) = .empty,
6atoms: std.AutoArrayHashMapUnmanaged(Elf.Ref, void) = .empty,
7
8dirty: bool = true,
69
710pub fn deinit(list: *AtomList, allocator: Allocator) void {
811 list.atoms.deinit(allocator);
......@@ -19,10 +22,8 @@ pub fn offset(list: AtomList, elf_file: *Elf) u64 {
1922}
2023
2124pub fn updateSize(list: *AtomList, elf_file: *Elf) void {
22 // TODO perhaps a 'stale' flag would be better here?
23 list.size = 0;
24 list.alignment = .@"1";
25 for (list.atoms.items) |ref| {
25 assert(list.dirty);
26 for (list.atoms.keys()) |ref| {
2627 const atom_ptr = elf_file.atom(ref).?;
2728 assert(atom_ptr.alive);
2829 const off = atom_ptr.alignment.forward(list.size);
......@@ -34,6 +35,8 @@ pub fn updateSize(list: *AtomList, elf_file: *Elf) void {
3435}
3536
3637pub fn allocate(list: *AtomList, elf_file: *Elf) !void {
38 assert(list.dirty);
39
3740 const alloc_res = try elf_file.allocateChunk(.{
3841 .shndx = list.output_section_index,
3942 .size = list.size,
......@@ -42,6 +45,8 @@ pub fn allocate(list: *AtomList, elf_file: *Elf) !void {
4245 });
4346 list.value = @intCast(alloc_res.value);
4447
48 log.debug("allocated atom_list({d}) at 0x{x}", .{ list.output_section_index, list.address(elf_file) });
49
4550 const slice = elf_file.sections.slice();
4651 const shdr = &slice.items(.shdr)[list.output_section_index];
4752 const last_atom_ref = &slice.items(.last_atom)[list.output_section_index];
......@@ -56,13 +61,13 @@ pub fn allocate(list: *AtomList, elf_file: *Elf) !void {
5661 // FIXME:JK this currently ignores Thunks as valid chunks.
5762 {
5863 var idx: usize = 0;
59 while (idx < list.atoms.items.len) : (idx += 1) {
60 const curr_atom_ptr = elf_file.atom(list.atoms.items[idx]).?;
64 while (idx < list.atoms.keys().len) : (idx += 1) {
65 const curr_atom_ptr = elf_file.atom(list.atoms.keys()[idx]).?;
6166 if (idx > 0) {
62 curr_atom_ptr.prev_atom_ref = list.atoms.items[idx - 1];
67 curr_atom_ptr.prev_atom_ref = list.atoms.keys()[idx - 1];
6368 }
64 if (idx + 1 < list.atoms.items.len) {
65 curr_atom_ptr.next_atom_ref = list.atoms.items[idx + 1];
69 if (idx + 1 < list.atoms.keys().len) {
70 curr_atom_ptr.next_atom_ref = list.atoms.keys()[idx + 1];
6671 }
6772 }
6873 }
......@@ -74,17 +79,20 @@ pub fn allocate(list: *AtomList, elf_file: *Elf) !void {
7479 }
7580
7681 // FIXME:JK if we had a link from Atom to parent AtomList we would not need to update Atom's value or osec index
77 for (list.atoms.items) |ref| {
82 for (list.atoms.keys()) |ref| {
7883 const atom_ptr = elf_file.atom(ref).?;
7984 atom_ptr.output_section_index = list.output_section_index;
8085 atom_ptr.value += list.value;
8186 }
87
88 list.dirty = false;
8289}
8390
8491pub fn write(list: AtomList, buffer: *std.ArrayList(u8), undefs: anytype, elf_file: *Elf) !void {
8592 const gpa = elf_file.base.comp.gpa;
8693 const osec = elf_file.sections.items(.shdr)[list.output_section_index];
8794 assert(osec.sh_type != elf.SHT_NOBITS);
95 assert(!list.dirty);
8896
8997 log.debug("writing atoms in section '{s}'", .{elf_file.getShString(osec.sh_name)});
9098
......@@ -92,7 +100,7 @@ pub fn write(list: AtomList, buffer: *std.ArrayList(u8), undefs: anytype, elf_fi
92100 try buffer.ensureUnusedCapacity(list_size);
93101 buffer.appendNTimesAssumeCapacity(0, list_size);
94102
95 for (list.atoms.items) |ref| {
103 for (list.atoms.keys()) |ref| {
96104 const atom_ptr = elf_file.atom(ref).?;
97105 assert(atom_ptr.alive);
98106
......@@ -128,7 +136,7 @@ pub fn writeRelocatable(list: AtomList, buffer: *std.ArrayList(u8), elf_file: *E
128136 try buffer.ensureUnusedCapacity(list_size);
129137 buffer.appendNTimesAssumeCapacity(0, list_size);
130138
131 for (list.atoms.items) |ref| {
139 for (list.atoms.keys()) |ref| {
132140 const atom_ptr = elf_file.atom(ref).?;
133141 assert(atom_ptr.alive);
134142
......@@ -149,13 +157,13 @@ pub fn writeRelocatable(list: AtomList, buffer: *std.ArrayList(u8), elf_file: *E
149157}
150158
151159pub fn firstAtom(list: AtomList, elf_file: *Elf) *Atom {
152 assert(list.atoms.items.len > 0);
153 return elf_file.atom(list.atoms.items[0]).?;
160 assert(list.atoms.keys().len > 0);
161 return elf_file.atom(list.atoms.keys()[0]).?;
154162}
155163
156164pub fn lastAtom(list: AtomList, elf_file: *Elf) *Atom {
157 assert(list.atoms.items.len > 0);
158 return elf_file.atom(list.atoms.items[list.atoms.items.len - 1]).?;
165 assert(list.atoms.keys().len > 0);
166 return elf_file.atom(list.atoms.keys()[list.atoms.keys().len - 1]).?;
159167}
160168
161169pub fn format(
......@@ -191,9 +199,9 @@ fn format2(
191199 list.alignment.toByteUnits() orelse 0, list.size,
192200 });
193201 try writer.writeAll(" : atoms{ ");
194 for (list.atoms.items, 0..) |ref, i| {
202 for (list.atoms.keys(), 0..) |ref, i| {
195203 try writer.print("{}", .{ref});
196 if (i < list.atoms.items.len - 1) try writer.writeAll(", ");
204 if (i < list.atoms.keys().len - 1) try writer.writeAll(", ");
197205 }
198206 try writer.writeAll(" }");
199207}
src/link/Elf/Object.zig+2-1
......@@ -29,6 +29,7 @@ cies: std.ArrayListUnmanaged(Cie) = .empty,
2929eh_frame_data: std.ArrayListUnmanaged(u8) = .empty,
3030
3131alive: bool = true,
32dirty: bool = true,
3233num_dynrelocs: u32 = 0,
3334
3435output_symtab_ctx: Elf.SymtabCtx = .{},
......@@ -917,7 +918,7 @@ pub fn initOutputSections(self: *Object, elf_file: *Elf) !void {
917918 });
918919 const atom_list = &elf_file.sections.items(.atom_list_2)[osec];
919920 atom_list.output_section_index = osec;
920 try atom_list.atoms.append(elf_file.base.comp.gpa, atom_ptr.ref());
921 _ = try atom_list.atoms.getOrPut(elf_file.base.comp.gpa, atom_ptr.ref());
921922 }
922923}
923924
src/link/Elf/Symbol.zig+10-5
......@@ -112,13 +112,16 @@ pub fn address(symbol: Symbol, opts: struct { plt: bool = true, trampoline: bool
112112 if (symbol.flags.has_trampoline and opts.trampoline) {
113113 return symbol.trampolineAddress(elf_file);
114114 }
115 if (symbol.flags.has_plt and opts.plt) {
116 if (!symbol.flags.is_canonical and symbol.flags.has_got) {
115 if (opts.plt) {
116 if (symbol.flags.has_pltgot) {
117 assert(!symbol.flags.is_canonical);
117118 // We have a non-lazy bound function pointer, use that!
118119 return symbol.pltGotAddress(elf_file);
119120 }
120 // Lazy-bound function it is!
121 return symbol.pltAddress(elf_file);
121 if (symbol.flags.has_plt) {
122 // Lazy-bound function it is!
123 return symbol.pltAddress(elf_file);
124 }
122125 }
123126 if (symbol.atom(elf_file)) |atom_ptr| {
124127 if (!atom_ptr.alive) {
......@@ -171,7 +174,7 @@ pub fn gotAddress(symbol: Symbol, elf_file: *Elf) i64 {
171174}
172175
173176pub fn pltGotAddress(symbol: Symbol, elf_file: *Elf) i64 {
174 if (!(symbol.flags.has_plt and symbol.flags.has_got)) return 0;
177 if (!symbol.flags.has_pltgot) return 0;
175178 const extras = symbol.extra(elf_file);
176179 const shdr = elf_file.sections.items(.shdr)[elf_file.plt_got_section_index.?];
177180 const cpu_arch = elf_file.getTarget().cpu.arch;
......@@ -430,6 +433,8 @@ pub const Flags = packed struct {
430433 has_plt: bool = false,
431434 /// Whether the PLT entry is canonical.
432435 is_canonical: bool = false,
436 /// Whether the PLT entry is indirected via GOT.
437 has_pltgot: bool = false,
433438
434439 /// Whether the symbol contains COPYREL directive.
435440 needs_copy_rel: bool = false,
src/link/Elf/ZigObject.zig+135-142
......@@ -101,6 +101,28 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {
101101 .dwarf => |v| {
102102 var dwarf = Dwarf.init(&elf_file.base, v);
103103
104 const addSectionSymbolWithAtom = struct {
105 fn addSectionSymbolWithAtom(
106 zo: *ZigObject,
107 allocator: Allocator,
108 name: [:0]const u8,
109 alignment: Atom.Alignment,
110 shndx: u32,
111 ) !Symbol.Index {
112 const name_off = try zo.addString(allocator, name);
113 const sym_index = try zo.addSectionSymbol(allocator, name_off, shndx);
114 const sym = zo.symbol(sym_index);
115 const atom_index = try zo.newAtom(allocator, name_off);
116 const atom_ptr = zo.atom(atom_index).?;
117 atom_ptr.alignment = alignment;
118 atom_ptr.output_section_index = shndx;
119 sym.ref = .{ .index = atom_index, .file = zo.index };
120 zo.symtab.items(.shndx)[sym.esym_index] = atom_index;
121 zo.symtab.items(.elf_sym)[sym.esym_index].st_shndx = SHN_ATOM;
122 return sym_index;
123 }
124 }.addSectionSymbolWithAtom;
125
104126 if (self.debug_str_index == null) {
105127 const osec = try elf_file.addSection(.{
106128 .name = try elf_file.insertShString(".debug_str"),
......@@ -110,8 +132,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {
110132 .addralign = 1,
111133 });
112134 self.debug_str_section_dirty = true;
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;
135 self.debug_str_index = try addSectionSymbolWithAtom(self, gpa, ".debug_str", .@"1", osec);
115136 }
116137
117138 if (self.debug_info_index == null) {
......@@ -121,8 +142,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {
121142 .addralign = 1,
122143 });
123144 self.debug_info_section_dirty = true;
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;
145 self.debug_info_index = try addSectionSymbolWithAtom(self, gpa, ".debug_info", .@"1", osec);
126146 }
127147
128148 if (self.debug_abbrev_index == null) {
......@@ -132,8 +152,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {
132152 .addralign = 1,
133153 });
134154 self.debug_abbrev_section_dirty = true;
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;
155 self.debug_abbrev_index = try addSectionSymbolWithAtom(self, gpa, ".debug_abbrev", .@"1", osec);
137156 }
138157
139158 if (self.debug_aranges_index == null) {
......@@ -143,8 +162,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {
143162 .addralign = 16,
144163 });
145164 self.debug_aranges_section_dirty = true;
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;
165 self.debug_aranges_index = try addSectionSymbolWithAtom(self, gpa, ".debug_aranges", .@"16", osec);
148166 }
149167
150168 if (self.debug_line_index == null) {
......@@ -154,8 +172,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {
154172 .addralign = 1,
155173 });
156174 self.debug_line_section_dirty = true;
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;
175 self.debug_line_index = try addSectionSymbolWithAtom(self, gpa, ".debug_line", .@"1", osec);
159176 }
160177
161178 if (self.debug_line_str_index == null) {
......@@ -167,8 +184,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {
167184 .addralign = 1,
168185 });
169186 self.debug_line_str_section_dirty = true;
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;
187 self.debug_line_str_index = try addSectionSymbolWithAtom(self, gpa, ".debug_line_str", .@"1", osec);
172188 }
173189
174190 if (self.debug_loclists_index == null) {
......@@ -178,8 +194,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {
178194 .addralign = 1,
179195 });
180196 self.debug_loclists_section_dirty = true;
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;
197 self.debug_loclists_index = try addSectionSymbolWithAtom(self, gpa, ".debug_loclists", .@"1", osec);
183198 }
184199
185200 if (self.debug_rnglists_index == null) {
......@@ -189,8 +204,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {
189204 .addralign = 1,
190205 });
191206 self.debug_rnglists_section_dirty = true;
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;
207 self.debug_rnglists_index = try addSectionSymbolWithAtom(self, gpa, ".debug_rnglists", .@"1", osec);
194208 }
195209
196210 if (self.eh_frame_index == null) {
......@@ -204,8 +218,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {
204218 .addralign = ptr_size,
205219 });
206220 self.eh_frame_section_dirty = true;
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;
221 self.eh_frame_index = try addSectionSymbolWithAtom(self, gpa, ".eh_frame", Atom.Alignment.fromNonzeroByteUnits(ptr_size), osec);
209222 }
210223
211224 try dwarf.initMetadata();
......@@ -336,8 +349,6 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi
336349 const atom_ptr = self.atom(sym.ref.index).?;
337350 if (!atom_ptr.alive) continue;
338351
339 log.debug("parsing relocs in {s}", .{sym.name(elf_file)});
340
341352 const relocs = &self.relocs.items[atom_ptr.relocsShndx().?];
342353 for (sect.units.items) |*unit| {
343354 try relocs.ensureUnusedCapacity(gpa, unit.cross_unit_relocs.items.len +
......@@ -350,12 +361,6 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi
350361 else
351362 0));
352363 const r_type = relocation.dwarf.crossSectionRelocType(dwarf.format, cpu_arch);
353 log.debug(" {s} <- r_off={x}, r_add={x}, r_type={}", .{
354 self.symbol(sym_index).name(elf_file),
355 r_offset,
356 r_addend,
357 relocation.fmtRelocType(r_type, cpu_arch),
358 });
359364 atom_ptr.addRelocAssumeCapacity(.{
360365 .r_offset = r_offset,
361366 .r_addend = r_addend,
......@@ -384,12 +389,6 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi
384389 else
385390 0));
386391 const r_type = relocation.dwarf.crossSectionRelocType(dwarf.format, cpu_arch);
387 log.debug(" {s} <- r_off={x}, r_add={x}, r_type={}", .{
388 self.symbol(target_sym_index).name(elf_file),
389 r_offset,
390 r_addend,
391 relocation.fmtRelocType(r_type, cpu_arch),
392 });
393392 atom_ptr.addRelocAssumeCapacity(.{
394393 .r_offset = r_offset,
395394 .r_addend = r_addend,
......@@ -410,12 +409,6 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi
410409 else
411410 0));
412411 const r_type = relocation.dwarf.crossSectionRelocType(dwarf.format, cpu_arch);
413 log.debug(" {s} <- r_off={x}, r_add={x}, r_type={}", .{
414 self.symbol(sym_index).name(elf_file),
415 r_offset,
416 r_addend,
417 relocation.fmtRelocType(r_type, cpu_arch),
418 });
419412 atom_ptr.addRelocAssumeCapacity(.{
420413 .r_offset = r_offset,
421414 .r_addend = r_addend,
......@@ -430,12 +423,6 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi
430423 else
431424 0));
432425 const r_type = relocation.dwarf.crossSectionRelocType(dwarf.format, cpu_arch);
433 log.debug(" {s} <- r_off={x}, r_add={x}, r_type={}", .{
434 self.symbol(sym_index).name(elf_file),
435 r_offset,
436 r_addend,
437 relocation.fmtRelocType(r_type, cpu_arch),
438 });
439426 atom_ptr.addRelocAssumeCapacity(.{
440427 .r_offset = r_offset,
441428 .r_addend = r_addend,
......@@ -464,12 +451,6 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi
464451 else
465452 0));
466453 const r_type = relocation.dwarf.crossSectionRelocType(dwarf.format, cpu_arch);
467 log.debug(" {s} <- r_off={x}, r_add={x}, r_type={}", .{
468 self.symbol(target_sym_index).name(elf_file),
469 r_offset,
470 r_addend,
471 relocation.fmtRelocType(r_type, cpu_arch),
472 });
473454 atom_ptr.addRelocAssumeCapacity(.{
474455 .r_offset = r_offset,
475456 .r_addend = r_addend,
......@@ -481,12 +462,6 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi
481462 const r_offset = entry_off + reloc.source_off;
482463 const r_addend: i64 = @intCast(reloc.target_off);
483464 const r_type = relocation.dwarf.externalRelocType(target_sym.*, sect_index, dwarf.address_size, cpu_arch);
484 log.debug(" {s} <- r_off={x}, r_add={x}, r_type={}", .{
485 target_sym.name(elf_file),
486 r_offset,
487 r_addend,
488 relocation.fmtRelocType(r_type, cpu_arch),
489 });
490465 atom_ptr.addRelocAssumeCapacity(.{
491466 .r_offset = r_offset,
492467 .r_addend = r_addend,
......@@ -1035,16 +1010,15 @@ pub fn lowerUav(
10351010 }
10361011
10371012 const osec = if (self.data_relro_index) |sym_index|
1038 self.symbol(sym_index).atom(elf_file).?.output_section_index
1013 self.symbol(sym_index).outputShndx(elf_file).?
10391014 else osec: {
10401015 const osec = try elf_file.addSection(.{
10411016 .name = try elf_file.insertShString(".data.rel.ro"),
10421017 .type = elf.SHT_PROGBITS,
10431018 .addralign = 1,
10441019 .flags = elf.SHF_ALLOC | elf.SHF_WRITE,
1045 .offset = std.math.maxInt(u64),
10461020 });
1047 self.data_relro_index = try self.addSectionSymbol(gpa, ".data.rel.ro", .@"1", osec);
1021 self.data_relro_index = try self.addSectionSymbol(gpa, try self.addString(gpa, ".data.rel.ro"), osec);
10481022 break :osec osec;
10491023 };
10501024
......@@ -1150,24 +1124,14 @@ pub fn getOrCreateMetadataForNav(
11501124 return gop.value_ptr.symbol_index;
11511125}
11521126
1153// FIXME: we always create an atom to basically store size and alignment, however, this is only true for
1154// sections that have a single atom like the debug sections. It would be a better solution to decouple this
1155// concept from the atom, maybe.
1156fn addSectionSymbol(
1157 self: *ZigObject,
1158 allocator: Allocator,
1159 name: [:0]const u8,
1160 alignment: Atom.Alignment,
1161 shndx: u32,
1162) !Symbol.Index {
1163 const name_off = try self.addString(allocator, name);
1164 const index = try self.newSymbolWithAtom(allocator, name_off);
1127fn addSectionSymbol(self: *ZigObject, allocator: Allocator, name_off: u32, shndx: u32) !Symbol.Index {
1128 const index = try self.newLocalSymbol(allocator, name_off);
11651129 const sym = self.symbol(index);
11661130 const esym = &self.symtab.items(.elf_sym)[sym.esym_index];
11671131 esym.st_info |= elf.STT_SECTION;
1168 const atom_ptr = self.atom(sym.ref.index).?;
1169 atom_ptr.alignment = alignment;
1170 atom_ptr.output_section_index = shndx;
1132 // TODO create fake shdrs?
1133 // esym.st_shndx = shndx;
1134 sym.output_section_index = shndx;
11711135 return index;
11721136}
11731137
......@@ -1186,15 +1150,14 @@ fn getNavShdrIndex(
11861150 const nav_val = zcu.navValue(nav_index);
11871151 if (ip.isFunctionType(nav_val.typeOf(zcu).toIntern())) {
11881152 if (self.text_index) |symbol_index|
1189 return self.symbol(symbol_index).atom(elf_file).?.output_section_index;
1153 return self.symbol(symbol_index).outputShndx(elf_file).?;
11901154 const osec = try elf_file.addSection(.{
11911155 .type = elf.SHT_PROGBITS,
11921156 .flags = elf.SHF_ALLOC | elf.SHF_EXECINSTR,
11931157 .name = try elf_file.insertShString(".text"),
11941158 .addralign = 1,
1195 .offset = std.math.maxInt(u64),
11961159 });
1197 self.text_index = try self.addSectionSymbol(gpa, ".text", .@"1", osec);
1160 self.text_index = try self.addSectionSymbol(gpa, try self.addString(gpa, ".text"), osec);
11981161 return osec;
11991162 }
12001163 const is_const, const is_threadlocal, const nav_init = switch (ip.indexToKey(nav_val.toIntern())) {
......@@ -1209,71 +1172,63 @@ fn getNavShdrIndex(
12091172 } else true;
12101173 if (is_bss) {
12111174 if (self.tbss_index) |symbol_index|
1212 return self.symbol(symbol_index).atom(elf_file).?.output_section_index;
1175 return self.symbol(symbol_index).outputShndx(elf_file).?;
12131176 const osec = try elf_file.addSection(.{
12141177 .name = try elf_file.insertShString(".tbss"),
12151178 .flags = elf.SHF_ALLOC | elf.SHF_WRITE | elf.SHF_TLS,
12161179 .type = elf.SHT_NOBITS,
12171180 .addralign = 1,
12181181 });
1219 self.tbss_index = try self.addSectionSymbol(gpa, ".tbss", .@"1", osec);
1182 self.tbss_index = try self.addSectionSymbol(gpa, try self.addString(gpa, ".tbss"), osec);
12201183 return osec;
12211184 }
12221185 if (self.tdata_index) |symbol_index|
1223 return self.symbol(symbol_index).atom(elf_file).?.output_section_index;
1186 return self.symbol(symbol_index).outputShndx(elf_file).?;
12241187 const osec = try elf_file.addSection(.{
12251188 .type = elf.SHT_PROGBITS,
12261189 .flags = elf.SHF_ALLOC | elf.SHF_WRITE | elf.SHF_TLS,
12271190 .name = try elf_file.insertShString(".tdata"),
12281191 .addralign = 1,
1229 .offset = std.math.maxInt(u64),
12301192 });
1231 self.tdata_index = try self.addSectionSymbol(gpa, ".tdata", .@"1", osec);
1193 self.tdata_index = try self.addSectionSymbol(gpa, try self.addString(gpa, ".tdata"), osec);
12321194 return osec;
12331195 }
12341196 if (is_const) {
12351197 if (self.data_relro_index) |symbol_index|
1236 return self.symbol(symbol_index).atom(elf_file).?.output_section_index;
1198 return self.symbol(symbol_index).outputShndx(elf_file).?;
12371199 const osec = try elf_file.addSection(.{
12381200 .name = try elf_file.insertShString(".data.rel.ro"),
12391201 .type = elf.SHT_PROGBITS,
12401202 .addralign = 1,
12411203 .flags = elf.SHF_ALLOC | elf.SHF_WRITE,
1242 .offset = std.math.maxInt(u64),
12431204 });
1244 self.data_relro_index = try self.addSectionSymbol(gpa, ".data.rel.ro", .@"1", osec);
1205 self.data_relro_index = try self.addSectionSymbol(gpa, try self.addString(gpa, ".data.rel.ro"), osec);
12451206 return osec;
12461207 }
12471208 if (nav_init != .none and Value.fromInterned(nav_init).isUndefDeep(zcu))
12481209 return switch (zcu.navFileScope(nav_index).mod.optimize_mode) {
12491210 .Debug, .ReleaseSafe => {
12501211 if (self.data_index) |symbol_index|
1251 return self.symbol(symbol_index).atom(elf_file).?.output_section_index;
1212 return self.symbol(symbol_index).outputShndx(elf_file).?;
12521213 const osec = try elf_file.addSection(.{
12531214 .name = try elf_file.insertShString(".data"),
12541215 .type = elf.SHT_PROGBITS,
12551216 .addralign = ptr_size,
12561217 .flags = elf.SHF_ALLOC | elf.SHF_WRITE,
1257 .offset = std.math.maxInt(u64),
12581218 });
1259 self.data_index = try self.addSectionSymbol(
1260 gpa,
1261 ".data",
1262 Atom.Alignment.fromNonzeroByteUnits(ptr_size),
1263 osec,
1264 );
1219 self.data_index = try self.addSectionSymbol(gpa, try self.addString(gpa, ".data"), osec);
12651220 return osec;
12661221 },
12671222 .ReleaseFast, .ReleaseSmall => {
12681223 if (self.bss_index) |symbol_index|
1269 return self.symbol(symbol_index).atom(elf_file).?.output_section_index;
1224 return self.symbol(symbol_index).outputShndx(elf_file).?;
12701225 const osec = try elf_file.addSection(.{
12711226 .type = elf.SHT_NOBITS,
12721227 .flags = elf.SHF_ALLOC | elf.SHF_WRITE,
12731228 .name = try elf_file.insertShString(".bss"),
12741229 .addralign = 1,
12751230 });
1276 self.bss_index = try self.addSectionSymbol(gpa, ".bss", .@"1", osec);
1231 self.bss_index = try self.addSectionSymbol(gpa, try self.addString(gpa, ".bss"), osec);
12771232 return osec;
12781233 },
12791234 };
......@@ -1282,31 +1237,25 @@ fn getNavShdrIndex(
12821237 } else true;
12831238 if (is_bss) {
12841239 if (self.bss_index) |symbol_index|
1285 return self.symbol(symbol_index).atom(elf_file).?.output_section_index;
1240 return self.symbol(symbol_index).outputShndx(elf_file).?;
12861241 const osec = try elf_file.addSection(.{
12871242 .type = elf.SHT_NOBITS,
12881243 .flags = elf.SHF_ALLOC | elf.SHF_WRITE,
12891244 .name = try elf_file.insertShString(".bss"),
12901245 .addralign = 1,
12911246 });
1292 self.bss_index = try self.addSectionSymbol(gpa, ".bss", .@"1", osec);
1247 self.bss_index = try self.addSectionSymbol(gpa, try self.addString(gpa, ".bss"), osec);
12931248 return osec;
12941249 }
12951250 if (self.data_index) |symbol_index|
1296 return self.symbol(symbol_index).atom(elf_file).?.output_section_index;
1251 return self.symbol(symbol_index).outputShndx(elf_file).?;
12971252 const osec = try elf_file.addSection(.{
12981253 .name = try elf_file.insertShString(".data"),
12991254 .type = elf.SHT_PROGBITS,
13001255 .addralign = ptr_size,
13011256 .flags = elf.SHF_ALLOC | elf.SHF_WRITE,
1302 .offset = std.math.maxInt(u64),
13031257 });
1304 self.data_index = try self.addSectionSymbol(
1305 gpa,
1306 ".data",
1307 Atom.Alignment.fromNonzeroByteUnits(ptr_size),
1308 osec,
1309 );
1258 self.data_index = try self.addSectionSymbol(gpa, try self.addString(gpa, ".data"), osec);
13101259 return osec;
13111260}
13121261
......@@ -1354,7 +1303,7 @@ fn updateNavCode(
13541303 const capacity = atom_ptr.capacity(elf_file);
13551304 const need_realloc = code.len > capacity or !required_alignment.check(@intCast(atom_ptr.value));
13561305 if (need_realloc) {
1357 try self.growAtom(atom_ptr, elf_file);
1306 try self.allocateAtom(atom_ptr, true, elf_file);
13581307 log.debug("growing {} from 0x{x} to 0x{x}", .{ nav.fqn.fmt(ip), old_vaddr, atom_ptr.value });
13591308 if (old_vaddr != atom_ptr.value) {
13601309 sym.value = 0;
......@@ -1364,7 +1313,7 @@ fn updateNavCode(
13641313 // TODO shrink section size
13651314 }
13661315 } else {
1367 try self.allocateAtom(atom_ptr, elf_file);
1316 try self.allocateAtom(atom_ptr, true, elf_file);
13681317 errdefer self.freeNavMetadata(elf_file, sym_index);
13691318 sym.value = 0;
13701319 esym.st_value = 0;
......@@ -1439,7 +1388,7 @@ fn updateTlv(
14391388 const gop = try self.tls_variables.getOrPut(gpa, atom_ptr.atom_index);
14401389 assert(!gop.found_existing); // TODO incremental updates
14411390
1442 try self.allocateAtom(atom_ptr, elf_file);
1391 try self.allocateAtom(atom_ptr, true, elf_file);
14431392 sym.value = 0;
14441393 esym.st_value = 0;
14451394
......@@ -1557,9 +1506,8 @@ pub fn updateFunc(
15571506 .flags = elf.SHF_ALLOC | elf.SHF_EXECINSTR,
15581507 .type = elf.SHT_PROGBITS,
15591508 .addralign = 1,
1560 .offset = std.math.maxInt(u64),
15611509 });
1562 self.text_index = try self.addSectionSymbol(gpa, ".text", .@"1", osec);
1510 self.text_index = try self.addSectionSymbol(gpa, try self.addString(gpa, ".text"), osec);
15631511 break :osec osec;
15641512 };
15651513 const name_off = try self.addString(gpa, name);
......@@ -1726,29 +1674,27 @@ fn updateLazySymbol(
17261674
17271675 const output_section_index = switch (sym.kind) {
17281676 .code => if (self.text_index) |sym_index|
1729 self.symbol(sym_index).atom(elf_file).?.output_section_index
1677 self.symbol(sym_index).outputShndx(elf_file).?
17301678 else osec: {
17311679 const osec = try elf_file.addSection(.{
17321680 .name = try elf_file.insertShString(".text"),
17331681 .type = elf.SHT_PROGBITS,
17341682 .addralign = 1,
17351683 .flags = elf.SHF_ALLOC | elf.SHF_EXECINSTR,
1736 .offset = std.math.maxInt(u64),
17371684 });
1738 self.text_index = try self.addSectionSymbol(gpa, ".text", .@"1", osec);
1685 self.text_index = try self.addSectionSymbol(gpa, try self.addString(gpa, ".text"), osec);
17391686 break :osec osec;
17401687 },
17411688 .const_data => if (self.rodata_index) |sym_index|
1742 self.symbol(sym_index).atom(elf_file).?.output_section_index
1689 self.symbol(sym_index).outputShndx(elf_file).?
17431690 else osec: {
17441691 const osec = try elf_file.addSection(.{
17451692 .name = try elf_file.insertShString(".rodata"),
17461693 .type = elf.SHT_PROGBITS,
17471694 .addralign = 1,
17481695 .flags = elf.SHF_ALLOC,
1749 .offset = std.math.maxInt(u64),
17501696 });
1751 self.rodata_index = try self.addSectionSymbol(gpa, ".rodata", .@"1", osec);
1697 self.rodata_index = try self.addSectionSymbol(gpa, try self.addString(gpa, ".rodata"), osec);
17521698 break :osec osec;
17531699 },
17541700 };
......@@ -1765,7 +1711,7 @@ fn updateLazySymbol(
17651711 atom_ptr.size = code.len;
17661712 atom_ptr.output_section_index = output_section_index;
17671713
1768 try self.allocateAtom(atom_ptr, elf_file);
1714 try self.allocateAtom(atom_ptr, true, elf_file);
17691715 errdefer self.freeNavMetadata(elf_file, symbol_index);
17701716
17711717 local_sym.value = 0;
......@@ -1820,7 +1766,7 @@ fn lowerConst(
18201766 atom_ptr.size = code.len;
18211767 atom_ptr.output_section_index = output_section_index;
18221768
1823 try self.allocateAtom(atom_ptr, elf_file);
1769 try self.allocateAtom(atom_ptr, true, elf_file);
18241770 errdefer self.freeNavMetadata(elf_file, sym_index);
18251771
18261772 try elf_file.base.file.?.pwriteAll(code, atom_ptr.offset(elf_file));
......@@ -2017,17 +1963,27 @@ fn writeTrampoline(tr_sym: Symbol, target: Symbol, elf_file: *Elf) !void {
20171963 }
20181964}
20191965
2020fn allocateAtom(self: *ZigObject, atom_ptr: *Atom, elf_file: *Elf) !void {
1966pub fn allocateAtom(self: *ZigObject, atom_ptr: *Atom, requires_padding: bool, elf_file: *Elf) !void {
1967 const slice = elf_file.sections.slice();
1968 const shdr = &slice.items(.shdr)[atom_ptr.output_section_index];
1969 const last_atom_ref = &slice.items(.last_atom)[atom_ptr.output_section_index];
1970
1971 // FIXME:JK this only works if this atom is the only atom in the output section
1972 // In every other case, we need to redo the prev/next links
1973 if (last_atom_ref.eql(atom_ptr.ref())) last_atom_ref.* = .{};
1974
20211975 const alloc_res = try elf_file.allocateChunk(.{
20221976 .shndx = atom_ptr.output_section_index,
20231977 .size = atom_ptr.size,
20241978 .alignment = atom_ptr.alignment,
1979 .requires_padding = requires_padding,
20251980 });
20261981 atom_ptr.value = @intCast(alloc_res.value);
2027
2028 const slice = elf_file.sections.slice();
2029 const shdr = &slice.items(.shdr)[atom_ptr.output_section_index];
2030 const last_atom_ref = &slice.items(.last_atom)[atom_ptr.output_section_index];
1982 log.debug("allocated {s} at {x}\n placement {?}", .{
1983 atom_ptr.name(elf_file),
1984 atom_ptr.offset(elf_file),
1985 alloc_res.placement,
1986 });
20311987
20321988 const expand_section = if (elf_file.atom(alloc_res.placement)) |placement_atom|
20331989 placement_atom.nextAtom(elf_file) == null
......@@ -2049,22 +2005,6 @@ fn allocateAtom(self: *ZigObject, atom_ptr: *Atom, elf_file: *Elf) !void {
20492005 }
20502006 shdr.sh_addralign = @max(shdr.sh_addralign, atom_ptr.alignment.toByteUnits().?);
20512007
2052 const sect_atom_ptr = for ([_]?Symbol.Index{
2053 self.text_index,
2054 self.rodata_index,
2055 self.data_relro_index,
2056 self.data_index,
2057 self.tdata_index,
2058 }) |maybe_sym_index| {
2059 const sect_sym_index = maybe_sym_index orelse continue;
2060 const sect_atom_ptr = self.symbol(sect_sym_index).atom(elf_file).?;
2061 if (sect_atom_ptr.output_section_index == atom_ptr.output_section_index) break sect_atom_ptr;
2062 } else null;
2063 if (sect_atom_ptr) |sap| {
2064 sap.size = shdr.sh_size;
2065 sap.alignment = Atom.Alignment.fromNonzeroByteUnits(shdr.sh_addralign);
2066 }
2067
20682008 // This function can also reallocate an atom.
20692009 // In this case we need to "unplug" it from its previous location before
20702010 // plugging it in to its new location.
......@@ -2083,11 +2023,37 @@ fn allocateAtom(self: *ZigObject, atom_ptr: *Atom, elf_file: *Elf) !void {
20832023 atom_ptr.prev_atom_ref = .{ .index = 0, .file = 0 };
20842024 atom_ptr.next_atom_ref = .{ .index = 0, .file = 0 };
20852025 }
2026
2027 log.debug(" prev {?}, next {?}", .{ atom_ptr.prev_atom_ref, atom_ptr.next_atom_ref });
20862028}
20872029
2088fn growAtom(self: *ZigObject, atom_ptr: *Atom, elf_file: *Elf) !void {
2089 if (!atom_ptr.alignment.check(@intCast(atom_ptr.value)) or atom_ptr.size > atom_ptr.capacity(elf_file)) {
2090 try self.allocateAtom(atom_ptr, elf_file);
2030pub fn resetShdrIndexes(self: *ZigObject, backlinks: anytype) void {
2031 for (self.atoms_indexes.items) |atom_index| {
2032 const atom_ptr = self.atom(atom_index) orelse continue;
2033 atom_ptr.output_section_index = backlinks[atom_ptr.output_section_index];
2034 }
2035 inline for ([_]?Symbol.Index{
2036 self.text_index,
2037 self.rodata_index,
2038 self.data_relro_index,
2039 self.data_index,
2040 self.bss_index,
2041 self.tdata_index,
2042 self.tbss_index,
2043 self.eh_frame_index,
2044 self.debug_info_index,
2045 self.debug_abbrev_index,
2046 self.debug_aranges_index,
2047 self.debug_str_index,
2048 self.debug_line_index,
2049 self.debug_line_str_index,
2050 self.debug_loclists_index,
2051 self.debug_rnglists_index,
2052 }) |maybe_sym_index| {
2053 if (maybe_sym_index) |sym_index| {
2054 const sym = self.symbol(sym_index);
2055 sym.output_section_index = backlinks[sym.output_section_index];
2056 }
20912057 }
20922058}
20932059
......@@ -2095,6 +2061,33 @@ pub fn asFile(self: *ZigObject) File {
20952061 return .{ .zig_object = self };
20962062}
20972063
2064pub fn sectionSymbol(self: *ZigObject, shndx: u32, elf_file: *Elf) ?*Symbol {
2065 inline for ([_]?Symbol.Index{
2066 self.text_index,
2067 self.rodata_index,
2068 self.data_relro_index,
2069 self.data_index,
2070 self.bss_index,
2071 self.tdata_index,
2072 self.tbss_index,
2073 self.eh_frame_index,
2074 self.debug_info_index,
2075 self.debug_abbrev_index,
2076 self.debug_aranges_index,
2077 self.debug_str_index,
2078 self.debug_line_index,
2079 self.debug_line_str_index,
2080 self.debug_loclists_index,
2081 self.debug_rnglists_index,
2082 }) |maybe_sym_index| {
2083 if (maybe_sym_index) |sym_index| {
2084 const sym = self.symbol(sym_index);
2085 if (sym.outputShndx(elf_file) == shndx) return sym;
2086 }
2087 }
2088 return null;
2089}
2090
20982091pub fn addString(self: *ZigObject, allocator: Allocator, string: []const u8) !u32 {
20992092 return self.strtab.insert(allocator, string);
21002093}
src/link/Elf/file.zig+7-7
......@@ -95,19 +95,19 @@ pub const File = union(enum) {
9595 log.debug("'{s}' is non-local", .{sym.name(ef)});
9696 try ef.dynsym.addSymbol(ref, ef);
9797 }
98 if (sym.flags.needs_got) {
98 if (sym.flags.needs_got and !sym.flags.has_got) {
9999 log.debug("'{s}' needs GOT", .{sym.name(ef)});
100100 _ = try ef.got.addGotSymbol(ref, ef);
101101 }
102102 if (sym.flags.needs_plt) {
103 if (sym.flags.is_canonical) {
103 if (sym.flags.is_canonical and !sym.flags.has_plt) {
104104 log.debug("'{s}' needs CPLT", .{sym.name(ef)});
105105 sym.flags.@"export" = true;
106106 try ef.plt.addSymbol(ref, ef);
107 } else if (sym.flags.needs_got) {
107 } else if (sym.flags.needs_got and !sym.flags.has_pltgot) {
108108 log.debug("'{s}' needs PLTGOT", .{sym.name(ef)});
109109 try ef.plt_got.addSymbol(ref, ef);
110 } else {
110 } else if (!sym.flags.has_plt) {
111111 log.debug("'{s}' needs PLT", .{sym.name(ef)});
112112 try ef.plt.addSymbol(ref, ef);
113113 }
......@@ -116,15 +116,15 @@ pub const File = union(enum) {
116116 log.debug("'{s}' needs COPYREL", .{sym.name(ef)});
117117 try ef.copy_rel.addSymbol(ref, ef);
118118 }
119 if (sym.flags.needs_tlsgd) {
119 if (sym.flags.needs_tlsgd and !sym.flags.has_tlsgd) {
120120 log.debug("'{s}' needs TLSGD", .{sym.name(ef)});
121121 try ef.got.addTlsGdSymbol(ref, ef);
122122 }
123 if (sym.flags.needs_gottp) {
123 if (sym.flags.needs_gottp and !sym.flags.has_gottp) {
124124 log.debug("'{s}' needs GOTTP", .{sym.name(ef)});
125125 try ef.got.addGotTpSymbol(ref, ef);
126126 }
127 if (sym.flags.needs_tlsdesc) {
127 if (sym.flags.needs_tlsdesc and !sym.flags.has_tlsdesc) {
128128 log.debug("'{s}' needs TLSDESC", .{sym.name(ef)});
129129 try ef.got.addTlsDescSymbol(ref, ef);
130130 }
src/link/Elf/relocatable.zig+12-22
......@@ -295,7 +295,6 @@ fn initSections(elf_file: *Elf) !void {
295295 elf.SHT_PROGBITS,
296296 .flags = elf.SHF_ALLOC,
297297 .addralign = elf_file.ptrWidthBytes(),
298 .offset = std.math.maxInt(u64),
299298 });
300299 }
301300 elf_file.eh_frame_rela_section_index = elf_file.sectionByName(".rela.eh_frame") orelse
......@@ -324,7 +323,6 @@ fn initComdatGroups(elf_file: *Elf) !void {
324323 .type = elf.SHT_GROUP,
325324 .entsize = @sizeOf(u32),
326325 .addralign = @alignOf(u32),
327 .offset = std.math.maxInt(u64),
328326 }),
329327 .cg_ref = .{ .index = @intCast(cg_index), .file = index },
330328 };
......@@ -335,9 +333,11 @@ fn initComdatGroups(elf_file: *Elf) !void {
335333fn updateSectionSizes(elf_file: *Elf) !void {
336334 const slice = elf_file.sections.slice();
337335 for (slice.items(.atom_list_2)) |*atom_list| {
338 if (atom_list.atoms.items.len == 0) continue;
336 if (atom_list.atoms.keys().len == 0) continue;
337 if (!atom_list.dirty) continue;
339338 atom_list.updateSize(elf_file);
340339 try atom_list.allocate(elf_file);
340 atom_list.dirty = false;
341341 }
342342
343343 for (slice.items(.shdr), 0..) |*shdr, shndx| {
......@@ -392,24 +392,14 @@ fn allocateAllocSections(elf_file: *Elf) !void {
392392 shdr.sh_size = 0;
393393 const new_offset = try elf_file.findFreeSpace(needed_size, shdr.sh_addralign);
394394
395 if (elf_file.zigObjectPtr()) |zo| blk: {
396 const existing_size = for ([_]?Symbol.Index{
397 zo.text_index,
398 zo.rodata_index,
399 zo.data_relro_index,
400 zo.data_index,
401 zo.tdata_index,
402 zo.eh_frame_index,
403 }) |maybe_sym_index| {
404 const sect_sym_index = maybe_sym_index orelse continue;
405 const sect_atom_ptr = zo.symbol(sect_sym_index).atom(elf_file).?;
406 if (sect_atom_ptr.output_section_index == shndx) break sect_atom_ptr.size;
407 } else break :blk;
408 log.debug("moving {s} from 0x{x} to 0x{x}", .{
409 elf_file.getShString(shdr.sh_name),
410 shdr.sh_offset,
411 new_offset,
412 });
395 log.debug("moving {s} from 0x{x} to 0x{x}", .{
396 elf_file.getShString(shdr.sh_name),
397 shdr.sh_offset,
398 new_offset,
399 });
400
401 if (shdr.sh_offset > 0) {
402 const existing_size = elf_file.sectionSize(@intCast(shndx));
413403 const amt = try elf_file.base.file.?.copyRangeAll(
414404 shdr.sh_offset,
415405 elf_file.base.file.?,
......@@ -434,7 +424,7 @@ fn writeAtoms(elf_file: *Elf) !void {
434424 const slice = elf_file.sections.slice();
435425 for (slice.items(.shdr), slice.items(.atom_list_2)) |shdr, atom_list| {
436426 if (shdr.sh_type == elf.SHT_NOBITS) continue;
437 if (atom_list.atoms.items.len == 0) continue;
427 if (atom_list.atoms.keys().len == 0) continue;
438428 try atom_list.writeRelocatable(&buffer, elf_file);
439429 }
440430}
src/link/Elf/synthetic_sections.zig+27-2
......@@ -435,6 +435,8 @@ pub const GotSection = struct {
435435 const cpu_arch = elf_file.getTarget().cpu.arch;
436436 try elf_file.rela_dyn.ensureUnusedCapacity(gpa, got.numRela(elf_file));
437437
438 relocs_log.debug(".got", .{});
439
438440 for (got.entries.items) |entry| {
439441 const symbol = elf_file.symbol(entry.ref);
440442 const extra = if (symbol) |s| s.extra(elf_file) else null;
......@@ -447,6 +449,7 @@ pub const GotSection = struct {
447449 .offset = offset,
448450 .sym = extra.?.dynamic,
449451 .type = relocation.encode(.glob_dat, cpu_arch),
452 .target = symbol,
450453 });
451454 continue;
452455 }
......@@ -455,6 +458,7 @@ pub const GotSection = struct {
455458 .offset = offset,
456459 .type = relocation.encode(.irel, cpu_arch),
457460 .addend = symbol.?.address(.{ .plt = false }, elf_file),
461 .target = symbol,
458462 });
459463 continue;
460464 }
......@@ -465,6 +469,7 @@ pub const GotSection = struct {
465469 .offset = offset,
466470 .type = relocation.encode(.rel, cpu_arch),
467471 .addend = symbol.?.address(.{ .plt = false }, elf_file),
472 .target = symbol,
468473 });
469474 }
470475 },
......@@ -486,17 +491,20 @@ pub const GotSection = struct {
486491 .offset = offset,
487492 .sym = extra.?.dynamic,
488493 .type = relocation.encode(.dtpmod, cpu_arch),
494 .target = symbol,
489495 });
490496 elf_file.addRelaDynAssumeCapacity(.{
491497 .offset = offset + 8,
492498 .sym = extra.?.dynamic,
493499 .type = relocation.encode(.dtpoff, cpu_arch),
500 .target = symbol,
494501 });
495502 } else if (is_dyn_lib) {
496503 elf_file.addRelaDynAssumeCapacity(.{
497504 .offset = offset,
498505 .sym = extra.?.dynamic,
499506 .type = relocation.encode(.dtpmod, cpu_arch),
507 .target = symbol,
500508 });
501509 }
502510 },
......@@ -508,12 +516,14 @@ pub const GotSection = struct {
508516 .offset = offset,
509517 .sym = extra.?.dynamic,
510518 .type = relocation.encode(.tpoff, cpu_arch),
519 .target = symbol,
511520 });
512521 } else if (is_dyn_lib) {
513522 elf_file.addRelaDynAssumeCapacity(.{
514523 .offset = offset,
515524 .type = relocation.encode(.tpoff, cpu_arch),
516525 .addend = symbol.?.address(.{}, elf_file) - elf_file.tlsAddress(),
526 .target = symbol,
517527 });
518528 }
519529 },
......@@ -525,6 +535,7 @@ pub const GotSection = struct {
525535 .sym = if (symbol.?.flags.import) extra.?.dynamic else 0,
526536 .type = relocation.encode(.tlsdesc, cpu_arch),
527537 .addend = if (symbol.?.flags.import) 0 else symbol.?.address(.{}, elf_file) - elf_file.tlsAddress(),
538 .target = symbol,
528539 });
529540 },
530541 }
......@@ -681,6 +692,9 @@ pub const PltSection = struct {
681692 const gpa = comp.gpa;
682693 const cpu_arch = elf_file.getTarget().cpu.arch;
683694 try elf_file.rela_plt.ensureUnusedCapacity(gpa, plt.numRela());
695
696 relocs_log.debug(".plt", .{});
697
684698 for (plt.symbols.items) |ref| {
685699 const sym = elf_file.symbol(ref).?;
686700 assert(sym.flags.import);
......@@ -688,6 +702,14 @@ pub const PltSection = struct {
688702 const r_offset: u64 = @intCast(sym.gotPltAddress(elf_file));
689703 const r_sym: u64 = extra.dynamic;
690704 const r_type = relocation.encode(.jump_slot, cpu_arch);
705
706 relocs_log.debug(" {s}: [{x} => {d}({s})] + 0", .{
707 relocation.fmtRelocType(r_type, cpu_arch),
708 r_offset,
709 r_sym,
710 sym.name(elf_file),
711 });
712
691713 elf_file.rela_plt.appendAssumeCapacity(.{
692714 .r_offset = r_offset,
693715 .r_info = (r_sym << 32) | r_type,
......@@ -895,8 +917,7 @@ pub const PltGotSection = struct {
895917 const gpa = comp.gpa;
896918 const index = @as(u32, @intCast(plt_got.symbols.items.len));
897919 const symbol = elf_file.symbol(ref).?;
898 symbol.flags.has_plt = true;
899 symbol.flags.has_got = true;
920 symbol.flags.has_pltgot = true;
900921 symbol.addExtra(.{ .plt_got = index }, elf_file);
901922 try plt_got.symbols.append(gpa, ref);
902923 }
......@@ -1054,6 +1075,9 @@ pub const CopyRelSection = struct {
10541075 const gpa = comp.gpa;
10551076 const cpu_arch = elf_file.getTarget().cpu.arch;
10561077 try elf_file.rela_dyn.ensureUnusedCapacity(gpa, copy_rel.numRela());
1078
1079 relocs_log.debug(".copy.rel", .{});
1080
10571081 for (copy_rel.symbols.items) |ref| {
10581082 const sym = elf_file.symbol(ref).?;
10591083 assert(sym.flags.import and sym.flags.has_copy_rel);
......@@ -1526,6 +1550,7 @@ const elf = std.elf;
15261550const math = std.math;
15271551const mem = std.mem;
15281552const log = std.log.scoped(.link);
1553const relocs_log = std.log.scoped(.link_relocs);
15291554const relocation = @import("relocation.zig");
15301555const std = @import("std");
15311556