authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-10-16 18:48:43-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-10-23 16:27:38-07:00
log2dcfa723767d284cef5eb180be7c080583ddbe25
tree43056d154bda710c6478f5a13688e712e636b633
parentb510c5719f3cfd55ee70da5a1005396d28dd1c1d

link.Elf: untangle parseObject and parseArchive

from link.Elf, so that they can be used earlier in the pipeline

7 files changed, 363 insertions(+), 289 deletions(-)

src/link/Elf.zig+46-67
......@@ -1398,8 +1398,15 @@ fn parseObject(self: *Elf, obj: link.Input.Object) ParseError!void {
13981398 defer tracy.end();
13991399
14001400 const gpa = self.base.comp.gpa;
1401 const diags = &self.base.comp.link_diags;
1402 const first_eflags = &self.first_eflags;
1403 const target = self.base.comp.root_mod.resolved_target.result;
1404 const debug_fmt_strip = self.base.comp.config.debug_format == .strip;
1405 const default_sym_version = self.default_sym_version;
1406 const file_handles = &self.file_handles;
1407
14011408 const handle = obj.file;
1402 const fh = try self.addFileHandle(handle);
1409 const fh = try addFileHandle(gpa, file_handles, handle);
14031410
14041411 const index: File.Index = @intCast(try self.files.addOne(gpa));
14051412 self.files.set(index, .{ .object = .{
......@@ -1413,7 +1420,7 @@ fn parseObject(self: *Elf, obj: link.Input.Object) ParseError!void {
14131420 try self.objects.append(gpa, index);
14141421
14151422 const object = self.file(index).?.object;
1416 try object.parse(self);
1423 try object.parse(gpa, diags, obj.path, handle, first_eflags, target, debug_fmt_strip, default_sym_version);
14171424}
14181425
14191426pub fn openParseArchiveReportingFailure(self: *Elf, path: Path) void {
......@@ -1427,36 +1434,49 @@ pub fn openParseArchiveReportingFailure(self: *Elf, path: Path) void {
14271434}
14281435
14291436pub fn parseArchiveReportingFailure(self: *Elf, obj: link.Input.Object) void {
1437 const gpa = self.base.comp.gpa;
14301438 const diags = &self.base.comp.link_diags;
1431 self.parseArchive(obj) catch |err| switch (err) {
1439 const first_eflags = &self.first_eflags;
1440 const target = self.base.comp.root_mod.resolved_target.result;
1441 const debug_fmt_strip = self.base.comp.config.debug_format == .strip;
1442 const default_sym_version = self.default_sym_version;
1443 const file_handles = &self.file_handles;
1444 const files = &self.files;
1445 const objects = &self.objects;
1446
1447 parseArchive(gpa, diags, file_handles, files, first_eflags, target, debug_fmt_strip, default_sym_version, objects, obj) catch |err| switch (err) {
14321448 error.LinkFailure => return, // already reported
14331449 else => |e| diags.addParseError(obj.path, "failed to parse archive: {s}", .{@errorName(e)}),
14341450 };
14351451}
14361452
1437fn parseArchive(self: *Elf, obj: link.Input.Object) ParseError!void {
1453fn parseArchive(
1454 gpa: Allocator,
1455 diags: *Diags,
1456 file_handles: *std.ArrayListUnmanaged(File.Handle),
1457 files: *std.MultiArrayList(File.Entry),
1458 first_eflags: *?elf.Word,
1459 target: std.Target,
1460 debug_fmt_strip: bool,
1461 default_sym_version: elf.Versym,
1462 objects: *std.ArrayListUnmanaged(File.Index),
1463 obj: link.Input.Object,
1464) ParseError!void {
14381465 const tracy = trace(@src());
14391466 defer tracy.end();
14401467
1441 const gpa = self.base.comp.gpa;
1442 const handle = obj.file;
1443 const fh = try self.addFileHandle(handle);
1444
1445 var archive: Archive = .{};
1468 const fh = try addFileHandle(gpa, file_handles, obj.file);
1469 var archive = try Archive.parse(gpa, diags, file_handles, obj.path, fh);
14461470 defer archive.deinit(gpa);
1447 try archive.parse(self, obj.path, fh);
1448
1449 const objects = try archive.objects.toOwnedSlice(gpa);
1450 defer gpa.free(objects);
14511471
1452 for (objects) |extracted| {
1453 const index: File.Index = @intCast(try self.files.addOne(gpa));
1454 self.files.set(index, .{ .object = extracted });
1455 const object = &self.files.items(.data)[index].object;
1472 for (archive.objects) |extracted| {
1473 const index: File.Index = @intCast(try files.addOne(gpa));
1474 files.set(index, .{ .object = extracted });
1475 const object = &files.items(.data)[index].object;
14561476 object.index = index;
14571477 object.alive = obj.must_link;
1458 try object.parse(self);
1459 try self.objects.append(gpa, index);
1478 try object.parse(gpa, diags, obj.path, obj.file, first_eflags, target, debug_fmt_strip, default_sym_version);
1479 try objects.append(gpa, index);
14601480 }
14611481}
14621482
......@@ -1565,46 +1585,6 @@ fn parseDso(
15651585 }
15661586}
15671587
1568pub fn validateEFlags(self: *Elf, file_index: File.Index, e_flags: elf.Word) !void {
1569 if (self.first_eflags == null) {
1570 self.first_eflags = e_flags;
1571 return; // there isn't anything to conflict with yet
1572 }
1573 const self_eflags: *elf.Word = &self.first_eflags.?;
1574
1575 switch (self.getTarget().cpu.arch) {
1576 .riscv64 => {
1577 if (e_flags != self_eflags.*) {
1578 const riscv_eflags: riscv.RiscvEflags = @bitCast(e_flags);
1579 const self_riscv_eflags: *riscv.RiscvEflags = @ptrCast(self_eflags);
1580
1581 self_riscv_eflags.rvc = self_riscv_eflags.rvc or riscv_eflags.rvc;
1582 self_riscv_eflags.tso = self_riscv_eflags.tso or riscv_eflags.tso;
1583
1584 var any_errors: bool = false;
1585 if (self_riscv_eflags.fabi != riscv_eflags.fabi) {
1586 any_errors = true;
1587 try self.addFileError(
1588 file_index,
1589 "cannot link object files with different float-point ABIs",
1590 .{},
1591 );
1592 }
1593 if (self_riscv_eflags.rve != riscv_eflags.rve) {
1594 any_errors = true;
1595 try self.addFileError(
1596 file_index,
1597 "cannot link object files with different RVEs",
1598 .{},
1599 );
1600 }
1601 if (any_errors) return error.LinkFailure;
1602 }
1603 },
1604 else => {},
1605 }
1606}
1607
16081588/// When resolving symbols, we approach the problem similarly to `mold`.
16091589/// 1. Resolve symbols across all objects (including those preemptively extracted archives).
16101590/// 2. Resolve symbols across all shared objects.
......@@ -4704,16 +4684,16 @@ fn fileLookup(files: std.MultiArrayList(File.Entry), index: File.Index) ?File {
47044684 };
47054685}
47064686
4707pub fn addFileHandle(self: *Elf, handle: fs.File) !File.HandleIndex {
4708 const gpa = self.base.comp.gpa;
4709 const index: File.HandleIndex = @intCast(self.file_handles.items.len);
4710 const fh = try self.file_handles.addOne(gpa);
4711 fh.* = handle;
4712 return index;
4687pub fn addFileHandle(
4688 gpa: Allocator,
4689 file_handles: *std.ArrayListUnmanaged(File.Handle),
4690 handle: fs.File,
4691) Allocator.Error!File.HandleIndex {
4692 try file_handles.append(gpa, handle);
4693 return @intCast(file_handles.items.len - 1);
47134694}
47144695
47154696pub fn fileHandle(self: Elf, index: File.HandleIndex) File.Handle {
4716 assert(index < self.file_handles.items.len);
47174697 return self.file_handles.items[index];
47184698}
47194699
......@@ -5588,4 +5568,3 @@ const Thunk = @import("Elf/Thunk.zig");
55885568const Value = @import("../Value.zig");
55895569const VerneedSection = synthetic_sections.VerneedSection;
55905570const ZigObject = @import("Elf/ZigObject.zig");
5591const riscv = @import("riscv.zig");
src/link/Elf/Archive.zig+36-20
......@@ -1,18 +1,29 @@
1objects: std.ArrayListUnmanaged(Object) = .empty,
2strtab: std.ArrayListUnmanaged(u8) = .empty,
3
4pub fn deinit(self: *Archive, allocator: Allocator) void {
5 self.objects.deinit(allocator);
6 self.strtab.deinit(allocator);
1objects: []const Object,
2/// '\n'-delimited
3strtab: []const u8,
4
5pub fn deinit(a: *Archive, gpa: Allocator) void {
6 gpa.free(a.objects);
7 gpa.free(a.strtab);
8 a.* = undefined;
79}
810
9pub fn parse(self: *Archive, elf_file: *Elf, path: Path, handle_index: File.HandleIndex) !void {
10 const comp = elf_file.base.comp;
11 const gpa = comp.gpa;
12 const diags = &comp.link_diags;
13 const handle = elf_file.fileHandle(handle_index);
11pub fn parse(
12 gpa: Allocator,
13 diags: *Diags,
14 file_handles: *const std.ArrayListUnmanaged(File.Handle),
15 path: Path,
16 handle_index: File.HandleIndex,
17) !Archive {
18 const handle = file_handles.items[handle_index];
1419 const size = (try handle.stat()).size;
1520
21 var objects: std.ArrayListUnmanaged(Object) = .empty;
22 defer objects.deinit(gpa);
23
24 var strtab: std.ArrayListUnmanaged(u8) = .empty;
25 defer strtab.deinit(gpa);
26
1627 var pos: usize = elf.ARMAG.len;
1728 while (true) {
1829 if (pos >= size) break;
......@@ -37,8 +48,8 @@ pub fn parse(self: *Archive, elf_file: *Elf, path: Path, handle_index: File.Hand
3748
3849 if (hdr.isSymtab() or hdr.isSymtab64()) continue;
3950 if (hdr.isStrtab()) {
40 try self.strtab.resize(gpa, obj_size);
41 const amt = try handle.preadAll(self.strtab.items, pos);
51 try strtab.resize(gpa, obj_size);
52 const amt = try handle.preadAll(strtab.items, pos);
4253 if (amt != obj_size) return error.InputOutput;
4354 continue;
4455 }
......@@ -47,7 +58,7 @@ pub fn parse(self: *Archive, elf_file: *Elf, path: Path, handle_index: File.Hand
4758 const name = if (hdr.name()) |name|
4859 name
4960 else if (try hdr.nameOffset()) |off|
50 self.getString(off)
61 stringTableLookup(strtab.items, off)
5162 else
5263 unreachable;
5364
......@@ -70,14 +81,18 @@ pub fn parse(self: *Archive, elf_file: *Elf, path: Path, handle_index: File.Hand
7081 @as(Path, object.path), @as(Path, path),
7182 });
7283
73 try self.objects.append(gpa, object);
84 try objects.append(gpa, object);
7485 }
86
87 return .{
88 .objects = try objects.toOwnedSlice(gpa),
89 .strtab = try strtab.toOwnedSlice(gpa),
90 };
7591}
7692
77fn getString(self: Archive, off: u32) []const u8 {
78 assert(off < self.strtab.items.len);
79 const name = mem.sliceTo(@as([*:'\n']const u8, @ptrCast(self.strtab.items.ptr + off)), 0);
80 return name[0 .. name.len - 1];
93pub fn stringTableLookup(strtab: []const u8, off: u32) [:'\n']const u8 {
94 const slice = strtab[off..];
95 return slice[0..mem.indexOfScalar(u8, slice, '\n').? :'\n'];
8196}
8297
8398pub fn setArHdr(opts: struct {
......@@ -290,8 +305,9 @@ const fs = std.fs;
290305const log = std.log.scoped(.link);
291306const mem = std.mem;
292307const Path = std.Build.Cache.Path;
308const Allocator = std.mem.Allocator;
293309
294const Allocator = mem.Allocator;
310const Diags = @import("../../link.zig").Diags;
295311const Archive = @This();
296312const Elf = @import("../Elf.zig");
297313const File = @import("file.zig").File;
src/link/Elf/Atom.zig+27-24
......@@ -102,9 +102,13 @@ pub fn relocsShndx(self: Atom) ?u32 {
102102 return self.relocs_section_index;
103103}
104104
105pub fn priority(self: Atom, elf_file: *Elf) u64 {
106 const index = self.file(elf_file).?.index();
107 return (@as(u64, @intCast(index)) << 32) | @as(u64, @intCast(self.input_section_index));
105pub fn priority(atom: Atom, elf_file: *Elf) u64 {
106 const index = atom.file(elf_file).?.index();
107 return priorityLookup(index, atom.input_section_index);
108}
109
110pub fn priorityLookup(file_index: File.Index, input_section_index: u32) u64 {
111 return (@as(u64, @intCast(file_index)) << 32) | @as(u64, @intCast(input_section_index));
108112}
109113
110114/// Returns how much room there is to grow in virtual address space.
......@@ -255,19 +259,13 @@ pub fn writeRelocs(self: Atom, elf_file: *Elf, out_relocs: *std.ArrayList(elf.El
255259 }
256260}
257261
258pub fn fdes(self: Atom, elf_file: *Elf) []Fde {
259 const extras = self.extra(elf_file);
260 return switch (self.file(elf_file).?) {
261 .shared_object => unreachable,
262 .linker_defined, .zig_object => &[0]Fde{},
263 .object => |x| x.fdes.items[extras.fde_start..][0..extras.fde_count],
264 };
262pub fn fdes(atom: Atom, object: *Object) []Fde {
263 const extras = object.atomExtra(atom.extra_index);
264 return object.fdes.items[extras.fde_start..][0..extras.fde_count];
265265}
266266
267pub fn markFdesDead(self: Atom, elf_file: *Elf) void {
268 for (self.fdes(elf_file)) |*fde| {
269 fde.alive = false;
270 }
267pub fn markFdesDead(self: Atom, object: *Object) void {
268 for (self.fdes(object)) |*fde| fde.alive = false;
271269}
272270
273271pub fn addReloc(self: Atom, alloc: Allocator, reloc: elf.Elf64_Rela, zo: *ZigObject) !void {
......@@ -946,16 +944,21 @@ fn format2(
946944 atom.output_section_index, atom.alignment.toByteUnits() orelse 0, atom.size,
947945 atom.prev_atom_ref, atom.next_atom_ref,
948946 });
949 if (atom.fdes(elf_file).len > 0) {
950 try writer.writeAll(" : fdes{ ");
951 const extras = atom.extra(elf_file);
952 for (atom.fdes(elf_file), extras.fde_start..) |fde, i| {
953 try writer.print("{d}", .{i});
954 if (!fde.alive) try writer.writeAll("([*])");
955 if (i - extras.fde_start < extras.fde_count - 1) try writer.writeAll(", ");
956 }
957 try writer.writeAll(" }");
958 }
947 if (atom.file(elf_file)) |atom_file| switch (atom_file) {
948 .object => |object| {
949 if (atom.fdes(object).len > 0) {
950 try writer.writeAll(" : fdes{ ");
951 const extras = atom.extra(elf_file);
952 for (atom.fdes(object), extras.fde_start..) |fde, i| {
953 try writer.print("{d}", .{i});
954 if (!fde.alive) try writer.writeAll("([*])");
955 if (i - extras.fde_start < extras.fde_count - 1) try writer.writeAll(", ");
956 }
957 try writer.writeAll(" }");
958 }
959 },
960 else => {},
961 };
959962 if (!atom.alive) {
960963 try writer.writeAll(" : [*]");
961964 }
src/link/Elf/Object.zig+197-126
......@@ -37,72 +37,87 @@ num_dynrelocs: u32 = 0,
3737output_symtab_ctx: Elf.SymtabCtx = .{},
3838output_ar_state: Archive.ArState = .{},
3939
40pub fn deinit(self: *Object, allocator: Allocator) void {
41 if (self.archive) |*ar| allocator.free(ar.path.sub_path);
42 allocator.free(self.path.sub_path);
43 self.shdrs.deinit(allocator);
44 self.symtab.deinit(allocator);
45 self.strtab.deinit(allocator);
46 self.symbols.deinit(allocator);
47 self.symbols_extra.deinit(allocator);
48 self.symbols_resolver.deinit(allocator);
49 self.atoms.deinit(allocator);
50 self.atoms_indexes.deinit(allocator);
51 self.atoms_extra.deinit(allocator);
52 self.comdat_groups.deinit(allocator);
53 self.comdat_group_data.deinit(allocator);
54 self.relocs.deinit(allocator);
55 self.fdes.deinit(allocator);
56 self.cies.deinit(allocator);
57 self.eh_frame_data.deinit(allocator);
40pub fn deinit(self: *Object, gpa: Allocator) void {
41 if (self.archive) |*ar| gpa.free(ar.path.sub_path);
42 gpa.free(self.path.sub_path);
43 self.shdrs.deinit(gpa);
44 self.symtab.deinit(gpa);
45 self.strtab.deinit(gpa);
46 self.symbols.deinit(gpa);
47 self.symbols_extra.deinit(gpa);
48 self.symbols_resolver.deinit(gpa);
49 self.atoms.deinit(gpa);
50 self.atoms_indexes.deinit(gpa);
51 self.atoms_extra.deinit(gpa);
52 self.comdat_groups.deinit(gpa);
53 self.comdat_group_data.deinit(gpa);
54 self.relocs.deinit(gpa);
55 self.fdes.deinit(gpa);
56 self.cies.deinit(gpa);
57 self.eh_frame_data.deinit(gpa);
5858 for (self.input_merge_sections.items) |*isec| {
59 isec.deinit(allocator);
59 isec.deinit(gpa);
6060 }
61 self.input_merge_sections.deinit(allocator);
62 self.input_merge_sections_indexes.deinit(allocator);
61 self.input_merge_sections.deinit(gpa);
62 self.input_merge_sections_indexes.deinit(gpa);
6363}
6464
65pub fn parse(self: *Object, elf_file: *Elf) !void {
66 const gpa = elf_file.base.comp.gpa;
67 const cpu_arch = elf_file.getTarget().cpu.arch;
68 const handle = elf_file.fileHandle(self.file_handle);
69
70 try self.parseCommon(gpa, handle, elf_file);
65pub fn parse(
66 self: *Object,
67 gpa: Allocator,
68 diags: *Diags,
69 /// For error reporting purposes only.
70 path: Path,
71 handle: fs.File,
72 first_eflags: *?elf.Word,
73 target: std.Target,
74 debug_fmt_strip: bool,
75 default_sym_version: elf.Versym,
76) !void {
77 try self.parseCommon(gpa, diags, path, handle, first_eflags, target);
7178
7279 // Append null input merge section
7380 try self.input_merge_sections.append(gpa, .{});
7481 // Allocate atom index 0 to null atom
7582 try self.atoms.append(gpa, .{ .extra_index = try self.addAtomExtra(gpa, .{}) });
7683
77 try self.initAtoms(gpa, handle, elf_file);
78 try self.initSymbols(gpa, elf_file);
84 try self.initAtoms(gpa, diags, path, handle, debug_fmt_strip, target);
85 try self.initSymbols(gpa, default_sym_version);
7986
8087 for (self.shdrs.items, 0..) |shdr, i| {
8188 const atom_ptr = self.atom(self.atoms_indexes.items[i]) orelse continue;
8289 if (!atom_ptr.alive) continue;
83 if ((cpu_arch == .x86_64 and shdr.sh_type == elf.SHT_X86_64_UNWIND) or
84 mem.eql(u8, atom_ptr.name(elf_file), ".eh_frame"))
90 if ((target.cpu.arch == .x86_64 and shdr.sh_type == elf.SHT_X86_64_UNWIND) or
91 mem.eql(u8, self.getString(atom_ptr.name_offset), ".eh_frame"))
8592 {
86 try self.parseEhFrame(gpa, handle, @as(u32, @intCast(i)), elf_file);
93 try self.parseEhFrame(gpa, handle, @intCast(i), target);
8794 }
8895 }
8996}
9097
91fn parseCommon(self: *Object, allocator: Allocator, handle: std.fs.File, elf_file: *Elf) !void {
98fn parseCommon(
99 self: *Object,
100 gpa: Allocator,
101 diags: *Diags,
102 path: Path,
103 handle: fs.File,
104 first_eflags: *?elf.Word,
105 target: std.Target,
106) !void {
92107 const offset = if (self.archive) |ar| ar.offset else 0;
93108 const file_size = (try handle.stat()).size;
94109
95 const header_buffer = try Elf.preadAllAlloc(allocator, handle, offset, @sizeOf(elf.Elf64_Ehdr));
96 defer allocator.free(header_buffer);
110 const header_buffer = try Elf.preadAllAlloc(gpa, handle, offset, @sizeOf(elf.Elf64_Ehdr));
111 defer gpa.free(header_buffer);
97112 self.header = @as(*align(1) const elf.Elf64_Ehdr, @ptrCast(header_buffer)).*;
98113
99 const em = elf_file.base.comp.root_mod.resolved_target.result.toElfMachine();
114 const em = target.toElfMachine();
100115 if (em != self.header.?.e_machine) {
101 return elf_file.failFile(self.index, "invalid ELF machine type: {s}", .{
116 return diags.failParse(path, "invalid ELF machine type: {s}", .{
102117 @tagName(self.header.?.e_machine),
103118 });
104119 }
105 try elf_file.validateEFlags(self.index, self.header.?.e_flags);
120 try validateEFlags(diags, path, target, self.header.?.e_flags, first_eflags);
106121
107122 if (self.header.?.e_shnum == 0) return;
108123
......@@ -110,30 +125,30 @@ fn parseCommon(self: *Object, allocator: Allocator, handle: std.fs.File, elf_fil
110125 const shnum = math.cast(usize, self.header.?.e_shnum) orelse return error.Overflow;
111126 const shsize = shnum * @sizeOf(elf.Elf64_Shdr);
112127 if (file_size < offset + shoff or file_size < offset + shoff + shsize) {
113 return elf_file.failFile(self.index, "corrupt header: section header table extends past the end of file", .{});
128 return diags.failParse(path, "corrupt header: section header table extends past the end of file", .{});
114129 }
115130
116 const shdrs_buffer = try Elf.preadAllAlloc(allocator, handle, offset + shoff, shsize);
117 defer allocator.free(shdrs_buffer);
131 const shdrs_buffer = try Elf.preadAllAlloc(gpa, handle, offset + shoff, shsize);
132 defer gpa.free(shdrs_buffer);
118133 const shdrs = @as([*]align(1) const elf.Elf64_Shdr, @ptrCast(shdrs_buffer.ptr))[0..shnum];
119 try self.shdrs.appendUnalignedSlice(allocator, shdrs);
134 try self.shdrs.appendUnalignedSlice(gpa, shdrs);
120135
121136 for (self.shdrs.items) |shdr| {
122137 if (shdr.sh_type != elf.SHT_NOBITS) {
123138 if (file_size < offset + shdr.sh_offset or file_size < offset + shdr.sh_offset + shdr.sh_size) {
124 return elf_file.failFile(self.index, "corrupt section: extends past the end of file", .{});
139 return diags.failParse(path, "corrupt section: extends past the end of file", .{});
125140 }
126141 }
127142 }
128143
129 const shstrtab = try self.preadShdrContentsAlloc(allocator, handle, self.header.?.e_shstrndx);
130 defer allocator.free(shstrtab);
144 const shstrtab = try self.preadShdrContentsAlloc(gpa, handle, self.header.?.e_shstrndx);
145 defer gpa.free(shstrtab);
131146 for (self.shdrs.items) |shdr| {
132147 if (shdr.sh_name >= shstrtab.len) {
133 return elf_file.failFile(self.index, "corrupt section name offset", .{});
148 return diags.failParse(path, "corrupt section name offset", .{});
134149 }
135150 }
136 try self.strtab.appendSlice(allocator, shstrtab);
151 try self.strtab.appendSlice(gpa, shstrtab);
137152
138153 const symtab_index = for (self.shdrs.items, 0..) |shdr, i| switch (shdr.sh_type) {
139154 elf.SHT_SYMTAB => break @as(u32, @intCast(i)),
......@@ -144,19 +159,19 @@ fn parseCommon(self: *Object, allocator: Allocator, handle: std.fs.File, elf_fil
144159 const shdr = self.shdrs.items[index];
145160 self.first_global = shdr.sh_info;
146161
147 const raw_symtab = try self.preadShdrContentsAlloc(allocator, handle, index);
148 defer allocator.free(raw_symtab);
162 const raw_symtab = try self.preadShdrContentsAlloc(gpa, handle, index);
163 defer gpa.free(raw_symtab);
149164 const nsyms = math.divExact(usize, raw_symtab.len, @sizeOf(elf.Elf64_Sym)) catch {
150 return elf_file.failFile(self.index, "symbol table not evenly divisible", .{});
165 return diags.failParse(path, "symbol table not evenly divisible", .{});
151166 };
152167 const symtab = @as([*]align(1) const elf.Elf64_Sym, @ptrCast(raw_symtab.ptr))[0..nsyms];
153168
154169 const strtab_bias = @as(u32, @intCast(self.strtab.items.len));
155 const strtab = try self.preadShdrContentsAlloc(allocator, handle, shdr.sh_link);
156 defer allocator.free(strtab);
157 try self.strtab.appendSlice(allocator, strtab);
170 const strtab = try self.preadShdrContentsAlloc(gpa, handle, shdr.sh_link);
171 defer gpa.free(strtab);
172 try self.strtab.appendSlice(gpa, strtab);
158173
159 try self.symtab.ensureUnusedCapacity(allocator, symtab.len);
174 try self.symtab.ensureUnusedCapacity(gpa, symtab.len);
160175 for (symtab) |sym| {
161176 const out_sym = self.symtab.addOneAssumeCapacity();
162177 out_sym.* = sym;
......@@ -168,15 +183,56 @@ fn parseCommon(self: *Object, allocator: Allocator, handle: std.fs.File, elf_fil
168183 }
169184}
170185
171fn initAtoms(self: *Object, allocator: Allocator, handle: std.fs.File, elf_file: *Elf) !void {
172 const comp = elf_file.base.comp;
173 const debug_fmt_strip = comp.config.debug_format == .strip;
174 const target = comp.root_mod.resolved_target.result;
186fn validateEFlags(
187 diags: *Diags,
188 path: Path,
189 target: std.Target,
190 e_flags: elf.Word,
191 first_eflags: *?elf.Word,
192) error{LinkFailure}!void {
193 if (first_eflags.*) |*self_eflags| {
194 switch (target.cpu.arch) {
195 .riscv64 => {
196 if (e_flags != self_eflags.*) {
197 const riscv_eflags: riscv.RiscvEflags = @bitCast(e_flags);
198 const self_riscv_eflags: *riscv.RiscvEflags = @ptrCast(self_eflags);
199
200 self_riscv_eflags.rvc = self_riscv_eflags.rvc or riscv_eflags.rvc;
201 self_riscv_eflags.tso = self_riscv_eflags.tso or riscv_eflags.tso;
202
203 var any_errors: bool = false;
204 if (self_riscv_eflags.fabi != riscv_eflags.fabi) {
205 any_errors = true;
206 diags.addParseError(path, "cannot link object files with different float-point ABIs", .{});
207 }
208 if (self_riscv_eflags.rve != riscv_eflags.rve) {
209 any_errors = true;
210 diags.addParseError(path, "cannot link object files with different RVEs", .{});
211 }
212 if (any_errors) return error.LinkFailure;
213 }
214 },
215 else => {},
216 }
217 } else {
218 first_eflags.* = e_flags;
219 }
220}
221
222fn initAtoms(
223 self: *Object,
224 gpa: Allocator,
225 diags: *Diags,
226 path: Path,
227 handle: fs.File,
228 debug_fmt_strip: bool,
229 target: std.Target,
230) !void {
175231 const shdrs = self.shdrs.items;
176 try self.atoms.ensureTotalCapacityPrecise(allocator, shdrs.len);
177 try self.atoms_extra.ensureTotalCapacityPrecise(allocator, shdrs.len * @sizeOf(Atom.Extra));
178 try self.atoms_indexes.ensureTotalCapacityPrecise(allocator, shdrs.len);
179 try self.atoms_indexes.resize(allocator, shdrs.len);
232 try self.atoms.ensureTotalCapacityPrecise(gpa, shdrs.len);
233 try self.atoms_extra.ensureTotalCapacityPrecise(gpa, shdrs.len * @sizeOf(Atom.Extra));
234 try self.atoms_indexes.ensureTotalCapacityPrecise(gpa, shdrs.len);
235 try self.atoms_indexes.resize(gpa, shdrs.len);
180236 @memset(self.atoms_indexes.items, 0);
181237
182238 for (shdrs, 0..) |shdr, i| {
......@@ -201,24 +257,24 @@ fn initAtoms(self: *Object, allocator: Allocator, handle: std.fs.File, elf_file:
201257 };
202258
203259 const shndx: u32 = @intCast(i);
204 const group_raw_data = try self.preadShdrContentsAlloc(allocator, handle, shndx);
205 defer allocator.free(group_raw_data);
260 const group_raw_data = try self.preadShdrContentsAlloc(gpa, handle, shndx);
261 defer gpa.free(group_raw_data);
206262 const group_nmembers = math.divExact(usize, group_raw_data.len, @sizeOf(u32)) catch {
207 return elf_file.failFile(self.index, "corrupt section group: not evenly divisible ", .{});
263 return diags.failParse(path, "corrupt section group: not evenly divisible ", .{});
208264 };
209265 if (group_nmembers == 0) {
210 return elf_file.failFile(self.index, "corrupt section group: empty section", .{});
266 return diags.failParse(path, "corrupt section group: empty section", .{});
211267 }
212268 const group_members = @as([*]align(1) const u32, @ptrCast(group_raw_data.ptr))[0..group_nmembers];
213269
214270 if (group_members[0] != elf.GRP_COMDAT) {
215 return elf_file.failFile(self.index, "corrupt section group: unknown SHT_GROUP format", .{});
271 return diags.failParse(path, "corrupt section group: unknown SHT_GROUP format", .{});
216272 }
217273
218274 const group_start: u32 = @intCast(self.comdat_group_data.items.len);
219 try self.comdat_group_data.appendUnalignedSlice(allocator, group_members[1..]);
275 try self.comdat_group_data.appendUnalignedSlice(gpa, group_members[1..]);
220276
221 const comdat_group_index = try self.addComdatGroup(allocator);
277 const comdat_group_index = try self.addComdatGroup(gpa);
222278 const comdat_group = self.comdatGroup(comdat_group_index);
223279 comdat_group.* = .{
224280 .signature_off = group_signature,
......@@ -242,8 +298,8 @@ fn initAtoms(self: *Object, allocator: Allocator, handle: std.fs.File, elf_file:
242298 const shndx: u32 = @intCast(i);
243299 if (self.skipShdr(shndx, debug_fmt_strip)) continue;
244300 const size, const alignment = if (shdr.sh_flags & elf.SHF_COMPRESSED != 0) blk: {
245 const data = try self.preadShdrContentsAlloc(allocator, handle, shndx);
246 defer allocator.free(data);
301 const data = try self.preadShdrContentsAlloc(gpa, handle, shndx);
302 defer gpa.free(data);
247303 const chdr = @as(*align(1) const elf.Elf64_Chdr, @ptrCast(data.ptr)).*;
248304 break :blk .{ chdr.ch_size, Alignment.fromNonzeroByteUnits(chdr.ch_addralign) };
249305 } else .{ shdr.sh_size, Alignment.fromNonzeroByteUnits(shdr.sh_addralign) };
......@@ -263,13 +319,13 @@ fn initAtoms(self: *Object, allocator: Allocator, handle: std.fs.File, elf_file:
263319 elf.SHT_REL, elf.SHT_RELA => {
264320 const atom_index = self.atoms_indexes.items[shdr.sh_info];
265321 if (self.atom(atom_index)) |atom_ptr| {
266 const relocs = try self.preadRelocsAlloc(allocator, handle, @intCast(i));
267 defer allocator.free(relocs);
322 const relocs = try self.preadRelocsAlloc(gpa, handle, @intCast(i));
323 defer gpa.free(relocs);
268324 atom_ptr.relocs_section_index = @intCast(i);
269325 const rel_index: u32 = @intCast(self.relocs.items.len);
270326 const rel_count: u32 = @intCast(relocs.len);
271327 self.setAtomFields(atom_ptr, .{ .rel_index = rel_index, .rel_count = rel_count });
272 try self.relocs.appendUnalignedSlice(allocator, relocs);
328 try self.relocs.appendUnalignedSlice(gpa, relocs);
273329 if (target.cpu.arch == .riscv64) {
274330 sortRelocs(self.relocs.items[rel_index..][0..rel_count]);
275331 }
......@@ -293,14 +349,18 @@ fn skipShdr(self: *Object, index: u32, debug_fmt_strip: bool) bool {
293349 return ignore;
294350}
295351
296fn initSymbols(self: *Object, allocator: Allocator, elf_file: *Elf) !void {
352fn initSymbols(
353 self: *Object,
354 gpa: Allocator,
355 default_sym_version: elf.Versym,
356) !void {
297357 const first_global = self.first_global orelse self.symtab.items.len;
298358 const nglobals = self.symtab.items.len - first_global;
299359
300 try self.symbols.ensureTotalCapacityPrecise(allocator, self.symtab.items.len);
301 try self.symbols_extra.ensureTotalCapacityPrecise(allocator, self.symtab.items.len * @sizeOf(Symbol.Extra));
302 try self.symbols_resolver.ensureTotalCapacityPrecise(allocator, nglobals);
303 self.symbols_resolver.resize(allocator, nglobals) catch unreachable;
360 try self.symbols.ensureTotalCapacityPrecise(gpa, self.symtab.items.len);
361 try self.symbols_extra.ensureTotalCapacityPrecise(gpa, self.symtab.items.len * @sizeOf(Symbol.Extra));
362 try self.symbols_resolver.ensureTotalCapacityPrecise(gpa, nglobals);
363 self.symbols_resolver.resize(gpa, nglobals) catch unreachable;
304364 @memset(self.symbols_resolver.items, 0);
305365
306366 for (self.symtab.items, 0..) |sym, i| {
......@@ -310,7 +370,7 @@ fn initSymbols(self: *Object, allocator: Allocator, elf_file: *Elf) !void {
310370 sym_ptr.name_offset = sym.st_name;
311371 sym_ptr.esym_index = @intCast(i);
312372 sym_ptr.extra_index = self.addSymbolExtraAssumeCapacity(.{});
313 sym_ptr.version_index = if (i >= first_global) elf_file.default_sym_version else .LOCAL;
373 sym_ptr.version_index = if (i >= first_global) default_sym_version else .LOCAL;
314374 sym_ptr.flags.weak = sym.st_bind() == elf.STB_WEAK;
315375 if (sym.st_shndx != elf.SHN_ABS and sym.st_shndx != elf.SHN_COMMON) {
316376 sym_ptr.ref = .{ .index = self.atoms_indexes.items[sym.st_shndx], .file = self.index };
......@@ -318,24 +378,30 @@ fn initSymbols(self: *Object, allocator: Allocator, elf_file: *Elf) !void {
318378 }
319379}
320380
321fn parseEhFrame(self: *Object, allocator: Allocator, handle: std.fs.File, shndx: u32, elf_file: *Elf) !void {
381fn parseEhFrame(
382 self: *Object,
383 gpa: Allocator,
384 handle: fs.File,
385 shndx: u32,
386 target: std.Target,
387) !void {
322388 const relocs_shndx = for (self.shdrs.items, 0..) |shdr, i| switch (shdr.sh_type) {
323389 elf.SHT_RELA => if (shdr.sh_info == shndx) break @as(u32, @intCast(i)),
324390 else => {},
325391 } else null;
326392
327 const raw = try self.preadShdrContentsAlloc(allocator, handle, shndx);
328 defer allocator.free(raw);
329 const data_start = @as(u32, @intCast(self.eh_frame_data.items.len));
330 try self.eh_frame_data.appendSlice(allocator, raw);
393 const raw = try self.preadShdrContentsAlloc(gpa, handle, shndx);
394 defer gpa.free(raw);
395 const data_start: u32 = @intCast(self.eh_frame_data.items.len);
396 try self.eh_frame_data.appendSlice(gpa, raw);
331397 const relocs = if (relocs_shndx) |index|
332 try self.preadRelocsAlloc(allocator, handle, index)
398 try self.preadRelocsAlloc(gpa, handle, index)
333399 else
334400 &[0]elf.Elf64_Rela{};
335 defer allocator.free(relocs);
336 const rel_start = @as(u32, @intCast(self.relocs.items.len));
337 try self.relocs.appendUnalignedSlice(allocator, relocs);
338 if (elf_file.getTarget().cpu.arch == .riscv64) {
401 defer gpa.free(relocs);
402 const rel_start: u32 = @intCast(self.relocs.items.len);
403 try self.relocs.appendUnalignedSlice(gpa, relocs);
404 if (target.cpu.arch == .riscv64) {
339405 sortRelocs(self.relocs.items[rel_start..][0..relocs.len]);
340406 }
341407 const fdes_start = self.fdes.items.len;
......@@ -345,11 +411,11 @@ fn parseEhFrame(self: *Object, allocator: Allocator, handle: std.fs.File, shndx:
345411 while (try it.next()) |rec| {
346412 const rel_range = filterRelocs(self.relocs.items[rel_start..][0..relocs.len], rec.offset, rec.size + 4);
347413 switch (rec.tag) {
348 .cie => try self.cies.append(allocator, .{
414 .cie => try self.cies.append(gpa, .{
349415 .offset = data_start + rec.offset,
350416 .size = rec.size,
351417 .rel_index = rel_start + @as(u32, @intCast(rel_range.start)),
352 .rel_num = @as(u32, @intCast(rel_range.len)),
418 .rel_num = @intCast(rel_range.len),
353419 .input_section_index = shndx,
354420 .file_index = self.index,
355421 }),
......@@ -361,12 +427,12 @@ fn parseEhFrame(self: *Object, allocator: Allocator, handle: std.fs.File, shndx:
361427 // this can happen for object files built with -r flag by the linker.
362428 continue;
363429 }
364 try self.fdes.append(allocator, .{
430 try self.fdes.append(gpa, .{
365431 .offset = data_start + rec.offset,
366432 .size = rec.size,
367433 .cie_index = undefined,
368434 .rel_index = rel_start + @as(u32, @intCast(rel_range.start)),
369 .rel_num = @as(u32, @intCast(rel_range.len)),
435 .rel_num = @intCast(rel_range.len),
370436 .input_section_index = shndx,
371437 .file_index = self.index,
372438 });
......@@ -376,7 +442,7 @@ fn parseEhFrame(self: *Object, allocator: Allocator, handle: std.fs.File, shndx:
376442
377443 // Tie each FDE to its CIE
378444 for (self.fdes.items[fdes_start..]) |*fde| {
379 const cie_ptr = fde.offset + 4 - fde.ciePointer(elf_file);
445 const cie_ptr = fde.offset + 4 - fde.ciePointer(self);
380446 const cie_index = for (self.cies.items[cies_start..], cies_start..) |cie, cie_index| {
381447 if (cie.offset == cie_ptr) break @as(u32, @intCast(cie_index));
382448 } else {
......@@ -392,26 +458,26 @@ fn parseEhFrame(self: *Object, allocator: Allocator, handle: std.fs.File, shndx:
392458
393459 // Tie each FDE record to its matching atom
394460 const SortFdes = struct {
395 pub fn lessThan(ctx: *Elf, lhs: Fde, rhs: Fde) bool {
461 pub fn lessThan(ctx: *Object, lhs: Fde, rhs: Fde) bool {
396462 const lhs_atom = lhs.atom(ctx);
397463 const rhs_atom = rhs.atom(ctx);
398 return lhs_atom.priority(ctx) < rhs_atom.priority(ctx);
464 return Atom.priorityLookup(ctx.index, lhs_atom.input_section_index) < Atom.priorityLookup(ctx.index, rhs_atom.input_section_index);
399465 }
400466 };
401 mem.sort(Fde, self.fdes.items[fdes_start..], elf_file, SortFdes.lessThan);
467 mem.sort(Fde, self.fdes.items[fdes_start..], self, SortFdes.lessThan);
402468
403469 // Create a back-link from atom to FDEs
404 var i: u32 = @as(u32, @intCast(fdes_start));
470 var i: u32 = @intCast(fdes_start);
405471 while (i < self.fdes.items.len) {
406472 const fde = self.fdes.items[i];
407 const atom_ptr = fde.atom(elf_file);
473 const atom_ptr = fde.atom(self);
408474 const start = i;
409475 i += 1;
410476 while (i < self.fdes.items.len) : (i += 1) {
411477 const next_fde = self.fdes.items[i];
412 if (atom_ptr.atom_index != next_fde.atom(elf_file).atom_index) break;
478 if (atom_ptr.atom_index != next_fde.atom(self).atom_index) break;
413479 }
414 atom_ptr.addExtra(.{ .fde_start = start, .fde_count = i - start }, elf_file);
480 self.setAtomFields(atom_ptr, .{ .fde_start = start, .fde_count = i - start });
415481 }
416482}
417483
......@@ -904,7 +970,7 @@ pub fn markComdatGroupsDead(self: *Object, elf_file: *Elf) void {
904970 const atom_index = self.atoms_indexes.items[shndx];
905971 if (self.atom(atom_index)) |atom_ptr| {
906972 atom_ptr.alive = false;
907 atom_ptr.markFdesDead(elf_file);
973 atom_ptr.markFdesDead(self);
908974 }
909975 }
910976 }
......@@ -970,10 +1036,13 @@ pub fn addAtomsToRelaSections(self: *Object, elf_file: *Elf) !void {
9701036 }
9711037}
9721038
973pub fn parseAr(self: *Object, elf_file: *Elf) !void {
1039pub fn parseAr(self: *Object, path: Path, elf_file: *Elf) !void {
9741040 const gpa = elf_file.base.comp.gpa;
1041 const diags = &elf_file.base.comp.link_diags;
9751042 const handle = elf_file.fileHandle(self.file_handle);
976 try self.parseCommon(gpa, handle, elf_file);
1043 const first_eflags = &elf_file.first_eflags;
1044 const target = elf_file.base.comp.root_mod.resolved_target.result;
1045 try self.parseCommon(gpa, diags, path, handle, first_eflags, target);
9771046}
9781047
9791048pub fn updateArSymtab(self: Object, ar_symtab: *Archive.ArSymtab, elf_file: *Elf) !void {
......@@ -1000,7 +1069,7 @@ pub fn updateArSize(self: *Object, elf_file: *Elf) !void {
10001069pub fn writeAr(self: Object, elf_file: *Elf, writer: anytype) !void {
10011070 const size = std.math.cast(usize, self.output_ar_state.size) orelse return error.Overflow;
10021071 const offset: u64 = if (self.archive) |ar| ar.offset else 0;
1003 const name = std.fs.path.basename(self.path.sub_path);
1072 const name = fs.path.basename(self.path.sub_path);
10041073 const hdr = Archive.setArHdr(.{
10051074 .name = if (name.len <= Archive.max_member_name_len)
10061075 .{ .name = name }
......@@ -1136,8 +1205,8 @@ pub fn resolveSymbol(self: Object, index: Symbol.Index, elf_file: *Elf) Elf.Ref
11361205 return elf_file.resolver.get(resolv).?;
11371206}
11381207
1139fn addSymbol(self: *Object, allocator: Allocator) !Symbol.Index {
1140 try self.symbols.ensureUnusedCapacity(allocator, 1);
1208fn addSymbol(self: *Object, gpa: Allocator) !Symbol.Index {
1209 try self.symbols.ensureUnusedCapacity(gpa, 1);
11411210 return self.addSymbolAssumeCapacity();
11421211}
11431212
......@@ -1147,9 +1216,9 @@ fn addSymbolAssumeCapacity(self: *Object) Symbol.Index {
11471216 return index;
11481217}
11491218
1150pub fn addSymbolExtra(self: *Object, allocator: Allocator, extra: Symbol.Extra) !u32 {
1219pub fn addSymbolExtra(self: *Object, gpa: Allocator, extra: Symbol.Extra) !u32 {
11511220 const fields = @typeInfo(Symbol.Extra).@"struct".fields;
1152 try self.symbols_extra.ensureUnusedCapacity(allocator, fields.len);
1221 try self.symbols_extra.ensureUnusedCapacity(gpa, fields.len);
11531222 return self.addSymbolExtraAssumeCapacity(extra);
11541223}
11551224
......@@ -1198,27 +1267,27 @@ pub fn getString(self: Object, off: u32) [:0]const u8 {
11981267 return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.strtab.items.ptr + off)), 0);
11991268}
12001269
1201fn addString(self: *Object, allocator: Allocator, str: []const u8) !u32 {
1270fn addString(self: *Object, gpa: Allocator, str: []const u8) !u32 {
12021271 const off: u32 = @intCast(self.strtab.items.len);
1203 try self.strtab.ensureUnusedCapacity(allocator, str.len + 1);
1272 try self.strtab.ensureUnusedCapacity(gpa, str.len + 1);
12041273 self.strtab.appendSliceAssumeCapacity(str);
12051274 self.strtab.appendAssumeCapacity(0);
12061275 return off;
12071276}
12081277
12091278/// Caller owns the memory.
1210fn preadShdrContentsAlloc(self: Object, allocator: Allocator, handle: std.fs.File, index: u32) ![]u8 {
1279fn preadShdrContentsAlloc(self: Object, gpa: Allocator, handle: fs.File, index: u32) ![]u8 {
12111280 assert(index < self.shdrs.items.len);
12121281 const offset = if (self.archive) |ar| ar.offset else 0;
12131282 const shdr = self.shdrs.items[index];
12141283 const sh_offset = math.cast(u64, shdr.sh_offset) orelse return error.Overflow;
12151284 const sh_size = math.cast(u64, shdr.sh_size) orelse return error.Overflow;
1216 return Elf.preadAllAlloc(allocator, handle, offset + sh_offset, sh_size);
1285 return Elf.preadAllAlloc(gpa, handle, offset + sh_offset, sh_size);
12171286}
12181287
12191288/// Caller owns the memory.
1220fn preadRelocsAlloc(self: Object, allocator: Allocator, handle: std.fs.File, shndx: u32) ![]align(1) const elf.Elf64_Rela {
1221 const raw = try self.preadShdrContentsAlloc(allocator, handle, shndx);
1289fn preadRelocsAlloc(self: Object, gpa: Allocator, handle: fs.File, shndx: u32) ![]align(1) const elf.Elf64_Rela {
1290 const raw = try self.preadShdrContentsAlloc(gpa, handle, shndx);
12221291 const num = @divExact(raw.len, @sizeOf(elf.Elf64_Rela));
12231292 return @as([*]align(1) const elf.Elf64_Rela, @ptrCast(raw.ptr))[0..num];
12241293}
......@@ -1230,9 +1299,9 @@ const AddAtomArgs = struct {
12301299 alignment: Alignment,
12311300};
12321301
1233fn addAtom(self: *Object, allocator: Allocator, args: AddAtomArgs) !Atom.Index {
1234 try self.atoms.ensureUnusedCapacity(allocator, 1);
1235 try self.atoms_extra.ensureUnusedCapacity(allocator, @sizeOf(Atom.Extra));
1302fn addAtom(self: *Object, gpa: Allocator, args: AddAtomArgs) !Atom.Index {
1303 try self.atoms.ensureUnusedCapacity(gpa, 1);
1304 try self.atoms_extra.ensureUnusedCapacity(gpa, @sizeOf(Atom.Extra));
12361305 return self.addAtomAssumeCapacity(args);
12371306}
12381307
......@@ -1257,9 +1326,9 @@ pub fn atom(self: *Object, atom_index: Atom.Index) ?*Atom {
12571326 return &self.atoms.items[atom_index];
12581327}
12591328
1260pub fn addAtomExtra(self: *Object, allocator: Allocator, extra: Atom.Extra) !u32 {
1329pub fn addAtomExtra(self: *Object, gpa: Allocator, extra: Atom.Extra) !u32 {
12611330 const fields = @typeInfo(Atom.Extra).@"struct".fields;
1262 try self.atoms_extra.ensureUnusedCapacity(allocator, fields.len);
1331 try self.atoms_extra.ensureUnusedCapacity(gpa, fields.len);
12631332 return self.addAtomExtraAssumeCapacity(extra);
12641333}
12651334
......@@ -1308,9 +1377,9 @@ fn setAtomFields(o: *Object, atom_ptr: *Atom, opts: Atom.Extra.AsOptionals) void
13081377 o.setAtomExtra(atom_ptr.extra_index, extras);
13091378}
13101379
1311fn addInputMergeSection(self: *Object, allocator: Allocator) !Merge.InputSection.Index {
1380fn addInputMergeSection(self: *Object, gpa: Allocator) !Merge.InputSection.Index {
13121381 const index: Merge.InputSection.Index = @intCast(self.input_merge_sections.items.len);
1313 const msec = try self.input_merge_sections.addOne(allocator);
1382 const msec = try self.input_merge_sections.addOne(gpa);
13141383 msec.* = .{};
13151384 return index;
13161385}
......@@ -1320,9 +1389,9 @@ fn inputMergeSection(self: *Object, index: Merge.InputSection.Index) ?*Merge.Inp
13201389 return &self.input_merge_sections.items[index];
13211390}
13221391
1323fn addComdatGroup(self: *Object, allocator: Allocator) !Elf.ComdatGroup.Index {
1392fn addComdatGroup(self: *Object, gpa: Allocator) !Elf.ComdatGroup.Index {
13241393 const index = @as(Elf.ComdatGroup.Index, @intCast(self.comdat_groups.items.len));
1325 _ = try self.comdat_groups.addOne(allocator);
1394 _ = try self.comdat_groups.addOne(gpa);
13261395 return index;
13271396}
13281397
......@@ -1516,8 +1585,9 @@ const log = std.log.scoped(.link);
15161585const math = std.math;
15171586const mem = std.mem;
15181587const Path = std.Build.Cache.Path;
1519const Allocator = mem.Allocator;
1588const Allocator = std.mem.Allocator;
15201589
1590const Diags = @import("../../link.zig").Diags;
15211591const Archive = @import("Archive.zig");
15221592const Atom = @import("Atom.zig");
15231593const AtomList = @import("AtomList.zig");
......@@ -1528,3 +1598,4 @@ const File = @import("file.zig").File;
15281598const Merge = @import("Merge.zig");
15291599const Symbol = @import("Symbol.zig");
15301600const Alignment = Atom.Alignment;
1601const riscv = @import("../riscv.zig");
src/link/Elf/eh_frame.zig+17-20
......@@ -19,18 +19,16 @@ pub const Fde = struct {
1919 return base + fde.out_offset;
2020 }
2121
22 pub fn data(fde: Fde, elf_file: *Elf) []u8 {
23 const object = elf_file.file(fde.file_index).?.object;
22 pub fn data(fde: Fde, object: *Object) []u8 {
2423 return object.eh_frame_data.items[fde.offset..][0..fde.calcSize()];
2524 }
2625
27 pub fn cie(fde: Fde, elf_file: *Elf) Cie {
28 const object = elf_file.file(fde.file_index).?.object;
26 pub fn cie(fde: Fde, object: *Object) Cie {
2927 return object.cies.items[fde.cie_index];
3028 }
3129
32 pub fn ciePointer(fde: Fde, elf_file: *Elf) u32 {
33 const fde_data = fde.data(elf_file);
30 pub fn ciePointer(fde: Fde, object: *Object) u32 {
31 const fde_data = fde.data(object);
3432 return std.mem.readInt(u32, fde_data[4..8], .little);
3533 }
3634
......@@ -38,16 +36,14 @@ pub const Fde = struct {
3836 return fde.size + 4;
3937 }
4038
41 pub fn atom(fde: Fde, elf_file: *Elf) *Atom {
42 const object = elf_file.file(fde.file_index).?.object;
43 const rel = fde.relocs(elf_file)[0];
39 pub fn atom(fde: Fde, object: *Object) *Atom {
40 const rel = fde.relocs(object)[0];
4441 const sym = object.symtab.items[rel.r_sym()];
4542 const atom_index = object.atoms_indexes.items[sym.st_shndx];
4643 return object.atom(atom_index).?;
4744 }
4845
49 pub fn relocs(fde: Fde, elf_file: *Elf) []align(1) const elf.Elf64_Rela {
50 const object = elf_file.file(fde.file_index).?.object;
46 pub fn relocs(fde: Fde, object: *Object) []const elf.Elf64_Rela {
5147 return object.relocs.items[fde.rel_index..][0..fde.rel_num];
5248 }
5349
......@@ -87,7 +83,8 @@ pub const Fde = struct {
8783 const fde = ctx.fde;
8884 const elf_file = ctx.elf_file;
8985 const base_addr = fde.address(elf_file);
90 const atom_name = fde.atom(elf_file).name(elf_file);
86 const object = elf_file.file(fde.file_index).?.object;
87 const atom_name = fde.atom(object).name(elf_file);
9188 try writer.print("@{x} : size({x}) : cie({d}) : {s}", .{
9289 base_addr + fde.out_offset,
9390 fde.calcSize(),
......@@ -306,7 +303,7 @@ pub fn calcEhFrameRelocs(elf_file: *Elf) usize {
306303 }
307304 for (object.fdes.items) |fde| {
308305 if (!fde.alive) continue;
309 count += fde.relocs(elf_file).len;
306 count += fde.relocs(object).len;
310307 }
311308 }
312309 return count;
......@@ -369,16 +366,16 @@ pub fn writeEhFrame(elf_file: *Elf, writer: anytype) !void {
369366 for (object.fdes.items) |fde| {
370367 if (!fde.alive) continue;
371368
372 const contents = fde.data(elf_file);
369 const contents = fde.data(object);
373370
374371 std.mem.writeInt(
375372 i32,
376373 contents[4..8],
377 @truncate(@as(i64, @intCast(fde.out_offset + 4)) - @as(i64, @intCast(fde.cie(elf_file).out_offset))),
374 @truncate(@as(i64, @intCast(fde.out_offset + 4)) - @as(i64, @intCast(fde.cie(object).out_offset))),
378375 .little,
379376 );
380377
381 for (fde.relocs(elf_file)) |rel| {
378 for (fde.relocs(object)) |rel| {
382379 const ref = object.resolveSymbol(rel.r_sym(), elf_file);
383380 const sym = elf_file.symbol(ref).?;
384381 resolveReloc(fde, sym, rel, elf_file, contents) catch |err| switch (err) {
......@@ -412,12 +409,12 @@ pub fn writeEhFrameRelocatable(elf_file: *Elf, writer: anytype) !void {
412409 for (object.fdes.items) |fde| {
413410 if (!fde.alive) continue;
414411
415 const contents = fde.data(elf_file);
412 const contents = fde.data(object);
416413
417414 std.mem.writeInt(
418415 i32,
419416 contents[4..8],
420 @truncate(@as(i64, @intCast(fde.out_offset + 4)) - @as(i64, @intCast(fde.cie(elf_file).out_offset))),
417 @truncate(@as(i64, @intCast(fde.out_offset + 4)) - @as(i64, @intCast(fde.cie(object).out_offset))),
421418 .little,
422419 );
423420
......@@ -490,7 +487,7 @@ pub fn writeEhFrameRelocs(elf_file: *Elf, writer: anytype) !void {
490487
491488 for (object.fdes.items) |fde| {
492489 if (!fde.alive) continue;
493 for (fde.relocs(elf_file)) |rel| {
490 for (fde.relocs(object)) |rel| {
494491 const ref = object.resolveSymbol(rel.r_sym(), elf_file);
495492 const sym = elf_file.symbol(ref).?;
496493 const r_offset = fde.address(elf_file) + rel.r_offset - fde.offset;
......@@ -548,7 +545,7 @@ pub fn writeEhFrameHdr(elf_file: *Elf, writer: anytype) !void {
548545 for (object.fdes.items) |fde| {
549546 if (!fde.alive) continue;
550547
551 const relocs = fde.relocs(elf_file);
548 const relocs = fde.relocs(object);
552549 assert(relocs.len > 0); // Should this be an error? Things are completely broken anyhow if this trips...
553550 const rel = relocs[0];
554551 const ref = object.resolveSymbol(rel.r_sym(), elf_file);
src/link/Elf/gc.zig+28-21
......@@ -103,15 +103,20 @@ fn markLive(atom: *Atom, elf_file: *Elf) void {
103103 assert(atom.visited);
104104 const file = atom.file(elf_file).?;
105105
106 for (atom.fdes(elf_file)) |fde| {
107 for (fde.relocs(elf_file)[1..]) |rel| {
108 const ref = file.resolveSymbol(rel.r_sym(), elf_file);
109 const target_sym = elf_file.symbol(ref) orelse continue;
110 const target_atom = target_sym.atom(elf_file) orelse continue;
111 target_atom.alive = true;
112 gc_track_live_log.debug("{}marking live atom({d})", .{ track_live_level, target_atom.atom_index });
113 if (markAtom(target_atom)) markLive(target_atom, elf_file);
114 }
106 switch (file) {
107 .object => |object| {
108 for (atom.fdes(object)) |fde| {
109 for (fde.relocs(object)[1..]) |rel| {
110 const ref = file.resolveSymbol(rel.r_sym(), elf_file);
111 const target_sym = elf_file.symbol(ref) orelse continue;
112 const target_atom = target_sym.atom(elf_file) orelse continue;
113 target_atom.alive = true;
114 gc_track_live_log.debug("{}marking live atom({d})", .{ track_live_level, target_atom.atom_index });
115 if (markAtom(target_atom)) markLive(target_atom, elf_file);
116 }
117 }
118 },
119 else => {},
115120 }
116121
117122 for (atom.relocs(elf_file)) |rel| {
......@@ -135,23 +140,25 @@ fn mark(roots: std.ArrayList(*Atom), elf_file: *Elf) void {
135140 }
136141}
137142
138fn prune(elf_file: *Elf) void {
139 const pruneInFile = struct {
140 fn pruneInFile(file: File, ef: *Elf) void {
141 for (file.atoms()) |atom_index| {
142 const atom = file.atom(atom_index) orelse continue;
143 if (atom.alive and !atom.visited) {
144 atom.alive = false;
145 atom.markFdesDead(ef);
146 }
143fn pruneInFile(file: File) void {
144 for (file.atoms()) |atom_index| {
145 const atom = file.atom(atom_index) orelse continue;
146 if (atom.alive and !atom.visited) {
147 atom.alive = false;
148 switch (file) {
149 .object => |object| atom.markFdesDead(object),
150 else => {},
147151 }
148152 }
149 }.pruneInFile;
153 }
154}
155
156fn prune(elf_file: *Elf) void {
150157 if (elf_file.zigObjectPtr()) |zo| {
151 pruneInFile(zo.asFile(), elf_file);
158 pruneInFile(zo.asFile());
152159 }
153160 for (elf_file.objects.items) |index| {
154 pruneInFile(elf_file.file(index).?, elf_file);
161 pruneInFile(elf_file.file(index).?);
155162 }
156163}
157164
src/link/Elf/relocatable.zig+12-11
......@@ -233,8 +233,10 @@ fn parseArchiveStaticLibReportingFailure(elf_file: *Elf, path: Path) void {
233233
234234fn parseObjectStaticLib(elf_file: *Elf, path: Path) Elf.ParseError!void {
235235 const gpa = elf_file.base.comp.gpa;
236 const file_handles = &elf_file.file_handles;
237
236238 const handle = try path.root_dir.handle.openFile(path.sub_path, .{});
237 const fh = try elf_file.addFileHandle(handle);
239 const fh = try Elf.addFileHandle(gpa, file_handles, handle);
238240
239241 const index: File.Index = @intCast(try elf_file.files.addOne(gpa));
240242 elf_file.files.set(index, .{ .object = .{
......@@ -248,27 +250,26 @@ fn parseObjectStaticLib(elf_file: *Elf, path: Path) Elf.ParseError!void {
248250 try elf_file.objects.append(gpa, index);
249251
250252 const object = elf_file.file(index).?.object;
251 try object.parseAr(elf_file);
253 try object.parseAr(path, elf_file);
252254}
253255
254256fn parseArchiveStaticLib(elf_file: *Elf, path: Path) Elf.ParseError!void {
255257 const gpa = elf_file.base.comp.gpa;
258 const diags = &elf_file.base.comp.link_diags;
259 const file_handles = &elf_file.file_handles;
260
256261 const handle = try path.root_dir.handle.openFile(path.sub_path, .{});
257 const fh = try elf_file.addFileHandle(handle);
262 const fh = try Elf.addFileHandle(gpa, file_handles, handle);
258263
259 var archive = Archive{};
264 var archive = try Archive.parse(gpa, diags, file_handles, path, fh);
260265 defer archive.deinit(gpa);
261 try archive.parse(elf_file, path, fh);
262
263 const objects = try archive.objects.toOwnedSlice(gpa);
264 defer gpa.free(objects);
265266
266 for (objects) |extracted| {
267 const index = @as(File.Index, @intCast(try elf_file.files.addOne(gpa)));
267 for (archive.objects) |extracted| {
268 const index: File.Index = @intCast(try elf_file.files.addOne(gpa));
268269 elf_file.files.set(index, .{ .object = extracted });
269270 const object = &elf_file.files.items(.data)[index].object;
270271 object.index = index;
271 try object.parseAr(elf_file);
272 try object.parseAr(path, elf_file);
272273 try elf_file.objects.append(gpa, index);
273274 }
274275}