authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-10-03 16:40:39+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-10-16 19:33:04+02:00
log9ccd94d56037e05e87755887e334aa6a1a096ec5
tree9abe67a02442a5b6bad0a653104a98088e95ccd4
parent53340544c6666d9d35463f509fbe0416f607c91c

elf: refactor object.shdrContents to never error out


5 files changed, 167 insertions(+), 72 deletions(-)

src/link/Elf.zig+49-5
...@@ -1235,7 +1235,8 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1235,7 +1235,8 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1235 // input Object files.1235 // input Object files.
1236 // Any qualifing unresolved symbol will be upgraded to an absolute, weak1236 // Any qualifing unresolved symbol will be upgraded to an absolute, weak
1237 // symbol for potential resolution at load-time.1237 // symbol for potential resolution at load-time.
1238 try self.resolveSymbols();1238 self.resolveSymbols();
1239 self.markEhFrameAtomsDead();
1239 self.markImportsExports();1240 self.markImportsExports();
1240 self.claimUnresolved();1241 self.claimUnresolved();
12411242
...@@ -1610,7 +1611,7 @@ fn parseArchive(...@@ -1610,7 +1611,7 @@ fn parseArchive(
1610/// 4. Reset state of all resolved globals since we will redo this bit on the pruned set.1611/// 4. Reset state of all resolved globals since we will redo this bit on the pruned set.
1611/// 5. Remove references to dead objects/shared objects1612/// 5. Remove references to dead objects/shared objects
1612/// 6. Re-run symbol resolution on pruned objects and shared objects sets.1613/// 6. Re-run symbol resolution on pruned objects and shared objects sets.
1613fn resolveSymbols(self: *Elf) error{Overflow}!void {1614fn resolveSymbols(self: *Elf) void {
1614 // Resolve symbols in the ZigModule. For now, we assume that it's always live.1615 // Resolve symbols in the ZigModule. For now, we assume that it's always live.
1615 if (self.zig_module_index) |index| self.file(index).?.resolveSymbols(self);1616 if (self.zig_module_index) |index| self.file(index).?.resolveSymbols(self);
1616 // Resolve symbols on the set of all objects and shared objects (even if some are unneeded).1617 // Resolve symbols on the set of all objects and shared objects (even if some are unneeded).
...@@ -1652,11 +1653,11 @@ fn resolveSymbols(self: *Elf) error{Overflow}!void {...@@ -1652,11 +1653,11 @@ fn resolveSymbols(self: *Elf) error{Overflow}!void {
1652 const cg = self.comdatGroup(cg_index);1653 const cg = self.comdatGroup(cg_index);
1653 const cg_owner = self.comdatGroupOwner(cg.owner);1654 const cg_owner = self.comdatGroupOwner(cg.owner);
1654 if (cg_owner.file != index) {1655 if (cg_owner.file != index) {
1655 for (try object.comdatGroupMembers(cg.shndx)) |shndx| {1656 for (object.comdatGroupMembers(cg.shndx)) |shndx| {
1656 const atom_index = object.atoms.items[shndx];1657 const atom_index = object.atoms.items[shndx];
1657 if (self.atom(atom_index)) |atom_ptr| {1658 if (self.atom(atom_index)) |atom_ptr| {
1658 atom_ptr.flags.alive = false;1659 atom_ptr.flags.alive = false;
1659 // atom_ptr.markFdesDead(self);1660 atom_ptr.markFdesDead(self);
1660 }1661 }
1661 }1662 }
1662 }1663 }
...@@ -1680,6 +1681,14 @@ fn markLive(self: *Elf) void {...@@ -1680,6 +1681,14 @@ fn markLive(self: *Elf) void {
1680 }1681 }
1681}1682}
16821683
1684fn markEhFrameAtomsDead(self: *Elf) void {
1685 for (self.objects.items) |index| {
1686 const file_ptr = self.file(index).?;
1687 if (!file_ptr.isAlive()) continue;
1688 file_ptr.object.markEhFrameAtomsDead(self);
1689 }
1690}
1691
1683fn markImportsExports(self: *Elf) void {1692fn markImportsExports(self: *Elf) void {
1684 const mark = struct {1693 const mark = struct {
1685 fn mark(elf_file: *Elf, file_index: File.Index) void {1694 fn mark(elf_file: *Elf, file_index: File.Index) void {
...@@ -3389,17 +3398,39 @@ fn initSections(self: *Elf) !void {...@@ -3389,17 +3398,39 @@ fn initSections(self: *Elf) !void {
3389 .p32 => true,3398 .p32 => true,
3390 .p64 => false,3399 .p64 => false,
3391 };3400 };
3401 const ptr_size = self.ptrWidthBytes();
33923402
3393 for (self.objects.items) |index| {3403 for (self.objects.items) |index| {
3394 try self.file(index).?.object.initOutputSections(self);3404 try self.file(index).?.object.initOutputSections(self);
3395 }3405 }
33963406
3407 const needs_eh_frame = for (self.objects.items) |index| {
3408 if (self.file(index).?.object.cies.items.len > 0) break true;
3409 } else false;
3410 if (needs_eh_frame) {
3411 self.eh_frame_section_index = try self.addSection(.{
3412 .name = ".eh_frame",
3413 .type = elf.SHT_PROGBITS,
3414 .flags = elf.SHF_ALLOC,
3415 .addralign = ptr_size,
3416 });
3417
3418 if (self.base.options.eh_frame_hdr) {
3419 self.eh_frame_hdr_section_index = try self.addSection(.{
3420 .name = ".eh_frame_hdr",
3421 .type = elf.SHT_PROGBITS,
3422 .flags = elf.SHF_ALLOC,
3423 .addralign = ptr_size,
3424 });
3425 }
3426 }
3427
3397 if (self.got.entries.items.len > 0 and self.got_section_index == null) {3428 if (self.got.entries.items.len > 0 and self.got_section_index == null) {
3398 self.got_section_index = try self.addSection(.{3429 self.got_section_index = try self.addSection(.{
3399 .name = ".got",3430 .name = ".got",
3400 .type = elf.SHT_PROGBITS,3431 .type = elf.SHT_PROGBITS,
3401 .flags = elf.SHF_ALLOC | elf.SHF_WRITE,3432 .flags = elf.SHF_ALLOC | elf.SHF_WRITE,
3402 .addralign = self.ptrWidthBytes(),3433 .addralign = ptr_size,
3403 });3434 });
3404 }3435 }
34053436
...@@ -3533,6 +3564,18 @@ fn updateSectionSizes(self: *Elf) !void {...@@ -3533,6 +3564,18 @@ fn updateSectionSizes(self: *Elf) !void {
3533 self.file(index).?.object.updateSectionSizes(self);3564 self.file(index).?.object.updateSectionSizes(self);
3534 }3565 }
35353566
3567 if (self.eh_frame_section_index) |index| {
3568 const shdr = &self.shdrs.items[index];
3569 shdr.sh_size = try eh_frame.calcEhFrameSize(self);
3570 shdr.sh_addralign = @alignOf(u64);
3571 }
3572
3573 if (self.eh_frame_hdr_section_index) |index| {
3574 const shdr = &self.shdrs.items[index];
3575 shdr.sh_size = eh_frame.calcEhFrameHdrSize(self);
3576 shdr.sh_addralign = @alignOf(u32);
3577 }
3578
3536 if (self.got_section_index) |index| {3579 if (self.got_section_index) |index| {
3537 self.shdrs.items[index].sh_size = self.got.size(self);3580 self.shdrs.items[index].sh_size = self.got.size(self);
3538 }3581 }
...@@ -4937,6 +4980,7 @@ const math = std.math;...@@ -4937,6 +4980,7 @@ const math = std.math;
4937const mem = std.mem;4980const mem = std.mem;
49384981
4939const codegen = @import("../codegen.zig");4982const codegen = @import("../codegen.zig");
4983const eh_frame = @import("Elf/eh_frame.zig");
4940const glibc = @import("../glibc.zig");4984const glibc = @import("../glibc.zig");
4941const link = @import("../link.zig");4985const link = @import("../link.zig");
4942const lldMain = @import("../main.zig").lldMain;4986const lldMain = @import("../main.zig").lldMain;
src/link/Elf/Atom.zig+21-6
...@@ -49,7 +49,7 @@ pub fn file(self: Atom, elf_file: *Elf) ?File {...@@ -49,7 +49,7 @@ pub fn file(self: Atom, elf_file: *Elf) ?File {
49 return elf_file.file(self.file_index);49 return elf_file.file(self.file_index);
50}50}
5151
52pub fn inputShdr(self: Atom, elf_file: *Elf) elf.Elf64_Shdr {52pub fn inputShdr(self: Atom, elf_file: *Elf) Object.ElfShdr {
53 const object = self.file(elf_file).?.object;53 const object = self.file(elf_file).?.object;
54 return object.shdrs.items[self.input_section_index];54 return object.shdrs.items[self.input_section_index];
55}55}
...@@ -272,7 +272,7 @@ pub fn free(self: *Atom, elf_file: *Elf) void {...@@ -272,7 +272,7 @@ pub fn free(self: *Atom, elf_file: *Elf) void {
272 self.* = .{};272 self.* = .{};
273}273}
274274
275pub fn relocs(self: Atom, elf_file: *Elf) error{Overflow}![]align(1) const elf.Elf64_Rela {275pub fn relocs(self: Atom, elf_file: *Elf) []align(1) const elf.Elf64_Rela {
276 return switch (self.file(elf_file).?) {276 return switch (self.file(elf_file).?) {
277 .zig_module => |x| x.relocs.items[self.relocs_section_index].items,277 .zig_module => |x| x.relocs.items[self.relocs_section_index].items,
278 .object => |x| x.getRelocs(self.relocs_section_index),278 .object => |x| x.getRelocs(self.relocs_section_index),
...@@ -280,6 +280,18 @@ pub fn relocs(self: Atom, elf_file: *Elf) error{Overflow}![]align(1) const elf.E...@@ -280,6 +280,18 @@ pub fn relocs(self: Atom, elf_file: *Elf) error{Overflow}![]align(1) const elf.E
280 };280 };
281}281}
282282
283pub fn fdes(self: Atom, elf_file: *Elf) []Fde {
284 if (self.fde_start == self.fde_end) return &[0]Fde{};
285 const object = self.file(elf_file).?.object;
286 return object.fdes.items[self.fde_start..self.fde_end];
287}
288
289pub fn markFdesDead(self: Atom, elf_file: *Elf) void {
290 for (self.fdes(elf_file)) |*fde| {
291 fde.alive = false;
292 }
293}
294
283pub fn addReloc(self: Atom, elf_file: *Elf, reloc: elf.Elf64_Rela) !void {295pub fn addReloc(self: Atom, elf_file: *Elf, reloc: elf.Elf64_Rela) !void {
284 const gpa = elf_file.base.allocator;296 const gpa = elf_file.base.allocator;
285 const file_ptr = self.file(elf_file).?;297 const file_ptr = self.file(elf_file).?;
...@@ -296,8 +308,8 @@ pub fn freeRelocs(self: Atom, elf_file: *Elf) void {...@@ -296,8 +308,8 @@ pub fn freeRelocs(self: Atom, elf_file: *Elf) void {
296 zig_module.relocs.items[self.relocs_section_index].clearRetainingCapacity();308 zig_module.relocs.items[self.relocs_section_index].clearRetainingCapacity();
297}309}
298310
299pub fn scanRelocsRequiresCode(self: Atom, elf_file: *Elf) error{Overflow}!bool {311pub fn scanRelocsRequiresCode(self: Atom, elf_file: *Elf) bool {
300 for (try self.relocs(elf_file)) |rel| {312 for (self.relocs(elf_file)) |rel| {
301 if (rel.r_type() == elf.R_X86_64_GOTTPOFF) return true;313 if (rel.r_type() == elf.R_X86_64_GOTTPOFF) return true;
302 }314 }
303 return false;315 return false;
...@@ -306,7 +318,7 @@ pub fn scanRelocsRequiresCode(self: Atom, elf_file: *Elf) error{Overflow}!bool {...@@ -306,7 +318,7 @@ pub fn scanRelocsRequiresCode(self: Atom, elf_file: *Elf) error{Overflow}!bool {
306pub fn scanRelocs(self: Atom, elf_file: *Elf, code: ?[]const u8, undefs: anytype) !void {318pub fn scanRelocs(self: Atom, elf_file: *Elf, code: ?[]const u8, undefs: anytype) !void {
307 const is_dyn_lib = elf_file.isDynLib();319 const is_dyn_lib = elf_file.isDynLib();
308 const file_ptr = self.file(elf_file).?;320 const file_ptr = self.file(elf_file).?;
309 const rels = try self.relocs(elf_file);321 const rels = self.relocs(elf_file);
310 var i: usize = 0;322 var i: usize = 0;
311 while (i < rels.len) : (i += 1) {323 while (i < rels.len) : (i += 1) {
312 const rel = rels[i];324 const rel = rels[i];
...@@ -456,7 +468,7 @@ pub fn resolveRelocs(self: Atom, elf_file: *Elf, code: []u8) !void {...@@ -456,7 +468,7 @@ pub fn resolveRelocs(self: Atom, elf_file: *Elf, code: []u8) !void {
456 var stream = std.io.fixedBufferStream(code);468 var stream = std.io.fixedBufferStream(code);
457 const cwriter = stream.writer();469 const cwriter = stream.writer();
458470
459 const rels = try self.relocs(elf_file);471 const rels = self.relocs(elf_file);
460 var i: usize = 0;472 var i: usize = 0;
461 while (i < rels.len) : (i += 1) {473 while (i < rels.len) : (i += 1) {
462 const rel = rels[i];474 const rel = rels[i];
...@@ -841,11 +853,14 @@ const x86_64 = struct {...@@ -841,11 +853,14 @@ const x86_64 = struct {
841const std = @import("std");853const std = @import("std");
842const assert = std.debug.assert;854const assert = std.debug.assert;
843const elf = std.elf;855const elf = std.elf;
856const eh_frame = @import("eh_frame.zig");
844const log = std.log.scoped(.link);857const log = std.log.scoped(.link);
845const relocs_log = std.log.scoped(.link_relocs);858const relocs_log = std.log.scoped(.link_relocs);
846859
847const Allocator = std.mem.Allocator;860const Allocator = std.mem.Allocator;
848const Atom = @This();861const Atom = @This();
849const Elf = @import("../Elf.zig");862const Elf = @import("../Elf.zig");
863const Fde = eh_frame.Fde;
850const File = @import("file.zig").File;864const File = @import("file.zig").File;
865const Object = @import("Object.zig");
851const Symbol = @import("Symbol.zig");866const Symbol = @import("Symbol.zig");
src/link/Elf/Object.zig+72-34
...@@ -4,7 +4,7 @@ data: []const u8,...@@ -4,7 +4,7 @@ data: []const u8,
4index: File.Index,4index: File.Index,
55
6header: ?elf.Elf64_Ehdr = null,6header: ?elf.Elf64_Ehdr = null,
7shdrs: std.ArrayListUnmanaged(elf.Elf64_Shdr) = .{},7shdrs: std.ArrayListUnmanaged(ElfShdr) = .{},
8strings: StringTable(.object_strings) = .{},8strings: StringTable(.object_strings) = .{},
9symtab: []align(1) const elf.Elf64_Sym = &[0]elf.Elf64_Sym{},9symtab: []align(1) const elf.Elf64_Sym = &[0]elf.Elf64_Sym{},
10strtab: []const u8 = &[0]u8{},10strtab: []const u8 = &[0]u8{},
...@@ -64,8 +64,13 @@ pub fn parse(self: *Object, elf_file: *Elf) !void {...@@ -64,8 +64,13 @@ pub fn parse(self: *Object, elf_file: *Elf) !void {
64 [*]align(1) const elf.Elf64_Shdr,64 [*]align(1) const elf.Elf64_Shdr,
65 @ptrCast(self.data.ptr + shoff),65 @ptrCast(self.data.ptr + shoff),
66 )[0..self.header.?.e_shnum];66 )[0..self.header.?.e_shnum];
67 try self.shdrs.appendUnalignedSlice(gpa, shdrs);67 try self.shdrs.ensureTotalCapacityPrecise(gpa, shdrs.len);
68 try self.strings.buffer.appendSlice(gpa, try self.shdrContents(self.header.?.e_shstrndx));68
69 for (shdrs) |shdr| {
70 self.shdrs.appendAssumeCapacity(try ElfShdr.fromElf64Shdr(shdr));
71 }
72
73 try self.strings.buffer.appendSlice(gpa, self.shdrContents(self.header.?.e_shstrndx));
6974
70 const symtab_index = for (self.shdrs.items, 0..) |shdr, i| switch (shdr.sh_type) {75 const symtab_index = for (self.shdrs.items, 0..) |shdr, i| switch (shdr.sh_type) {
71 elf.SHT_SYMTAB => break @as(u16, @intCast(i)),76 elf.SHT_SYMTAB => break @as(u16, @intCast(i)),
...@@ -76,21 +81,21 @@ pub fn parse(self: *Object, elf_file: *Elf) !void {...@@ -76,21 +81,21 @@ pub fn parse(self: *Object, elf_file: *Elf) !void {
76 const shdr = shdrs[index];81 const shdr = shdrs[index];
77 self.first_global = shdr.sh_info;82 self.first_global = shdr.sh_info;
7883
79 const symtab = try self.shdrContents(index);84 const symtab = self.shdrContents(index);
80 const nsyms = @divExact(symtab.len, @sizeOf(elf.Elf64_Sym));85 const nsyms = @divExact(symtab.len, @sizeOf(elf.Elf64_Sym));
81 self.symtab = @as([*]align(1) const elf.Elf64_Sym, @ptrCast(symtab.ptr))[0..nsyms];86 self.symtab = @as([*]align(1) const elf.Elf64_Sym, @ptrCast(symtab.ptr))[0..nsyms];
82 self.strtab = try self.shdrContents(@as(u16, @intCast(shdr.sh_link)));87 self.strtab = self.shdrContents(@as(u16, @intCast(shdr.sh_link)));
83 }88 }
8489
85 try self.initAtoms(elf_file);90 try self.initAtoms(elf_file);
86 try self.initSymtab(elf_file);91 try self.initSymtab(elf_file);
8792
88 // for (self.shdrs.items, 0..) |shdr, i| {93 for (self.shdrs.items, 0..) |shdr, i| {
89 // const atom = elf_file.atom(self.atoms.items[i]) orelse continue;94 const atom = elf_file.atom(self.atoms.items[i]) orelse continue;
90 // if (!atom.alive) continue;95 if (!atom.flags.alive) continue;
91 // if (shdr.sh_type == elf.SHT_X86_64_UNWIND or mem.eql(u8, atom.name(elf_file), ".eh_frame"))96 if (shdr.sh_type == elf.SHT_X86_64_UNWIND or mem.eql(u8, atom.name(elf_file), ".eh_frame"))
92 // try self.parseEhFrame(@as(u16, @intCast(i)), elf_file);97 try self.parseEhFrame(@as(u16, @intCast(i)), elf_file);
93 // }98 }
94}99}
95100
96fn initAtoms(self: *Object, elf_file: *Elf) !void {101fn initAtoms(self: *Object, elf_file: *Elf) !void {
...@@ -120,7 +125,7 @@ fn initAtoms(self: *Object, elf_file: *Elf) !void {...@@ -120,7 +125,7 @@ fn initAtoms(self: *Object, elf_file: *Elf) !void {
120 };125 };
121126
122 const shndx = @as(u16, @intCast(i));127 const shndx = @as(u16, @intCast(i));
123 const group_raw_data = try self.shdrContents(shndx);128 const group_raw_data = self.shdrContents(shndx);
124 const group_nmembers = @divExact(group_raw_data.len, @sizeOf(u32));129 const group_nmembers = @divExact(group_raw_data.len, @sizeOf(u32));
125 const group_members = @as([*]align(1) const u32, @ptrCast(group_raw_data.ptr))[0..group_nmembers];130 const group_members = @as([*]align(1) const u32, @ptrCast(group_raw_data.ptr))[0..group_nmembers];
126131
...@@ -173,11 +178,11 @@ fn initAtoms(self: *Object, elf_file: *Elf) !void {...@@ -173,11 +178,11 @@ fn initAtoms(self: *Object, elf_file: *Elf) !void {
173178
174fn addAtom(179fn addAtom(
175 self: *Object,180 self: *Object,
176 shdr: elf.Elf64_Shdr,181 shdr: ElfShdr,
177 shndx: u16,182 shndx: u16,
178 name: [:0]const u8,183 name: [:0]const u8,
179 elf_file: *Elf,184 elf_file: *Elf,
180) error{ OutOfMemory, Overflow }!void {185) error{OutOfMemory}!void {
181 const atom_index = try elf_file.addAtom();186 const atom_index = try elf_file.addAtom();
182 const atom = elf_file.atom(atom_index).?;187 const atom = elf_file.atom(atom_index).?;
183 atom.atom_index = atom_index;188 atom.atom_index = atom_index;
...@@ -188,7 +193,7 @@ fn addAtom(...@@ -188,7 +193,7 @@ fn addAtom(
188 self.atoms.items[shndx] = atom_index;193 self.atoms.items[shndx] = atom_index;
189194
190 if (shdr.sh_flags & elf.SHF_COMPRESSED != 0) {195 if (shdr.sh_flags & elf.SHF_COMPRESSED != 0) {
191 const data = try self.shdrContents(shndx);196 const data = self.shdrContents(shndx);
192 const chdr = @as(*align(1) const elf.Elf64_Chdr, @ptrCast(data.ptr)).*;197 const chdr = @as(*align(1) const elf.Elf64_Chdr, @ptrCast(data.ptr)).*;
193 atom.size = chdr.ch_size;198 atom.size = chdr.ch_size;
194 atom.alignment = Alignment.fromNonzeroByteUnits(chdr.ch_addralign);199 atom.alignment = Alignment.fromNonzeroByteUnits(chdr.ch_addralign);
...@@ -198,7 +203,7 @@ fn addAtom(...@@ -198,7 +203,7 @@ fn addAtom(
198 }203 }
199}204}
200205
201fn initOutputSection(self: Object, elf_file: *Elf, shdr: elf.Elf64_Shdr) error{OutOfMemory}!u16 {206fn initOutputSection(self: Object, elf_file: *Elf, shdr: ElfShdr) error{OutOfMemory}!u16 {
202 const name = blk: {207 const name = blk: {
203 const name = self.strings.getAssumeExists(shdr.sh_name);208 const name = self.strings.getAssumeExists(shdr.sh_name);
204 if (shdr.sh_flags & elf.SHF_MERGE != 0) break :blk name;209 if (shdr.sh_flags & elf.SHF_MERGE != 0) break :blk name;
...@@ -244,7 +249,6 @@ fn initOutputSection(self: Object, elf_file: *Elf, shdr: elf.Elf64_Shdr) error{O...@@ -244,7 +249,6 @@ fn initOutputSection(self: Object, elf_file: *Elf, shdr: elf.Elf64_Shdr) error{O
244}249}
245250
246fn skipShdr(self: *Object, index: u16, elf_file: *Elf) bool {251fn skipShdr(self: *Object, index: u16, elf_file: *Elf) bool {
247 _ = elf_file;
248 const shdr = self.shdrs.items[index];252 const shdr = self.shdrs.items[index];
249 const name = self.strings.getAssumeExists(shdr.sh_name);253 const name = self.strings.getAssumeExists(shdr.sh_name);
250 const ignore = blk: {254 const ignore = blk: {
...@@ -252,9 +256,8 @@ fn skipShdr(self: *Object, index: u16, elf_file: *Elf) bool {...@@ -252,9 +256,8 @@ fn skipShdr(self: *Object, index: u16, elf_file: *Elf) bool {
252 if (mem.startsWith(u8, name, ".comment")) break :blk true;256 if (mem.startsWith(u8, name, ".comment")) break :blk true;
253 if (mem.startsWith(u8, name, ".llvm_addrsig")) break :blk true;257 if (mem.startsWith(u8, name, ".llvm_addrsig")) break :blk true;
254 if (mem.startsWith(u8, name, ".eh_frame")) break :blk true;258 if (mem.startsWith(u8, name, ".eh_frame")) break :blk true;
255 // if (elf_file.base.options.strip and shdr.sh_flags & elf.SHF_ALLOC == 0 and259 if (elf_file.base.options.strip and shdr.sh_flags & elf.SHF_ALLOC == 0 and
256 // mem.startsWith(u8, name, ".debug")) break :blk true;260 mem.startsWith(u8, name, ".debug")) break :blk true;
257 if (shdr.sh_flags & elf.SHF_ALLOC == 0 and mem.startsWith(u8, name, ".debug")) break :blk true;
258 break :blk false;261 break :blk false;
259 };262 };
260 return ignore;263 return ignore;
...@@ -303,8 +306,8 @@ fn parseEhFrame(self: *Object, shndx: u16, elf_file: *Elf) !void {...@@ -303,8 +306,8 @@ fn parseEhFrame(self: *Object, shndx: u16, elf_file: *Elf) !void {
303 };306 };
304307
305 const gpa = elf_file.base.allocator;308 const gpa = elf_file.base.allocator;
306 const raw = try self.shdrContents(shndx);309 const raw = self.shdrContents(shndx);
307 const relocs = try self.getRelocs(relocs_shndx);310 const relocs = self.getRelocs(relocs_shndx);
308 const fdes_start = self.fdes.items.len;311 const fdes_start = self.fdes.items.len;
309 const cies_start = self.cies.items.len;312 const cies_start = self.cies.items.len;
310313
...@@ -408,7 +411,7 @@ pub fn scanRelocs(self: *Object, elf_file: *Elf, undefs: anytype) !void {...@@ -408,7 +411,7 @@ pub fn scanRelocs(self: *Object, elf_file: *Elf, undefs: anytype) !void {
408 const shdr = atom.inputShdr(elf_file);411 const shdr = atom.inputShdr(elf_file);
409 if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue;412 if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue;
410 if (shdr.sh_type == elf.SHT_NOBITS) continue;413 if (shdr.sh_type == elf.SHT_NOBITS) continue;
411 if (try atom.scanRelocsRequiresCode(elf_file)) {414 if (atom.scanRelocsRequiresCode(elf_file)) {
412 // TODO ideally, we don't have to decompress at this stage (should already be done)415 // TODO ideally, we don't have to decompress at this stage (should already be done)
413 // and we just fetch the code slice.416 // and we just fetch the code slice.
414 const code = try self.codeDecompressAlloc(elf_file, atom_index);417 const code = try self.codeDecompressAlloc(elf_file, atom_index);
...@@ -418,7 +421,7 @@ pub fn scanRelocs(self: *Object, elf_file: *Elf, undefs: anytype) !void {...@@ -418,7 +421,7 @@ pub fn scanRelocs(self: *Object, elf_file: *Elf, undefs: anytype) !void {
418 }421 }
419422
420 for (self.cies.items) |cie| {423 for (self.cies.items) |cie| {
421 for (try cie.relocs(elf_file)) |rel| {424 for (cie.relocs(elf_file)) |rel| {
422 const sym = elf_file.symbol(self.symbols.items[rel.r_sym()]);425 const sym = elf_file.symbol(self.symbols.items[rel.r_sym()]);
423 if (sym.flags.import) {426 if (sym.flags.import) {
424 if (sym.type(elf_file) != elf.STT_FUNC)427 if (sym.type(elf_file) != elf.STT_FUNC)
...@@ -518,6 +521,15 @@ pub fn markLive(self: *Object, elf_file: *Elf) void {...@@ -518,6 +521,15 @@ pub fn markLive(self: *Object, elf_file: *Elf) void {
518 }521 }
519}522}
520523
524pub fn markEhFrameAtomsDead(self: Object, elf_file: *Elf) void {
525 for (self.atoms.items) |atom_index| {
526 const atom = elf_file.atom(atom_index) orelse continue;
527 const is_eh_frame = atom.inputShdr(elf_file).sh_type == elf.SHT_X86_64_UNWIND or
528 mem.eql(u8, atom.name(elf_file), ".eh_frame");
529 if (atom.flags.alive and is_eh_frame) atom.flags.alive = false;
530 }
531}
532
521pub fn checkDuplicates(self: *Object, elf_file: *Elf) void {533pub fn checkDuplicates(self: *Object, elf_file: *Elf) void {
522 const first_global = self.first_global orelse return;534 const first_global = self.first_global orelse return;
523 for (self.globals(), 0..) |index, i| {535 for (self.globals(), 0..) |index, i| {
...@@ -747,12 +759,10 @@ pub fn globals(self: Object) []const Symbol.Index {...@@ -747,12 +759,10 @@ pub fn globals(self: Object) []const Symbol.Index {
747 return self.symbols.items[start..];759 return self.symbols.items[start..];
748}760}
749761
750fn shdrContents(self: Object, index: u32) error{Overflow}![]const u8 {762pub fn shdrContents(self: Object, index: u32) []const u8 {
751 assert(index < self.shdrs.items.len);763 assert(index < self.shdrs.items.len);
752 const shdr = self.shdrs.items[index];764 const shdr = self.shdrs.items[index];
753 const offset = math.cast(usize, shdr.sh_offset) orelse return error.Overflow;765 return self.data[shdr.sh_offset..][0..shdr.sh_size];
754 const size = math.cast(usize, shdr.sh_size) orelse return error.Overflow;
755 return self.data[offset..][0..size];
756}766}
757767
758/// Returns atom's code and optionally uncompresses data if required (for compressed sections).768/// Returns atom's code and optionally uncompresses data if required (for compressed sections).
...@@ -761,7 +771,7 @@ pub fn codeDecompressAlloc(self: Object, elf_file: *Elf, atom_index: Atom.Index)...@@ -761,7 +771,7 @@ pub fn codeDecompressAlloc(self: Object, elf_file: *Elf, atom_index: Atom.Index)
761 const gpa = elf_file.base.allocator;771 const gpa = elf_file.base.allocator;
762 const atom_ptr = elf_file.atom(atom_index).?;772 const atom_ptr = elf_file.atom(atom_index).?;
763 assert(atom_ptr.file_index == self.index);773 assert(atom_ptr.file_index == self.index);
764 const data = try self.shdrContents(atom_ptr.input_section_index);774 const data = self.shdrContents(atom_ptr.input_section_index);
765 const shdr = atom_ptr.inputShdr(elf_file);775 const shdr = atom_ptr.inputShdr(elf_file);
766 if (shdr.sh_flags & elf.SHF_COMPRESSED != 0) {776 if (shdr.sh_flags & elf.SHF_COMPRESSED != 0) {
767 const chdr = @as(*align(1) const elf.Elf64_Chdr, @ptrCast(data.ptr)).*;777 const chdr = @as(*align(1) const elf.Elf64_Chdr, @ptrCast(data.ptr)).*;
...@@ -789,8 +799,8 @@ fn getString(self: *Object, off: u32) [:0]const u8 {...@@ -789,8 +799,8 @@ fn getString(self: *Object, off: u32) [:0]const u8 {
789 return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.strtab.ptr + off)), 0);799 return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.strtab.ptr + off)), 0);
790}800}
791801
792pub fn comdatGroupMembers(self: *Object, index: u16) error{Overflow}![]align(1) const u32 {802pub fn comdatGroupMembers(self: *Object, index: u16) []align(1) const u32 {
793 const raw = try self.shdrContents(index);803 const raw = self.shdrContents(index);
794 const nmembers = @divExact(raw.len, @sizeOf(u32));804 const nmembers = @divExact(raw.len, @sizeOf(u32));
795 const members = @as([*]align(1) const u32, @ptrCast(raw.ptr))[1..nmembers];805 const members = @as([*]align(1) const u32, @ptrCast(raw.ptr))[1..nmembers];
796 return members;806 return members;
...@@ -800,8 +810,8 @@ pub fn asFile(self: *Object) File {...@@ -800,8 +810,8 @@ pub fn asFile(self: *Object) File {
800 return .{ .object = self };810 return .{ .object = self };
801}811}
802812
803pub fn getRelocs(self: *Object, shndx: u32) error{Overflow}![]align(1) const elf.Elf64_Rela {813pub fn getRelocs(self: *Object, shndx: u32) []align(1) const elf.Elf64_Rela {
804 const raw = try self.shdrContents(shndx);814 const raw = self.shdrContents(shndx);
805 const num = @divExact(raw.len, @sizeOf(elf.Elf64_Rela));815 const num = @divExact(raw.len, @sizeOf(elf.Elf64_Rela));
806 return @as([*]align(1) const elf.Elf64_Rela, @ptrCast(raw.ptr))[0..num];816 return @as([*]align(1) const elf.Elf64_Rela, @ptrCast(raw.ptr))[0..num];
807}817}
...@@ -941,7 +951,7 @@ fn formatComdatGroups(...@@ -941,7 +951,7 @@ fn formatComdatGroups(
941 const cg = elf_file.comdatGroup(cg_index);951 const cg = elf_file.comdatGroup(cg_index);
942 const cg_owner = elf_file.comdatGroupOwner(cg.owner);952 const cg_owner = elf_file.comdatGroupOwner(cg.owner);
943 if (cg_owner.file != object.index) continue;953 if (cg_owner.file != object.index) continue;
944 const cg_members = object.comdatGroupMembers(cg.shndx) catch continue;954 const cg_members = object.comdatGroupMembers(cg.shndx);
945 for (cg_members) |shndx| {955 for (cg_members) |shndx| {
946 const atom_index = object.atoms.items[shndx];956 const atom_index = object.atoms.items[shndx];
947 const atom = elf_file.atom(atom_index) orelse continue;957 const atom = elf_file.atom(atom_index) orelse continue;
...@@ -970,6 +980,34 @@ fn formatPath(...@@ -970,6 +980,34 @@ fn formatPath(
970 } else try writer.writeAll(object.path);980 } else try writer.writeAll(object.path);
971}981}
972982
983pub const ElfShdr = struct {
984 sh_name: u32,
985 sh_type: u32,
986 sh_flags: u64,
987 sh_addr: u64,
988 sh_offset: usize,
989 sh_size: usize,
990 sh_link: u32,
991 sh_info: u32,
992 sh_addralign: u64,
993 sh_entsize: u64,
994
995 fn fromElf64Shdr(shdr: elf.Elf64_Shdr) error{Overflow}!ElfShdr {
996 return .{
997 .sh_name = shdr.sh_name,
998 .sh_type = shdr.sh_type,
999 .sh_flags = shdr.sh_flags,
1000 .sh_addr = shdr.sh_addr,
1001 .sh_offset = math.cast(usize, shdr.sh_offset) orelse return error.Overflow,
1002 .sh_size = math.cast(usize, shdr.sh_size) orelse return error.Overflow,
1003 .sh_link = shdr.sh_link,
1004 .sh_info = shdr.sh_info,
1005 .sh_addralign = shdr.sh_addralign,
1006 .sh_entsize = shdr.sh_entsize,
1007 };
1008 }
1009};
1010
973const Object = @This();1011const Object = @This();
9741012
975const std = @import("std");1013const std = @import("std");
src/link/Elf/ZigModule.zig+1-1
...@@ -145,7 +145,7 @@ pub fn scanRelocs(self: *ZigModule, elf_file: *Elf, undefs: anytype) !void {...@@ -145,7 +145,7 @@ pub fn scanRelocs(self: *ZigModule, elf_file: *Elf, undefs: anytype) !void {
145 for (self.atoms.items) |atom_index| {145 for (self.atoms.items) |atom_index| {
146 const atom = elf_file.atom(atom_index) orelse continue;146 const atom = elf_file.atom(atom_index) orelse continue;
147 if (!atom.flags.alive) continue;147 if (!atom.flags.alive) continue;
148 if (try atom.scanRelocsRequiresCode(elf_file)) {148 if (atom.scanRelocsRequiresCode(elf_file)) {
149 // TODO ideally we don't have to fetch the code here.149 // TODO ideally we don't have to fetch the code here.
150 // Perhaps it would make sense to save the code until flushModule where we150 // Perhaps it would make sense to save the code until flushModule where we
151 // would free all of generated code?151 // would free all of generated code?
src/link/Elf/eh_frame.zig+24-26
...@@ -20,9 +20,9 @@ pub const Fde = struct {...@@ -20,9 +20,9 @@ pub const Fde = struct {
20 return base + fde.out_offset;20 return base + fde.out_offset;
21 }21 }
2222
23 pub fn data(fde: Fde, elf_file: *Elf) error{Overflow}![]const u8 {23 pub fn data(fde: Fde, elf_file: *Elf) []const u8 {
24 const object = elf_file.file(fde.file_index).?.object;24 const object = elf_file.file(fde.file_index).?.object;
25 const contents = try object.shdrContents(fde.input_section_index);25 const contents = object.shdrContents(fde.input_section_index);
26 return contents[fde.offset..][0..fde.calcSize()];26 return contents[fde.offset..][0..fde.calcSize()];
27 }27 }
2828
...@@ -32,24 +32,25 @@ pub const Fde = struct {...@@ -32,24 +32,25 @@ pub const Fde = struct {
32 }32 }
3333
34 pub fn ciePointer(fde: Fde, elf_file: *Elf) u32 {34 pub fn ciePointer(fde: Fde, elf_file: *Elf) u32 {
35 return std.mem.readIntLittle(u32, fde.data(elf_file)[4..8]);35 const fde_data = fde.data(elf_file);
36 return std.mem.readIntLittle(u32, fde_data[4..8]);
36 }37 }
3738
38 pub fn calcSize(fde: Fde) u64 {39 pub fn calcSize(fde: Fde) u64 {
39 return fde.size + 4;40 return fde.size + 4;
40 }41 }
4142
42 pub fn atom(fde: Fde, elf_file: *Elf) error{Overflow}!*Atom {43 pub fn atom(fde: Fde, elf_file: *Elf) *Atom {
43 const object = elf_file.file(fde.file_index).?.object;44 const object = elf_file.file(fde.file_index).?.object;
44 const rel = (try fde.relocs(elf_file))[0];45 const rel = fde.relocs(elf_file)[0];
45 const sym = object.symtab[rel.r_sym()];46 const sym = object.symtab[rel.r_sym()];
46 const atom_index = object.atoms.items[sym.st_shndx];47 const atom_index = object.atoms.items[sym.st_shndx];
47 return elf_file.atom(atom_index).?;48 return elf_file.atom(atom_index).?;
48 }49 }
4950
50 pub fn relocs(fde: Fde, elf_file: *Elf) error{Overflow}![]align(1) const elf.Elf64_Rela {51 pub fn relocs(fde: Fde, elf_file: *Elf) []align(1) const elf.Elf64_Rela {
51 const object = elf_file.file(fde.file_index).?.object;52 const object = elf_file.file(fde.file_index).?.object;
52 return (try object.getRelocs(fde.rel_section_index))[fde.rel_index..][0..fde.rel_num];53 return object.getRelocs(fde.rel_section_index)[fde.rel_index..][0..fde.rel_num];
53 }54 }
5455
55 pub fn format(56 pub fn format(
...@@ -88,10 +89,7 @@ pub const Fde = struct {...@@ -88,10 +89,7 @@ pub const Fde = struct {
88 const fde = ctx.fde;89 const fde = ctx.fde;
89 const elf_file = ctx.elf_file;90 const elf_file = ctx.elf_file;
90 const base_addr = fde.address(elf_file);91 const base_addr = fde.address(elf_file);
91 const atom_name = if (fde.atom(elf_file)) |atom_ptr|92 const atom_name = fde.atom(elf_file).name(elf_file);
92 atom_ptr.name(elf_file)
93 else |_|
94 "";
95 try writer.print("@{x} : size({x}) : cie({d}) : {s}", .{93 try writer.print("@{x} : size({x}) : cie({d}) : {s}", .{
96 base_addr + fde.out_offset,94 base_addr + fde.out_offset,
97 fde.calcSize(),95 fde.calcSize(),
...@@ -123,9 +121,9 @@ pub const Cie = struct {...@@ -123,9 +121,9 @@ pub const Cie = struct {
123 return base + cie.out_offset;121 return base + cie.out_offset;
124 }122 }
125123
126 pub fn data(cie: Cie, elf_file: *Elf) error{Overflow}![]const u8 {124 pub fn data(cie: Cie, elf_file: *Elf) []const u8 {
127 const object = elf_file.file(cie.file_index).?.object;125 const object = elf_file.file(cie.file_index).?.object;
128 const contents = try object.shdrContents(cie.input_section_index);126 const contents = object.shdrContents(cie.input_section_index);
129 return contents[cie.offset..][0..cie.calcSize()];127 return contents[cie.offset..][0..cie.calcSize()];
130 }128 }
131129
...@@ -133,16 +131,16 @@ pub const Cie = struct {...@@ -133,16 +131,16 @@ pub const Cie = struct {
133 return cie.size + 4;131 return cie.size + 4;
134 }132 }
135133
136 pub fn relocs(cie: Cie, elf_file: *Elf) error{Overflow}![]align(1) const elf.Elf64_Rela {134 pub fn relocs(cie: Cie, elf_file: *Elf) []align(1) const elf.Elf64_Rela {
137 const object = elf_file.file(cie.file_index).?.object;135 const object = elf_file.file(cie.file_index).?.object;
138 return (try object.getRelocs(cie.rel_section_index))[cie.rel_index..][0..cie.rel_num];136 return object.getRelocs(cie.rel_section_index)[cie.rel_index..][0..cie.rel_num];
139 }137 }
140138
141 pub fn eql(cie: Cie, other: Cie, elf_file: *Elf) error{Overflow}!bool {139 pub fn eql(cie: Cie, other: Cie, elf_file: *Elf) bool {
142 if (!std.mem.eql(u8, try cie.data(elf_file), try other.data(elf_file))) return false;140 if (!std.mem.eql(u8, cie.data(elf_file), other.data(elf_file))) return false;
143141
144 const cie_relocs = try cie.relocs(elf_file);142 const cie_relocs = cie.relocs(elf_file);
145 const other_relocs = try other.relocs(elf_file);143 const other_relocs = other.relocs(elf_file);
146 if (cie_relocs.len != other_relocs.len) return false;144 if (cie_relocs.len != other_relocs.len) return false;
147145
148 for (cie_relocs, other_relocs) |cie_rel, other_rel| {146 for (cie_relocs, other_relocs) |cie_rel, other_rel| {
...@@ -152,8 +150,8 @@ pub const Cie = struct {...@@ -152,8 +150,8 @@ pub const Cie = struct {
152150
153 const cie_object = elf_file.file(cie.file_index).?.object;151 const cie_object = elf_file.file(cie.file_index).?.object;
154 const other_object = elf_file.file(other.file_index).?.object;152 const other_object = elf_file.file(other.file_index).?.object;
155 const cie_sym = cie_object.symbol(cie_rel.r_sym(), elf_file);153 const cie_sym = cie_object.symbols.items[cie_rel.r_sym()];
156 const other_sym = other_object.symbol(other_rel.r_sym(), elf_file);154 const other_sym = other_object.symbols.items[other_rel.r_sym()];
157 if (!std.mem.eql(u8, std.mem.asBytes(&cie_sym), std.mem.asBytes(&other_sym))) return false;155 if (!std.mem.eql(u8, std.mem.asBytes(&cie_sym), std.mem.asBytes(&other_sym))) return false;
158 }156 }
159 return true;157 return true;
...@@ -319,10 +317,10 @@ pub fn writeEhFrame(elf_file: *Elf, writer: anytype) !void {...@@ -319,10 +317,10 @@ pub fn writeEhFrame(elf_file: *Elf, writer: anytype) !void {
319 for (object.cies.items) |cie| {317 for (object.cies.items) |cie| {
320 if (!cie.alive) continue;318 if (!cie.alive) continue;
321319
322 const contents = try gpa.dupe(u8, try cie.data(elf_file));320 const contents = try gpa.dupe(u8, cie.data(elf_file));
323 defer gpa.free(contents);321 defer gpa.free(contents);
324322
325 for (try cie.relocs(elf_file)) |rel| {323 for (cie.relocs(elf_file)) |rel| {
326 const sym = object.symbol(rel.r_sym(), elf_file);324 const sym = object.symbol(rel.r_sym(), elf_file);
327 try resolveReloc(cie, sym, rel, elf_file, contents);325 try resolveReloc(cie, sym, rel, elf_file, contents);
328 }326 }
...@@ -337,7 +335,7 @@ pub fn writeEhFrame(elf_file: *Elf, writer: anytype) !void {...@@ -337,7 +335,7 @@ pub fn writeEhFrame(elf_file: *Elf, writer: anytype) !void {
337 for (object.fdes.items) |fde| {335 for (object.fdes.items) |fde| {
338 if (!fde.alive) continue;336 if (!fde.alive) continue;
339337
340 const contents = try gpa.dupe(u8, try fde.data(elf_file));338 const contents = try gpa.dupe(u8, fde.data(elf_file));
341 defer gpa.free(contents);339 defer gpa.free(contents);
342340
343 std.mem.writeIntLittle(341 std.mem.writeIntLittle(
...@@ -346,7 +344,7 @@ pub fn writeEhFrame(elf_file: *Elf, writer: anytype) !void {...@@ -346,7 +344,7 @@ pub fn writeEhFrame(elf_file: *Elf, writer: anytype) !void {
346 @as(i32, @truncate(@as(i64, @intCast(fde.out_offset + 4)) - @as(i64, @intCast(fde.cie(elf_file).out_offset)))),344 @as(i32, @truncate(@as(i64, @intCast(fde.out_offset + 4)) - @as(i64, @intCast(fde.cie(elf_file).out_offset)))),
347 );345 );
348346
349 for (try fde.relocs(elf_file)) |rel| {347 for (fde.relocs(elf_file)) |rel| {
350 const sym = object.symbol(rel.r_sym(), elf_file);348 const sym = object.symbol(rel.r_sym(), elf_file);
351 try resolveReloc(fde, sym, rel, elf_file, contents);349 try resolveReloc(fde, sym, rel, elf_file, contents);
352 }350 }
...@@ -395,7 +393,7 @@ pub fn writeEhFrameHdr(elf_file: *Elf, writer: anytype) !void {...@@ -395,7 +393,7 @@ pub fn writeEhFrameHdr(elf_file: *Elf, writer: anytype) !void {
395 for (object.fdes.items) |fde| {393 for (object.fdes.items) |fde| {
396 if (!fde.alive) continue;394 if (!fde.alive) continue;
397395
398 const relocs = try fde.relocs(elf_file);396 const relocs = fde.relocs(elf_file);
399 assert(relocs.len > 0); // Should this be an error? Things are completely broken anyhow if this trips...397 assert(relocs.len > 0); // Should this be an error? Things are completely broken anyhow if this trips...
400 const rel = relocs[0];398 const rel = relocs[0];
401 const sym = object.symbol(rel.r_sym(), elf_file);399 const sym = object.symbol(rel.r_sym(), elf_file);