| author | |
| committer | |
| log | d302a1068effe4edcd36bd01f77ac2e1b1048e16 |
| tree | be0f2fc35bb60239b4fbb4e8ebdbe416ddca1f6e |
| parent | 64ad6eff16aac1f6154efa12406818efed57bf73 |
3 files changed, 103 insertions(+), 326 deletions(-)
src/link/Elf.zig+84-49| ... | ... | @@ -393,7 +393,8 @@ pub fn deinit(self: *Elf) void { |
| 393 | 393 | self.objects.deinit(gpa); |
| 394 | 394 | self.shared_objects.deinit(gpa); |
| 395 | 395 | |
| 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 | 398 | atoms.deinit(gpa); |
| 398 | 399 | free_list.deinit(gpa); |
| 399 | 400 | } |
| ... | ... | @@ -3204,8 +3205,9 @@ fn sortInitFini(self: *Elf) !void { |
| 3204 | 3205 | } |
| 3205 | 3206 | }; |
| 3206 | 3207 | |
| 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 | 3209 | if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue; |
| 3210 | if (atom_list.atoms.items.len == 0) continue; | |
| 3209 | 3211 | |
| 3210 | 3212 | var is_init_fini = false; |
| 3211 | 3213 | var is_ctor_dtor = false; |
| ... | ... | @@ -3219,15 +3221,13 @@ fn sortInitFini(self: *Elf) !void { |
| 3219 | 3221 | is_ctor_dtor = mem.indexOf(u8, name, ".ctors") != null or mem.indexOf(u8, name, ".dtors") != null; |
| 3220 | 3222 | }, |
| 3221 | 3223 | } |
| 3222 | ||
| 3223 | 3224 | if (!is_init_fini and !is_ctor_dtor) continue; |
| 3224 | if (atom_list.items.len == 0) continue; | |
| 3225 | 3225 | |
| 3226 | 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 | 3228 | defer entries.deinit(); |
| 3229 | 3229 | |
| 3230 | for (atom_list.items) |ref| { | |
| 3230 | for (atom_list.atoms.items) |ref| { | |
| 3231 | 3231 | const atom_ptr = self.atom(ref).?; |
| 3232 | 3232 | const object = atom_ptr.file(self).?.object; |
| 3233 | 3233 | const priority = blk: { |
| ... | ... | @@ -3246,9 +3246,9 @@ fn sortInitFini(self: *Elf) !void { |
| 3246 | 3246 | |
| 3247 | 3247 | mem.sort(Entry, entries.items, self, Entry.lessThan); |
| 3248 | 3248 | |
| 3249 | atom_list.clearRetainingCapacity(); | |
| 3249 | atom_list.atoms.clearRetainingCapacity(); | |
| 3250 | 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 | 3491 | msec.output_section_index = backlinks[msec.output_section_index]; |
| 3492 | 3492 | } |
| 3493 | 3493 | |
| 3494 | for (self.sections.items(.shdr)) |*shdr| { | |
| 3495 | if (shdr.sh_type != elf.SHT_RELA) continue; | |
| 3496 | // FIXME:JK we should spin up .symtab potentially earlier, or set all non-dynamic RELA sections | |
| 3497 | // to point at symtab | |
| 3498 | // shdr.sh_link = backlinks[shdr.sh_link]; | |
| 3499 | shdr.sh_link = self.symtab_section_index.?; | |
| 3500 | shdr.sh_info = backlinks[shdr.sh_info]; | |
| 3494 | const slice = self.sections.slice(); | |
| 3495 | for (slice.items(.shdr), slice.items(.atom_list_2)) |*shdr, *atom_list| { | |
| 3496 | atom_list.output_section_index = backlinks[atom_list.output_section_index]; | |
| 3497 | for (atom_list.atoms.items) |ref| { | |
| 3498 | self.atom(ref).?.output_section_index = atom_list.output_section_index; | |
| 3499 | } | |
| 3500 | if (shdr.sh_type == elf.SHT_RELA) { | |
| 3501 | // FIXME:JK we should spin up .symtab potentially earlier, or set all non-dynamic RELA sections | |
| 3502 | // to point at symtab | |
| 3503 | // shdr.sh_link = backlinks[shdr.sh_link]; | |
| 3504 | shdr.sh_link = self.symtab_section_index.?; | |
| 3505 | shdr.sh_info = backlinks[shdr.sh_info]; | |
| 3506 | } | |
| 3501 | 3507 | } |
| 3502 | 3508 | |
| 3503 | 3509 | if (self.zigObjectPtr()) |zo| { |
| ... | ... | @@ -3507,79 +3513,71 @@ fn resetShdrIndexes(self: *Elf, backlinks: []const u32) void { |
| 3507 | 3513 | } |
| 3508 | 3514 | } |
| 3509 | 3515 | |
| 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 | 3516 | for (self.comdat_group_sections.items) |*cg| { |
| 3521 | 3517 | cg.shndx = backlinks[cg.shndx]; |
| 3522 | 3518 | } |
| 3523 | 3519 | |
| 3524 | 3520 | if (self.symtab_section_index) |index| { |
| 3525 | const shdr = &self.sections.items(.shdr)[index]; | |
| 3521 | const shdr = &slice.items(.shdr)[index]; | |
| 3526 | 3522 | shdr.sh_link = self.strtab_section_index.?; |
| 3527 | 3523 | } |
| 3528 | 3524 | |
| 3529 | 3525 | if (self.dynamic_section_index) |index| { |
| 3530 | const shdr = &self.sections.items(.shdr)[index]; | |
| 3526 | const shdr = &slice.items(.shdr)[index]; | |
| 3531 | 3527 | shdr.sh_link = self.dynstrtab_section_index.?; |
| 3532 | 3528 | } |
| 3533 | 3529 | |
| 3534 | 3530 | if (self.dynsymtab_section_index) |index| { |
| 3535 | const shdr = &self.sections.items(.shdr)[index]; | |
| 3531 | const shdr = &slice.items(.shdr)[index]; | |
| 3536 | 3532 | shdr.sh_link = self.dynstrtab_section_index.?; |
| 3537 | 3533 | } |
| 3538 | 3534 | |
| 3539 | 3535 | if (self.hash_section_index) |index| { |
| 3540 | const shdr = &self.sections.items(.shdr)[index]; | |
| 3536 | const shdr = &slice.items(.shdr)[index]; | |
| 3541 | 3537 | shdr.sh_link = self.dynsymtab_section_index.?; |
| 3542 | 3538 | } |
| 3543 | 3539 | |
| 3544 | 3540 | if (self.gnu_hash_section_index) |index| { |
| 3545 | const shdr = &self.sections.items(.shdr)[index]; | |
| 3541 | const shdr = &slice.items(.shdr)[index]; | |
| 3546 | 3542 | shdr.sh_link = self.dynsymtab_section_index.?; |
| 3547 | 3543 | } |
| 3548 | 3544 | |
| 3549 | 3545 | if (self.versym_section_index) |index| { |
| 3550 | const shdr = &self.sections.items(.shdr)[index]; | |
| 3546 | const shdr = &slice.items(.shdr)[index]; | |
| 3551 | 3547 | shdr.sh_link = self.dynsymtab_section_index.?; |
| 3552 | 3548 | } |
| 3553 | 3549 | |
| 3554 | 3550 | if (self.verneed_section_index) |index| { |
| 3555 | const shdr = &self.sections.items(.shdr)[index]; | |
| 3551 | const shdr = &slice.items(.shdr)[index]; | |
| 3556 | 3552 | shdr.sh_link = self.dynstrtab_section_index.?; |
| 3557 | 3553 | } |
| 3558 | 3554 | |
| 3559 | 3555 | if (self.rela_dyn_section_index) |index| { |
| 3560 | const shdr = &self.sections.items(.shdr)[index]; | |
| 3556 | const shdr = &slice.items(.shdr)[index]; | |
| 3561 | 3557 | shdr.sh_link = self.dynsymtab_section_index orelse 0; |
| 3562 | 3558 | } |
| 3563 | 3559 | |
| 3564 | 3560 | if (self.rela_plt_section_index) |index| { |
| 3565 | const shdr = &self.sections.items(.shdr)[index]; | |
| 3561 | const shdr = &slice.items(.shdr)[index]; | |
| 3566 | 3562 | shdr.sh_link = self.dynsymtab_section_index.?; |
| 3567 | 3563 | shdr.sh_info = self.plt_section_index.?; |
| 3568 | 3564 | } |
| 3569 | 3565 | |
| 3570 | 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 | 3568 | shdr.sh_link = self.symtab_section_index.?; |
| 3573 | 3569 | shdr.sh_info = self.eh_frame_section_index.?; |
| 3574 | 3570 | } |
| 3575 | 3571 | } |
| 3576 | 3572 | |
| 3577 | 3573 | fn updateSectionSizes(self: *Elf) !void { |
| 3578 | for (self.objects.items) |index| { | |
| 3579 | try self.file(index).?.object.allocateAtoms(self); | |
| 3574 | const slice = self.sections.slice(); | |
| 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 | } |
| 3581 | 3580 | |
| 3582 | const slice = self.sections.slice(); | |
| 3583 | 3581 | if (self.requiresThunks()) { |
| 3584 | 3582 | for (slice.items(.shdr), slice.items(.atom_list), 0..) |*shdr, atom_list, shndx| { |
| 3585 | 3583 | if (shdr.sh_flags & elf.SHF_EXECINSTR == 0) continue; |
| ... | ... | @@ -4033,15 +4031,38 @@ fn allocateSpecialPhdrs(self: *Elf) void { |
| 4033 | 4031 | } |
| 4034 | 4032 | |
| 4035 | 4033 | fn writeAtoms(self: *Elf) !void { |
| 4036 | for (self.objects.items) |index| { | |
| 4037 | try self.file(index).?.object.writeAtoms(self); | |
| 4034 | const gpa = self.base.comp.gpa; | |
| 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 | } |
| 4039 | 4043 | |
| 4040 | if (self.requiresThunks()) { | |
| 4041 | const gpa = self.base.comp.gpa; | |
| 4042 | var buffer = std.ArrayList(u8).init(gpa); | |
| 4043 | defer buffer.deinit(); | |
| 4044 | var buffer = std.ArrayList(u8).init(gpa); | |
| 4045 | defer buffer.deinit(); | |
| 4046 | ||
| 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; | |
| 4044 | 4064 | |
| 4065 | if (self.requiresThunks()) { | |
| 4045 | 4066 | for (self.thunks.items) |th| { |
| 4046 | 4067 | const thunk_size = th.size(self); |
| 4047 | 4068 | try buffer.ensureUnusedCapacity(thunk_size); |
| ... | ... | @@ -4993,7 +5014,7 @@ pub fn insertDynString(self: *Elf, name: []const u8) error{OutOfMemory}!u32 { |
| 4993 | 5014 | return off; |
| 4994 | 5015 | } |
| 4995 | 5016 | |
| 4996 | pub fn reportUndefinedSymbols(self: *Elf, undefs: anytype) !void { | |
| 5017 | fn reportUndefinedSymbols(self: *Elf, undefs: anytype) !void { | |
| 4997 | 5018 | const gpa = self.base.comp.gpa; |
| 4998 | 5019 | const max_notes = 4; |
| 4999 | 5020 | |
| ... | ... | @@ -5061,7 +5082,7 @@ fn reportMissingLibraryError( |
| 5061 | 5082 | } |
| 5062 | 5083 | } |
| 5063 | 5084 | |
| 5064 | pub fn reportUnsupportedCpuArch(self: *Elf) error{OutOfMemory}!void { | |
| 5085 | fn reportUnsupportedCpuArch(self: *Elf) error{OutOfMemory}!void { | |
| 5065 | 5086 | var err = try self.base.addErrorWithNotes(0); |
| 5066 | 5087 | try err.addMsg("fatal linker error: unsupported CPU architecture {s}", .{ |
| 5067 | 5088 | @tagName(self.getTarget().cpu.arch), |
| ... | ... | @@ -5248,9 +5269,8 @@ fn fmtDumpState( |
| 5248 | 5269 | try writer.print("object({d}) : {}", .{ index, object.fmtPath() }); |
| 5249 | 5270 | if (!object.alive) try writer.writeAll(" : [*]"); |
| 5250 | 5271 | try writer.writeByte('\n'); |
| 5251 | try writer.print("{}{}{}{}{}{}\n", .{ | |
| 5272 | try writer.print("{}{}{}{}{}\n", .{ | |
| 5252 | 5273 | object.fmtAtoms(self), |
| 5253 | object.fmtSectionChunks(self), | |
| 5254 | 5274 | object.fmtCies(self), |
| 5255 | 5275 | object.fmtFdes(self), |
| 5256 | 5276 | object.fmtSymtab(self), |
| ... | ... | @@ -5274,6 +5294,14 @@ fn fmtDumpState( |
| 5274 | 5294 | try writer.print("{}\n", .{linker_defined.fmtSymtab(self)}); |
| 5275 | 5295 | } |
| 5276 | 5296 | |
| 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 | 5305 | if (self.requiresThunks()) { |
| 5278 | 5306 | try writer.writeAll("thunks\n"); |
| 5279 | 5307 | for (self.thunks.items, 0..) |th, index| { |
| ... | ... | @@ -5295,7 +5323,7 @@ fn fmtDumpState( |
| 5295 | 5323 | } |
| 5296 | 5324 | |
| 5297 | 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 | 5327 | try writer.print(" shdr({d}) : phdr({?d}) : {}\n", .{ |
| 5300 | 5328 | shndx, |
| 5301 | 5329 | phndx, |
| ... | ... | @@ -5549,8 +5577,14 @@ const Section = struct { |
| 5549 | 5577 | phndx: ?u32 = null, |
| 5550 | 5578 | |
| 5551 | 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 | 5582 | atom_list: std.ArrayListUnmanaged(Ref) = .{}, |
| 5553 | 5583 | |
| 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 | 5588 | /// Index of the last allocated atom in this section. |
| 5555 | 5589 | last_atom: Ref = .{ .index = 0, .file = 0 }, |
| 5556 | 5590 | |
| ... | ... | @@ -5690,6 +5724,7 @@ const Air = @import("../Air.zig"); |
| 5690 | 5724 | const Allocator = std.mem.Allocator; |
| 5691 | 5725 | const Archive = @import("Elf/Archive.zig"); |
| 5692 | 5726 | pub const Atom = @import("Elf/Atom.zig"); |
| 5727 | const AtomList = @import("Elf/AtomList.zig"); | |
| 5693 | 5728 | const Cache = std.Build.Cache; |
| 5694 | 5729 | const Path = Cache.Path; |
| 5695 | 5730 | const Compilation = @import("../Compilation.zig"); |
src/link/Elf/Object.zig+4-272| ... | ... | @@ -17,7 +17,6 @@ relocs: std.ArrayListUnmanaged(elf.Elf64_Rela) = .{}, |
| 17 | 17 | atoms: std.ArrayListUnmanaged(Atom) = .{}, |
| 18 | 18 | atoms_indexes: std.ArrayListUnmanaged(Atom.Index) = .{}, |
| 19 | 19 | atoms_extra: std.ArrayListUnmanaged(u32) = .{}, |
| 20 | section_chunks: std.ArrayListUnmanaged(SectionChunk) = .{}, | |
| 21 | 20 | |
| 22 | 21 | comdat_groups: std.ArrayListUnmanaged(Elf.ComdatGroup) = .{}, |
| 23 | 22 | comdat_group_data: std.ArrayListUnmanaged(u32) = .{}, |
| ... | ... | @@ -59,10 +58,6 @@ pub fn deinit(self: *Object, allocator: Allocator) void { |
| 59 | 58 | self.atoms.deinit(allocator); |
| 60 | 59 | self.atoms_indexes.deinit(allocator); |
| 61 | 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 | 61 | self.comdat_groups.deinit(allocator); |
| 67 | 62 | self.comdat_group_data.deinit(allocator); |
| 68 | 63 | self.relocs.deinit(allocator); |
| ... | ... | @@ -952,166 +947,9 @@ pub fn initOutputSections(self: *Object, elf_file: *Elf) !void { |
| 952 | 947 | .flags = shdr.sh_flags, |
| 953 | 948 | .type = shdr.sh_type, |
| 954 | 949 | }); |
| 955 | const chunk = for (self.section_chunks.items) |*chunk| { | |
| 956 | if (chunk.output_section_index == osec) break chunk; | |
| 957 | } else blk: { | |
| 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 | ||
| 966 | pub 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 | ||
| 1019 | pub 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 | ||
| 1081 | pub 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(); | |
| 950 | const atom_list = &elf_file.sections.items(.atom_list_2)[osec]; | |
| 951 | atom_list.output_section_index = osec; | |
| 952 | try atom_list.atoms.append(elf_file.base.comp.gpa, atom_ptr.ref()); | |
| 1115 | 953 | } |
| 1116 | 954 | } |
| 1117 | 955 | |
| ... | ... | @@ -1585,29 +1423,6 @@ fn formatAtoms( |
| 1585 | 1423 | } |
| 1586 | 1424 | } |
| 1587 | 1425 | |
| 1588 | pub 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 | ||
| 1595 | fn 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 | ||
| 1611 | 1426 | pub fn fmtCies(self: *Object, elf_file: *Elf) std.fmt.Formatter(formatCies) { |
| 1612 | 1427 | return .{ .data = .{ |
| 1613 | 1428 | .object = self, |
| ... | ... | @@ -1709,90 +1524,6 @@ const InArchive = struct { |
| 1709 | 1524 | size: u32, |
| 1710 | 1525 | }; |
| 1711 | 1526 | |
| 1712 | const 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 | ||
| 1796 | 1527 | const Object = @This(); |
| 1797 | 1528 | |
| 1798 | 1529 | const std = @import("std"); |
| ... | ... | @@ -1807,6 +1538,7 @@ const mem = std.mem; |
| 1807 | 1538 | const Allocator = mem.Allocator; |
| 1808 | 1539 | const Archive = @import("Archive.zig"); |
| 1809 | 1540 | const Atom = @import("Atom.zig"); |
| 1541 | const AtomList = @import("AtomList.zig"); | |
| 1810 | 1542 | const Cie = eh_frame.Cie; |
| 1811 | 1543 | const Elf = @import("../Elf.zig"); |
| 1812 | 1544 | const Fde = eh_frame.Fde; |
src/link/Elf/relocatable.zig+15-5| ... | ... | @@ -353,11 +353,13 @@ fn initComdatGroups(elf_file: *Elf) !void { |
| 353 | 353 | } |
| 354 | 354 | |
| 355 | 355 | fn updateSectionSizes(elf_file: *Elf) !void { |
| 356 | for (elf_file.objects.items) |index| { | |
| 357 | try elf_file.file(index).?.object.allocateAtoms(elf_file); | |
| 356 | const slice = elf_file.sections.slice(); | |
| 357 | for (slice.items(.atom_list_2)) |*atom_list| { | |
| 358 | if (atom_list.atoms.items.len == 0) continue; | |
| 359 | atom_list.updateSize(elf_file); | |
| 360 | try atom_list.allocate(elf_file); | |
| 358 | 361 | } |
| 359 | 362 | |
| 360 | const slice = elf_file.sections.slice(); | |
| 361 | 363 | for (slice.items(.shdr), 0..) |*shdr, shndx| { |
| 362 | 364 | const atom_list = slice.items(.atom_list)[shndx]; |
| 363 | 365 | if (shdr.sh_type != elf.SHT_RELA) continue; |
| ... | ... | @@ -444,8 +446,16 @@ fn allocateAllocSections(elf_file: *Elf) !void { |
| 444 | 446 | } |
| 445 | 447 | |
| 446 | 448 | fn writeAtoms(elf_file: *Elf) !void { |
| 447 | for (elf_file.objects.items) |index| { | |
| 448 | try elf_file.file(index).?.object.writeAtomsRelocatable(elf_file); | |
| 449 | const gpa = elf_file.base.comp.gpa; | |
| 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 | } |
| 451 | 461 |