authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-09-04 11:40:56+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-09-04 13:34:26+02:00
logd302a1068effe4edcd36bd01f77ac2e1b1048e16
treebe0f2fc35bb60239b4fbb4e8ebdbe416ddca1f6e
parent64ad6eff16aac1f6154efa12406818efed57bf73

elf: rename SectionChunk into AtomList and store as part of Section


3 files changed, 103 insertions(+), 326 deletions(-)

src/link/Elf.zig+84-49
...@@ -393,7 +393,8 @@ pub fn deinit(self: *Elf) void {...@@ -393,7 +393,8 @@ pub fn deinit(self: *Elf) void {
393 self.objects.deinit(gpa);393 self.objects.deinit(gpa);
394 self.shared_objects.deinit(gpa);394 self.shared_objects.deinit(gpa);
395395
396 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);
397 atoms.deinit(gpa);398 atoms.deinit(gpa);
398 free_list.deinit(gpa);399 free_list.deinit(gpa);
399 }400 }
...@@ -3204,8 +3205,9 @@ fn sortInitFini(self: *Elf) !void {...@@ -3204,8 +3205,9 @@ fn sortInitFini(self: *Elf) !void {
3204 }3205 }
3205 };3206 };
32063207
3207 for (slice.items(.shdr), slice.items(.atom_list)) |shdr, *atom_list| {3208 for (slice.items(.shdr), slice.items(.atom_list_2)) |shdr, *atom_list| {
3208 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;
32093211
3210 var is_init_fini = false;3212 var is_init_fini = false;
3211 var is_ctor_dtor = false;3213 var is_ctor_dtor = false;
...@@ -3219,15 +3221,13 @@ fn sortInitFini(self: *Elf) !void {...@@ -3219,15 +3221,13 @@ fn sortInitFini(self: *Elf) !void {
3219 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;
3220 },3222 },
3221 }3223 }
3222
3223 if (!is_init_fini and !is_ctor_dtor) continue;3224 if (!is_init_fini and !is_ctor_dtor) continue;
3224 if (atom_list.items.len == 0) continue;
32253225
3226 var entries = std.ArrayList(Entry).init(gpa);3226 var entries = std.ArrayList(Entry).init(gpa);
3227 try entries.ensureTotalCapacityPrecise(atom_list.items.len);3227 try entries.ensureTotalCapacityPrecise(atom_list.atoms.items.len);
3228 defer entries.deinit();3228 defer entries.deinit();
32293229
3230 for (atom_list.items) |ref| {3230 for (atom_list.atoms.items) |ref| {
3231 const atom_ptr = self.atom(ref).?;3231 const atom_ptr = self.atom(ref).?;
3232 const object = atom_ptr.file(self).?.object;3232 const object = atom_ptr.file(self).?.object;
3233 const priority = blk: {3233 const priority = blk: {
...@@ -3246,9 +3246,9 @@ fn sortInitFini(self: *Elf) !void {...@@ -3246,9 +3246,9 @@ fn sortInitFini(self: *Elf) !void {
32463246
3247 mem.sort(Entry, entries.items, self, Entry.lessThan);3247 mem.sort(Entry, entries.items, self, Entry.lessThan);
32483248
3249 atom_list.clearRetainingCapacity();3249 atom_list.atoms.clearRetainingCapacity();
3250 for (entries.items) |entry| {3250 for (entries.items) |entry| {
3251 atom_list.appendAssumeCapacity(entry.atom_ref);3251 atom_list.atoms.appendAssumeCapacity(entry.atom_ref);
3252 }3252 }
3253 }3253 }
3254}3254}
...@@ -3491,13 +3491,19 @@ fn resetShdrIndexes(self: *Elf, backlinks: []const u32) void {...@@ -3491,13 +3491,19 @@ fn resetShdrIndexes(self: *Elf, backlinks: []const u32) void {
3491 msec.output_section_index = backlinks[msec.output_section_index];3491 msec.output_section_index = backlinks[msec.output_section_index];
3492 }3492 }
34933493
3494 for (self.sections.items(.shdr)) |*shdr| {3494 const slice = self.sections.slice();
3495 if (shdr.sh_type != elf.SHT_RELA) continue;3495 for (slice.items(.shdr), slice.items(.atom_list_2)) |*shdr, *atom_list| {
3496 // 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];
3497 // to point at symtab3497 for (atom_list.atoms.items) |ref| {
3498 // shdr.sh_link = backlinks[shdr.sh_link];3498 self.atom(ref).?.output_section_index = atom_list.output_section_index;
3499 shdr.sh_link = self.symtab_section_index.?;3499 }
3500 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 }
3501 }3507 }
35023508
3503 if (self.zigObjectPtr()) |zo| {3509 if (self.zigObjectPtr()) |zo| {
...@@ -3507,79 +3513,71 @@ fn resetShdrIndexes(self: *Elf, backlinks: []const u32) void {...@@ -3507,79 +3513,71 @@ fn resetShdrIndexes(self: *Elf, backlinks: []const u32) void {
3507 }3513 }
3508 }3514 }
35093515
3510 for (self.objects.items) |index| {
3511 const object = self.file(index).?.object;
3512 for (object.section_chunks.items) |*chunk| {
3513 chunk.output_section_index = backlinks[chunk.output_section_index];
3514 for (chunk.atoms.items) |atom_index| {
3515 object.atom(atom_index).?.output_section_index = chunk.output_section_index;
3516 }
3517 }
3518 }
3519
3520 for (self.comdat_group_sections.items) |*cg| {3516 for (self.comdat_group_sections.items) |*cg| {
3521 cg.shndx = backlinks[cg.shndx];3517 cg.shndx = backlinks[cg.shndx];
3522 }3518 }
35233519
3524 if (self.symtab_section_index) |index| {3520 if (self.symtab_section_index) |index| {
3525 const shdr = &self.sections.items(.shdr)[index];3521 const shdr = &slice.items(.shdr)[index];
3526 shdr.sh_link = self.strtab_section_index.?;3522 shdr.sh_link = self.strtab_section_index.?;
3527 }3523 }
35283524
3529 if (self.dynamic_section_index) |index| {3525 if (self.dynamic_section_index) |index| {
3530 const shdr = &self.sections.items(.shdr)[index];3526 const shdr = &slice.items(.shdr)[index];
3531 shdr.sh_link = self.dynstrtab_section_index.?;3527 shdr.sh_link = self.dynstrtab_section_index.?;
3532 }3528 }
35333529
3534 if (self.dynsymtab_section_index) |index| {3530 if (self.dynsymtab_section_index) |index| {
3535 const shdr = &self.sections.items(.shdr)[index];3531 const shdr = &slice.items(.shdr)[index];
3536 shdr.sh_link = self.dynstrtab_section_index.?;3532 shdr.sh_link = self.dynstrtab_section_index.?;
3537 }3533 }
35383534
3539 if (self.hash_section_index) |index| {3535 if (self.hash_section_index) |index| {
3540 const shdr = &self.sections.items(.shdr)[index];3536 const shdr = &slice.items(.shdr)[index];
3541 shdr.sh_link = self.dynsymtab_section_index.?;3537 shdr.sh_link = self.dynsymtab_section_index.?;
3542 }3538 }
35433539
3544 if (self.gnu_hash_section_index) |index| {3540 if (self.gnu_hash_section_index) |index| {
3545 const shdr = &self.sections.items(.shdr)[index];3541 const shdr = &slice.items(.shdr)[index];
3546 shdr.sh_link = self.dynsymtab_section_index.?;3542 shdr.sh_link = self.dynsymtab_section_index.?;
3547 }3543 }
35483544
3549 if (self.versym_section_index) |index| {3545 if (self.versym_section_index) |index| {
3550 const shdr = &self.sections.items(.shdr)[index];3546 const shdr = &slice.items(.shdr)[index];
3551 shdr.sh_link = self.dynsymtab_section_index.?;3547 shdr.sh_link = self.dynsymtab_section_index.?;
3552 }3548 }
35533549
3554 if (self.verneed_section_index) |index| {3550 if (self.verneed_section_index) |index| {
3555 const shdr = &self.sections.items(.shdr)[index];3551 const shdr = &slice.items(.shdr)[index];
3556 shdr.sh_link = self.dynstrtab_section_index.?;3552 shdr.sh_link = self.dynstrtab_section_index.?;
3557 }3553 }
35583554
3559 if (self.rela_dyn_section_index) |index| {3555 if (self.rela_dyn_section_index) |index| {
3560 const shdr = &self.sections.items(.shdr)[index];3556 const shdr = &slice.items(.shdr)[index];
3561 shdr.sh_link = self.dynsymtab_section_index orelse 0;3557 shdr.sh_link = self.dynsymtab_section_index orelse 0;
3562 }3558 }
35633559
3564 if (self.rela_plt_section_index) |index| {3560 if (self.rela_plt_section_index) |index| {
3565 const shdr = &self.sections.items(.shdr)[index];3561 const shdr = &slice.items(.shdr)[index];
3566 shdr.sh_link = self.dynsymtab_section_index.?;3562 shdr.sh_link = self.dynsymtab_section_index.?;
3567 shdr.sh_info = self.plt_section_index.?;3563 shdr.sh_info = self.plt_section_index.?;
3568 }3564 }
35693565
3570 if (self.eh_frame_rela_section_index) |index| {3566 if (self.eh_frame_rela_section_index) |index| {
3571 const shdr = &self.sections.items(.shdr)[index];3567 const shdr = &slice.items(.shdr)[index];
3572 shdr.sh_link = self.symtab_section_index.?;3568 shdr.sh_link = self.symtab_section_index.?;
3573 shdr.sh_info = self.eh_frame_section_index.?;3569 shdr.sh_info = self.eh_frame_section_index.?;
3574 }3570 }
3575}3571}
35763572
3577fn updateSectionSizes(self: *Elf) !void {3573fn updateSectionSizes(self: *Elf) !void {
3578 for (self.objects.items) |index| {3574 const slice = self.sections.slice();
3579 try self.file(index).?.object.allocateAtoms(self);3575 for (slice.items(.atom_list_2)) |*atom_list| {
3576 if (atom_list.atoms.items.len == 0) continue;
3577 atom_list.updateSize(self);
3578 try atom_list.allocate(self);
3580 }3579 }
35813580
3582 const slice = self.sections.slice();
3583 if (self.requiresThunks()) {3581 if (self.requiresThunks()) {
3584 for (slice.items(.shdr), slice.items(.atom_list), 0..) |*shdr, atom_list, shndx| {3582 for (slice.items(.shdr), slice.items(.atom_list), 0..) |*shdr, atom_list, shndx| {
3585 if (shdr.sh_flags & elf.SHF_EXECINSTR == 0) continue;3583 if (shdr.sh_flags & elf.SHF_EXECINSTR == 0) continue;
...@@ -4033,15 +4031,38 @@ fn allocateSpecialPhdrs(self: *Elf) void {...@@ -4033,15 +4031,38 @@ fn allocateSpecialPhdrs(self: *Elf) void {
4033}4031}
40344032
4035fn writeAtoms(self: *Elf) !void {4033fn writeAtoms(self: *Elf) !void {
4036 for (self.objects.items) |index| {4034 const gpa = self.base.comp.gpa;
4037 try self.file(index).?.object.writeAtoms(self);4035
4036 var undefs = std.AutoArrayHashMap(SymbolResolver.Index, std.ArrayList(Ref)).init(gpa);
4037 defer {
4038 for (undefs.values()) |*refs| {
4039 refs.deinit();
4040 }
4041 undefs.deinit();
4038 }4042 }
40394043
4040 if (self.requiresThunks()) {4044 var buffer = std.ArrayList(u8).init(gpa);
4041 const gpa = self.base.comp.gpa;4045 defer buffer.deinit();
4042 var buffer = std.ArrayList(u8).init(gpa);4046
4043 defer buffer.deinit();4047 const slice = self.sections.slice();
4048 var has_reloc_errors = false;
4049 for (slice.items(.shdr), slice.items(.atom_list_2)) |shdr, atom_list| {
4050 if (shdr.sh_type == elf.SHT_NOBITS) continue;
4051 if (atom_list.atoms.items.len == 0) continue;
4052 atom_list.write(&buffer, &undefs, self) catch |err| switch (err) {
4053 error.UnsupportedCpuArch => {
4054 try self.reportUnsupportedCpuArch();
4055 return error.FlushFailure;
4056 },
4057 error.RelocFailure, error.RelaxFailure => has_reloc_errors = true,
4058 else => |e| return e,
4059 };
4060 }
4061
4062 try self.reportUndefinedSymbols(&undefs);
4063 if (has_reloc_errors) return error.FlushFailure;
40444064
4065 if (self.requiresThunks()) {
4045 for (self.thunks.items) |th| {4066 for (self.thunks.items) |th| {
4046 const thunk_size = th.size(self);4067 const thunk_size = th.size(self);
4047 try buffer.ensureUnusedCapacity(thunk_size);4068 try buffer.ensureUnusedCapacity(thunk_size);
...@@ -4993,7 +5014,7 @@ pub fn insertDynString(self: *Elf, name: []const u8) error{OutOfMemory}!u32 {...@@ -4993,7 +5014,7 @@ pub fn insertDynString(self: *Elf, name: []const u8) error{OutOfMemory}!u32 {
4993 return off;5014 return off;
4994}5015}
49955016
4996pub fn reportUndefinedSymbols(self: *Elf, undefs: anytype) !void {5017fn reportUndefinedSymbols(self: *Elf, undefs: anytype) !void {
4997 const gpa = self.base.comp.gpa;5018 const gpa = self.base.comp.gpa;
4998 const max_notes = 4;5019 const max_notes = 4;
49995020
...@@ -5061,7 +5082,7 @@ fn reportMissingLibraryError(...@@ -5061,7 +5082,7 @@ fn reportMissingLibraryError(
5061 }5082 }
5062}5083}
50635084
5064pub fn reportUnsupportedCpuArch(self: *Elf) error{OutOfMemory}!void {5085fn reportUnsupportedCpuArch(self: *Elf) error{OutOfMemory}!void {
5065 var err = try self.base.addErrorWithNotes(0);5086 var err = try self.base.addErrorWithNotes(0);
5066 try err.addMsg("fatal linker error: unsupported CPU architecture {s}", .{5087 try err.addMsg("fatal linker error: unsupported CPU architecture {s}", .{
5067 @tagName(self.getTarget().cpu.arch),5088 @tagName(self.getTarget().cpu.arch),
...@@ -5248,9 +5269,8 @@ fn fmtDumpState(...@@ -5248,9 +5269,8 @@ fn fmtDumpState(
5248 try writer.print("object({d}) : {}", .{ index, object.fmtPath() });5269 try writer.print("object({d}) : {}", .{ index, object.fmtPath() });
5249 if (!object.alive) try writer.writeAll(" : [*]");5270 if (!object.alive) try writer.writeAll(" : [*]");
5250 try writer.writeByte('\n');5271 try writer.writeByte('\n');
5251 try writer.print("{}{}{}{}{}{}\n", .{5272 try writer.print("{}{}{}{}{}\n", .{
5252 object.fmtAtoms(self),5273 object.fmtAtoms(self),
5253 object.fmtSectionChunks(self),
5254 object.fmtCies(self),5274 object.fmtCies(self),
5255 object.fmtFdes(self),5275 object.fmtFdes(self),
5256 object.fmtSymtab(self),5276 object.fmtSymtab(self),
...@@ -5274,6 +5294,14 @@ fn fmtDumpState(...@@ -5274,6 +5294,14 @@ fn fmtDumpState(
5274 try writer.print("{}\n", .{linker_defined.fmtSymtab(self)});5294 try writer.print("{}\n", .{linker_defined.fmtSymtab(self)});
5275 }5295 }
52765296
5297 const slice = self.sections.slice();
5298 {
5299 try writer.writeAll("atom lists\n");
5300 for (slice.items(.shdr), slice.items(.atom_list_2), 0..) |shdr, atom_list, shndx| {
5301 try writer.print("shdr({d}) : {s} : {}", .{ shndx, self.getShString(shdr.sh_name), atom_list.fmt(self) });
5302 }
5303 }
5304
5277 if (self.requiresThunks()) {5305 if (self.requiresThunks()) {
5278 try writer.writeAll("thunks\n");5306 try writer.writeAll("thunks\n");
5279 for (self.thunks.items, 0..) |th, index| {5307 for (self.thunks.items, 0..) |th, index| {
...@@ -5295,7 +5323,7 @@ fn fmtDumpState(...@@ -5295,7 +5323,7 @@ fn fmtDumpState(
5295 }5323 }
52965324
5297 try writer.writeAll("\nOutput shdrs\n");5325 try writer.writeAll("\nOutput shdrs\n");
5298 for (self.sections.items(.shdr), self.sections.items(.phndx), 0..) |shdr, phndx, shndx| {5326 for (slice.items(.shdr), slice.items(.phndx), 0..) |shdr, phndx, shndx| {
5299 try writer.print(" shdr({d}) : phdr({?d}) : {}\n", .{5327 try writer.print(" shdr({d}) : phdr({?d}) : {}\n", .{
5300 shndx,5328 shndx,
5301 phndx,5329 phndx,
...@@ -5549,8 +5577,14 @@ const Section = struct {...@@ -5549,8 +5577,14 @@ const Section = struct {
5549 phndx: ?u32 = null,5577 phndx: ?u32 = null,
55505578
5551 /// List of atoms contributing to this section.5579 /// List of atoms contributing to this section.
5580 /// TODO currently this is only used for relocations tracking in relocatable mode
5581 /// but will be merged with atom_list_2.
5552 atom_list: std.ArrayListUnmanaged(Ref) = .{},5582 atom_list: std.ArrayListUnmanaged(Ref) = .{},
55535583
5584 /// List of atoms contributing to this section.
5585 /// This can be used by sections that require special handling such as init/fini array, etc.
5586 atom_list_2: AtomList = .{},
5587
5554 /// Index of the last allocated atom in this section.5588 /// Index of the last allocated atom in this section.
5555 last_atom: Ref = .{ .index = 0, .file = 0 },5589 last_atom: Ref = .{ .index = 0, .file = 0 },
55565590
...@@ -5690,6 +5724,7 @@ const Air = @import("../Air.zig");...@@ -5690,6 +5724,7 @@ const Air = @import("../Air.zig");
5690const Allocator = std.mem.Allocator;5724const Allocator = std.mem.Allocator;
5691const Archive = @import("Elf/Archive.zig");5725const Archive = @import("Elf/Archive.zig");
5692pub const Atom = @import("Elf/Atom.zig");5726pub const Atom = @import("Elf/Atom.zig");
5727const AtomList = @import("Elf/AtomList.zig");
5693const Cache = std.Build.Cache;5728const Cache = std.Build.Cache;
5694const Path = Cache.Path;5729const Path = Cache.Path;
5695const Compilation = @import("../Compilation.zig");5730const Compilation = @import("../Compilation.zig");
src/link/Elf/Object.zig+4-272
...@@ -17,7 +17,6 @@ relocs: std.ArrayListUnmanaged(elf.Elf64_Rela) = .{},...@@ -17,7 +17,6 @@ relocs: std.ArrayListUnmanaged(elf.Elf64_Rela) = .{},
17atoms: std.ArrayListUnmanaged(Atom) = .{},17atoms: std.ArrayListUnmanaged(Atom) = .{},
18atoms_indexes: std.ArrayListUnmanaged(Atom.Index) = .{},18atoms_indexes: std.ArrayListUnmanaged(Atom.Index) = .{},
19atoms_extra: std.ArrayListUnmanaged(u32) = .{},19atoms_extra: std.ArrayListUnmanaged(u32) = .{},
20section_chunks: std.ArrayListUnmanaged(SectionChunk) = .{},
2120
22comdat_groups: std.ArrayListUnmanaged(Elf.ComdatGroup) = .{},21comdat_groups: std.ArrayListUnmanaged(Elf.ComdatGroup) = .{},
23comdat_group_data: std.ArrayListUnmanaged(u32) = .{},22comdat_group_data: std.ArrayListUnmanaged(u32) = .{},
...@@ -59,10 +58,6 @@ pub fn deinit(self: *Object, allocator: Allocator) void {...@@ -59,10 +58,6 @@ pub fn deinit(self: *Object, allocator: Allocator) void {
59 self.atoms.deinit(allocator);58 self.atoms.deinit(allocator);
60 self.atoms_indexes.deinit(allocator);59 self.atoms_indexes.deinit(allocator);
61 self.atoms_extra.deinit(allocator);60 self.atoms_extra.deinit(allocator);
62 for (self.section_chunks.items) |*chunk| {
63 chunk.deinit(allocator);
64 }
65 self.section_chunks.deinit(allocator);
66 self.comdat_groups.deinit(allocator);61 self.comdat_groups.deinit(allocator);
67 self.comdat_group_data.deinit(allocator);62 self.comdat_group_data.deinit(allocator);
68 self.relocs.deinit(allocator);63 self.relocs.deinit(allocator);
...@@ -952,166 +947,9 @@ pub fn initOutputSections(self: *Object, elf_file: *Elf) !void {...@@ -952,166 +947,9 @@ pub fn initOutputSections(self: *Object, elf_file: *Elf) !void {
952 .flags = shdr.sh_flags,947 .flags = shdr.sh_flags,
953 .type = shdr.sh_type,948 .type = shdr.sh_type,
954 });949 });
955 const chunk = for (self.section_chunks.items) |*chunk| {950 const atom_list = &elf_file.sections.items(.atom_list_2)[osec];
956 if (chunk.output_section_index == osec) break chunk;951 atom_list.output_section_index = osec;
957 } else blk: {952 try atom_list.atoms.append(elf_file.base.comp.gpa, atom_ptr.ref());
958 const chunk = try self.section_chunks.addOne(elf_file.base.comp.gpa);
959 chunk.* = .{ .output_section_index = osec };
960 break :blk chunk;
961 };
962 try chunk.atoms.append(elf_file.base.comp.gpa, atom_index);
963 }
964}
965
966pub fn allocateAtoms(self: *Object, elf_file: *Elf) !void {
967 for (self.section_chunks.items) |*chunk| {
968 chunk.updateSize(self);
969 }
970
971 for (self.section_chunks.items) |*chunk| {
972 const alloc_res = try elf_file.allocateChunk(.{
973 .shndx = chunk.output_section_index,
974 .size = chunk.size,
975 .alignment = chunk.alignment,
976 .requires_padding = false,
977 });
978 chunk.value = @intCast(alloc_res.value);
979
980 const slice = elf_file.sections.slice();
981 const shdr = &slice.items(.shdr)[chunk.output_section_index];
982 const last_atom_ref = &slice.items(.last_atom)[chunk.output_section_index];
983
984 const expand_section = if (elf_file.atom(alloc_res.placement)) |placement_atom|
985 placement_atom.nextAtom(elf_file) == null
986 else
987 true;
988 if (expand_section) last_atom_ref.* = chunk.lastAtom(self).ref();
989 shdr.sh_addralign = @max(shdr.sh_addralign, chunk.alignment.toByteUnits().?);
990
991 {
992 var idx: usize = 0;
993 while (idx < chunk.atoms.items.len) : (idx += 1) {
994 const curr_atom_ptr = self.atom(chunk.atoms.items[idx]).?;
995 if (idx > 0) {
996 curr_atom_ptr.prev_atom_ref = .{ .index = chunk.atoms.items[idx - 1], .file = self.index };
997 }
998 if (idx + 1 < chunk.atoms.items.len) {
999 curr_atom_ptr.next_atom_ref = .{ .index = chunk.atoms.items[idx + 1], .file = self.index };
1000 }
1001 }
1002 }
1003
1004 if (elf_file.atom(alloc_res.placement)) |placement_atom| {
1005 chunk.firstAtom(self).prev_atom_ref = placement_atom.ref();
1006 chunk.lastAtom(self).next_atom_ref = placement_atom.next_atom_ref;
1007 placement_atom.next_atom_ref = chunk.firstAtom(self).ref();
1008 }
1009
1010 // TODO if we had a link from Atom to parent Chunk we would not need to update Atom's value or osec index
1011 for (chunk.atoms.items) |atom_index| {
1012 const atom_ptr = self.atom(atom_index).?;
1013 atom_ptr.output_section_index = chunk.output_section_index;
1014 atom_ptr.value += chunk.value;
1015 }
1016 }
1017}
1018
1019pub fn writeAtoms(self: *Object, elf_file: *Elf) !void {
1020 const gpa = elf_file.base.comp.gpa;
1021
1022 var undefs = std.AutoArrayHashMap(Elf.SymbolResolver.Index, std.ArrayList(Elf.Ref)).init(gpa);
1023 defer {
1024 for (undefs.values()) |*refs| {
1025 refs.deinit();
1026 }
1027 undefs.deinit();
1028 }
1029
1030 var buffer = std.ArrayList(u8).init(gpa);
1031 defer buffer.deinit();
1032
1033 log.debug("writing atoms in {}", .{self.fmtPath()});
1034
1035 var has_reloc_errors = false;
1036 for (self.section_chunks.items) |chunk| {
1037 const osec = elf_file.sections.items(.shdr)[chunk.output_section_index];
1038 if (osec.sh_type == elf.SHT_NOBITS) continue;
1039
1040 log.debug(" in section '{s}'", .{elf_file.getShString(osec.sh_name)});
1041
1042 try buffer.ensureUnusedCapacity(chunk.size);
1043 buffer.appendNTimesAssumeCapacity(0, chunk.size);
1044
1045 for (chunk.atoms.items) |atom_index| {
1046 const atom_ptr = self.atom(atom_index).?;
1047 assert(atom_ptr.alive);
1048
1049 const offset = math.cast(usize, atom_ptr.value - chunk.value) orelse return error.Overflow;
1050 const size = math.cast(usize, atom_ptr.size) orelse return error.Overflow;
1051
1052 log.debug(" * atom({d}) at 0x{x}", .{ atom_index, chunk.offset(elf_file) + offset });
1053
1054 const code = try self.codeDecompressAlloc(elf_file, atom_index);
1055 defer gpa.free(code);
1056 const out_code = buffer.items[offset..][0..size];
1057 @memcpy(out_code, code);
1058
1059 const res = if (osec.sh_flags & elf.SHF_ALLOC == 0)
1060 atom_ptr.resolveRelocsNonAlloc(elf_file, out_code, &undefs)
1061 else
1062 atom_ptr.resolveRelocsAlloc(elf_file, out_code);
1063 _ = res catch |err| switch (err) {
1064 error.UnsupportedCpuArch => {
1065 try elf_file.reportUnsupportedCpuArch();
1066 return error.FlushFailure;
1067 },
1068 error.RelocFailure, error.RelaxFailure => has_reloc_errors = true,
1069 else => |e| return e,
1070 };
1071 }
1072
1073 try elf_file.base.file.?.pwriteAll(buffer.items, chunk.offset(elf_file));
1074 buffer.clearRetainingCapacity();
1075 }
1076
1077 try elf_file.reportUndefinedSymbols(&undefs);
1078 if (has_reloc_errors) return error.FlushFailure;
1079}
1080
1081pub fn writeAtomsRelocatable(self: *Object, elf_file: *Elf) !void {
1082 const gpa = elf_file.base.comp.gpa;
1083
1084 var buffer = std.ArrayList(u8).init(gpa);
1085 defer buffer.deinit();
1086
1087 log.debug("writing atoms in {}", .{self.fmtPath()});
1088
1089 for (self.section_chunks.items) |chunk| {
1090 const osec = elf_file.sections.items(.shdr)[chunk.output_section_index];
1091 if (osec.sh_type == elf.SHT_NOBITS) continue;
1092
1093 log.debug(" in section '{s}'", .{elf_file.getShString(osec.sh_name)});
1094
1095 try buffer.ensureUnusedCapacity(chunk.size);
1096 buffer.appendNTimesAssumeCapacity(0, chunk.size);
1097
1098 for (chunk.atoms.items) |atom_index| {
1099 const atom_ptr = self.atom(atom_index).?;
1100 assert(atom_ptr.alive);
1101
1102 const offset = math.cast(usize, atom_ptr.value - chunk.value) orelse return error.Overflow;
1103 const size = math.cast(usize, atom_ptr.size) orelse return error.Overflow;
1104
1105 log.debug(" * atom({d}) at 0x{x}", .{ atom_index, chunk.offset(elf_file) + offset });
1106
1107 const code = try self.codeDecompressAlloc(elf_file, atom_index);
1108 defer gpa.free(code);
1109 const out_code = buffer.items[offset..][0..size];
1110 @memcpy(out_code, code);
1111 }
1112
1113 try elf_file.base.file.?.pwriteAll(buffer.items, chunk.offset(elf_file));
1114 buffer.clearRetainingCapacity();
1115 }953 }
1116}954}
1117955
...@@ -1585,29 +1423,6 @@ fn formatAtoms(...@@ -1585,29 +1423,6 @@ fn formatAtoms(
1585 }1423 }
1586}1424}
15871425
1588pub fn fmtSectionChunks(self: *Object, elf_file: *Elf) std.fmt.Formatter(formatSectionChunks) {
1589 return .{ .data = .{
1590 .object = self,
1591 .elf_file = elf_file,
1592 } };
1593}
1594
1595fn formatSectionChunks(
1596 ctx: FormatContext,
1597 comptime unused_fmt_string: []const u8,
1598 options: std.fmt.FormatOptions,
1599 writer: anytype,
1600) !void {
1601 _ = unused_fmt_string;
1602 _ = options;
1603 const object = ctx.object;
1604 const elf_file = ctx.elf_file;
1605 try writer.writeAll(" section chunks\n");
1606 for (object.section_chunks.items) |chunk| {
1607 try writer.print(" {}\n", .{chunk.fmt(elf_file)});
1608 }
1609}
1610
1611pub fn fmtCies(self: *Object, elf_file: *Elf) std.fmt.Formatter(formatCies) {1426pub fn fmtCies(self: *Object, elf_file: *Elf) std.fmt.Formatter(formatCies) {
1612 return .{ .data = .{1427 return .{ .data = .{
1613 .object = self,1428 .object = self,
...@@ -1709,90 +1524,6 @@ const InArchive = struct {...@@ -1709,90 +1524,6 @@ const InArchive = struct {
1709 size: u32,1524 size: u32,
1710};1525};
17111526
1712const SectionChunk = struct {
1713 value: i64 = 0,
1714 size: u64 = 0,
1715 alignment: Atom.Alignment = .@"1",
1716 output_section_index: u32 = 0,
1717 atoms: std.ArrayListUnmanaged(Atom.Index) = .{},
1718
1719 fn deinit(chunk: *SectionChunk, allocator: Allocator) void {
1720 chunk.atoms.deinit(allocator);
1721 }
1722
1723 fn address(chunk: SectionChunk, elf_file: *Elf) i64 {
1724 const shdr = elf_file.sections.items(.shdr)[chunk.output_section_index];
1725 return @as(i64, @intCast(shdr.sh_addr)) + chunk.value;
1726 }
1727
1728 fn offset(chunk: SectionChunk, elf_file: *Elf) u64 {
1729 const shdr = elf_file.sections.items(.shdr)[chunk.output_section_index];
1730 return shdr.sh_offset + @as(u64, @intCast(chunk.value));
1731 }
1732
1733 fn updateSize(chunk: *SectionChunk, object: *Object) void {
1734 for (chunk.atoms.items) |atom_index| {
1735 const atom_ptr = object.atom(atom_index).?;
1736 assert(atom_ptr.alive);
1737 const off = atom_ptr.alignment.forward(chunk.size);
1738 const padding = off - chunk.size;
1739 atom_ptr.value = @intCast(off);
1740 chunk.size += padding + atom_ptr.size;
1741 chunk.alignment = chunk.alignment.max(atom_ptr.alignment);
1742 }
1743 }
1744
1745 fn firstAtom(chunk: SectionChunk, object: *Object) *Atom {
1746 assert(chunk.atoms.items.len > 0);
1747 return object.atom(chunk.atoms.items[0]).?;
1748 }
1749
1750 fn lastAtom(chunk: SectionChunk, object: *Object) *Atom {
1751 assert(chunk.atoms.items.len > 0);
1752 return object.atom(chunk.atoms.items[chunk.atoms.items.len - 1]).?;
1753 }
1754
1755 pub fn format(
1756 chunk: SectionChunk,
1757 comptime unused_fmt_string: []const u8,
1758 options: std.fmt.FormatOptions,
1759 writer: anytype,
1760 ) !void {
1761 _ = chunk;
1762 _ = unused_fmt_string;
1763 _ = options;
1764 _ = writer;
1765 @compileError("do not format SectionChunk directly");
1766 }
1767
1768 const FormatCtx = struct { SectionChunk, *Elf };
1769
1770 pub fn fmt(chunk: SectionChunk, elf_file: *Elf) std.fmt.Formatter(format2) {
1771 return .{ .data = .{ chunk, elf_file } };
1772 }
1773
1774 fn format2(
1775 ctx: FormatCtx,
1776 comptime unused_fmt_string: []const u8,
1777 options: std.fmt.FormatOptions,
1778 writer: anytype,
1779 ) !void {
1780 _ = unused_fmt_string;
1781 _ = options;
1782 const chunk, const elf_file = ctx;
1783 try writer.print("chunk : @{x} : shdr({d}) : align({x}) : size({x})", .{
1784 chunk.address(elf_file), chunk.output_section_index,
1785 chunk.alignment.toByteUnits() orelse 0, chunk.size,
1786 });
1787 try writer.writeAll(" : atoms{ ");
1788 for (chunk.atoms.items, 0..) |atom_index, i| {
1789 try writer.print("{d}", .{atom_index});
1790 if (i < chunk.atoms.items.len - 1) try writer.writeAll(", ");
1791 }
1792 try writer.writeAll(" }");
1793 }
1794};
1795
1796const Object = @This();1527const Object = @This();
17971528
1798const std = @import("std");1529const std = @import("std");
...@@ -1807,6 +1538,7 @@ const mem = std.mem;...@@ -1807,6 +1538,7 @@ const mem = std.mem;
1807const Allocator = mem.Allocator;1538const Allocator = mem.Allocator;
1808const Archive = @import("Archive.zig");1539const Archive = @import("Archive.zig");
1809const Atom = @import("Atom.zig");1540const Atom = @import("Atom.zig");
1541const AtomList = @import("AtomList.zig");
1810const Cie = eh_frame.Cie;1542const Cie = eh_frame.Cie;
1811const Elf = @import("../Elf.zig");1543const Elf = @import("../Elf.zig");
1812const Fde = eh_frame.Fde;1544const Fde = eh_frame.Fde;
src/link/Elf/relocatable.zig+15-5
...@@ -353,11 +353,13 @@ fn initComdatGroups(elf_file: *Elf) !void {...@@ -353,11 +353,13 @@ fn initComdatGroups(elf_file: *Elf) !void {
353}353}
354354
355fn updateSectionSizes(elf_file: *Elf) !void {355fn updateSectionSizes(elf_file: *Elf) !void {
356 for (elf_file.objects.items) |index| {356 const slice = elf_file.sections.slice();
357 try elf_file.file(index).?.object.allocateAtoms(elf_file);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);
358 }361 }
359362
360 const slice = elf_file.sections.slice();
361 for (slice.items(.shdr), 0..) |*shdr, shndx| {363 for (slice.items(.shdr), 0..) |*shdr, shndx| {
362 const atom_list = slice.items(.atom_list)[shndx];364 const atom_list = slice.items(.atom_list)[shndx];
363 if (shdr.sh_type != elf.SHT_RELA) continue;365 if (shdr.sh_type != elf.SHT_RELA) continue;
...@@ -444,8 +446,16 @@ fn allocateAllocSections(elf_file: *Elf) !void {...@@ -444,8 +446,16 @@ fn allocateAllocSections(elf_file: *Elf) !void {
444}446}
445447
446fn writeAtoms(elf_file: *Elf) !void {448fn writeAtoms(elf_file: *Elf) !void {
447 for (elf_file.objects.items) |index| {449 const gpa = elf_file.base.comp.gpa;
448 try elf_file.file(index).?.object.writeAtomsRelocatable(elf_file);450
451 var buffer = std.ArrayList(u8).init(gpa);
452 defer buffer.deinit();
453
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);
449 }459 }
450}460}
451461