authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-02-12 21:45:15+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-02-12 23:07:51+01:00
loga94d5895cfbc7b2e695ba1edaad8f4af3d2081ab
treedc05ede8334a06346fc7b3339657a7132e5fd973
parentfad5e7a997344eddc45511df581472acaf0e880e

elf: do not prealloc input objects, pread selectively


9 files changed, 339 insertions(+), 281 deletions(-)

src/link/Elf.zig+58-21
......@@ -35,6 +35,10 @@ llvm_object: ?*LlvmObject = null,
3535/// Index of each input file also encodes the priority or precedence of one input file
3636/// over another.
3737files: std.MultiArrayList(File.Entry) = .{},
38/// Long-lived list of all file descriptors.
39/// We store them globally rather than per actual File so that we can re-use
40/// one file handle per every object file within an archive.
41file_handles: std.ArrayListUnmanaged(File.Handle) = .{},
3842zig_object_index: ?File.Index = null,
3943linker_defined_index: ?File.Index = null,
4044objects: std.ArrayListUnmanaged(File.Index) = .{},
......@@ -444,6 +448,11 @@ pub fn deinit(self: *Elf) void {
444448
445449 if (self.llvm_object) |llvm_object| llvm_object.deinit();
446450
451 for (self.file_handles.items) |fh| {
452 fh.close();
453 }
454 self.file_handles.deinit(gpa);
455
447456 for (self.files.items(.tags), self.files.items(.data)) |tag, *data| switch (tag) {
448457 .null => {},
449458 .zig_object => data.zig_object.deinit(gpa),
......@@ -1244,9 +1253,6 @@ pub fn flushModule(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node)
12441253 for (self.objects.items) |index| {
12451254 try self.file(index).?.object.init(self);
12461255 }
1247 for (self.shared_objects.items) |index| {
1248 try self.file(index).?.shared_object.init(self);
1249 }
12501256
12511257 if (comp.link_errors.items.len > 0) return error.FlushFailure;
12521258
......@@ -1463,7 +1469,7 @@ pub fn flushStaticLib(self: *Elf, comp: *Compilation, module_obj_path: ?[]const
14631469 for (files.items) |index| {
14641470 const file_ptr = self.file(index).?;
14651471 try file_ptr.updateArStrtab(gpa, &ar_strtab);
1466 file_ptr.updateArSize();
1472 try file_ptr.updateArSize(self);
14671473 }
14681474
14691475 // Update file offsets of contributing objects.
......@@ -1515,7 +1521,7 @@ pub fn flushStaticLib(self: *Elf, comp: *Compilation, module_obj_path: ?[]const
15151521 // Write object files
15161522 for (files.items) |index| {
15171523 if (!mem.isAligned(buffer.items.len, 2)) try buffer.writer().writeByte(0);
1518 try self.file(index).?.writeAr(buffer.writer());
1524 try self.file(index).?.writeAr(self, buffer.writer());
15191525 }
15201526
15211527 assert(buffer.items.len == total_size);
......@@ -1902,13 +1908,13 @@ fn parseObject(self: *Elf, path: []const u8) ParseError!void {
19021908 defer tracy.end();
19031909
19041910 const gpa = self.base.comp.gpa;
1905 const in_file = try std.fs.cwd().openFile(path, .{});
1906 defer in_file.close();
1907 const data = try in_file.readToEndAlloc(gpa, std.math.maxInt(u32));
1911 const handle = try std.fs.cwd().openFile(path, .{});
1912 const fh = try self.addFileHandle(handle);
1913
19081914 const index = @as(File.Index, @intCast(try self.files.addOne(gpa)));
19091915 self.files.set(index, .{ .object = .{
19101916 .path = try gpa.dupe(u8, path),
1911 .data = data,
1917 .file_handle = fh,
19121918 .index = index,
19131919 } });
19141920 try self.objects.append(gpa, index);
......@@ -1922,12 +1928,12 @@ fn parseArchive(self: *Elf, path: []const u8, must_link: bool) ParseError!void {
19221928 defer tracy.end();
19231929
19241930 const gpa = self.base.comp.gpa;
1925 const in_file = try std.fs.cwd().openFile(path, .{});
1926 defer in_file.close();
1927 const data = try in_file.readToEndAlloc(gpa, std.math.maxInt(u32));
1928 var archive = Archive{ .path = try gpa.dupe(u8, path), .data = data };
1931 const handle = try std.fs.cwd().openFile(path, .{});
1932 const fh = try self.addFileHandle(handle);
1933
1934 var archive = Archive{};
19291935 defer archive.deinit(gpa);
1930 try archive.parse(self);
1936 try archive.parse(self, path, fh);
19311937
19321938 const objects = try archive.objects.toOwnedSlice(gpa);
19331939 defer gpa.free(objects);
......@@ -1948,13 +1954,12 @@ fn parseSharedObject(self: *Elf, lib: SystemLib) ParseError!void {
19481954 defer tracy.end();
19491955
19501956 const gpa = self.base.comp.gpa;
1951 const in_file = try std.fs.cwd().openFile(lib.path, .{});
1952 defer in_file.close();
1953 const data = try in_file.readToEndAlloc(gpa, std.math.maxInt(u32));
1957 const handle = try std.fs.cwd().openFile(lib.path, .{});
1958 defer handle.close();
1959
19541960 const index = @as(File.Index, @intCast(try self.files.addOne(gpa)));
19551961 self.files.set(index, .{ .shared_object = .{
19561962 .path = try gpa.dupe(u8, lib.path),
1957 .data = data,
19581963 .index = index,
19591964 .needed = lib.needed,
19601965 .alive = lib.needed,
......@@ -1962,7 +1967,7 @@ fn parseSharedObject(self: *Elf, lib: SystemLib) ParseError!void {
19621967 try self.shared_objects.append(gpa, index);
19631968
19641969 const shared_object = self.file(index).?.shared_object;
1965 try shared_object.parse(self);
1970 try shared_object.parse(self, handle);
19661971}
19671972
19681973fn parseLdScript(self: *Elf, lib: SystemLib) ParseError!void {
......@@ -2135,7 +2140,7 @@ fn resolveSymbols(self: *Elf) void {
21352140 const cg = self.comdatGroup(cg_index);
21362141 const cg_owner = self.comdatGroupOwner(cg.owner);
21372142 if (cg_owner.file != index) {
2138 for (object.comdatGroupMembers(cg.shndx)) |shndx| {
2143 for (cg.comdatGroupMembers(self)) |shndx| {
21392144 const atom_index = object.atoms.items[shndx];
21402145 if (self.atom(atom_index)) |atom_ptr| {
21412146 atom_ptr.flags.alive = false;
......@@ -5862,6 +5867,19 @@ pub fn file(self: *Elf, index: File.Index) ?File {
58625867 };
58635868}
58645869
5870pub fn addFileHandle(self: *Elf, handle: std.fs.File) !File.HandleIndex {
5871 const gpa = self.base.comp.gpa;
5872 const index: File.HandleIndex = @intCast(self.file_handles.items.len);
5873 const fh = try self.file_handles.addOne(gpa);
5874 fh.* = handle;
5875 return index;
5876}
5877
5878pub fn fileHandle(self: Elf, index: File.HandleIndex) File.Handle {
5879 assert(index < self.file_handles.items.len);
5880 return self.file_handles.items[index];
5881}
5882
58655883/// Returns pointer-to-symbol described at sym_index.
58665884pub fn symbol(self: *Elf, sym_index: Symbol.Index) *Symbol {
58675885 return &self.symbols.items[sym_index];
......@@ -6395,6 +6413,15 @@ fn fmtDumpState(
63956413 }
63966414}
63976415
6416/// Caller owns the memory.
6417pub fn preadAllAlloc(allocator: Allocator, handle: std.fs.File, offset: usize, size: usize) ![]u8 {
6418 const buffer = try allocator.alloc(u8, size);
6419 errdefer allocator.free(buffer);
6420 const amt = try handle.preadAll(buffer, offset);
6421 if (amt != size) return error.InputOutput;
6422 return buffer;
6423}
6424
63986425/// Binary search
63996426pub fn bsearch(comptime T: type, haystack: []align(1) const T, predicate: anytype) usize {
64006427 if (!@hasDecl(@TypeOf(predicate), "predicate"))
......@@ -6441,12 +6468,22 @@ pub const base_tag: link.File.Tag = .elf;
64416468
64426469const ComdatGroupOwner = struct {
64436470 file: File.Index = 0,
6471
64446472 const Index = u32;
64456473};
64466474
64476475pub const ComdatGroup = struct {
64486476 owner: ComdatGroupOwner.Index,
6449 shndx: u16,
6477 file: File.Index,
6478 shndx: u32,
6479 members_start: u32,
6480 members_len: u32,
6481
6482 pub fn comdatGroupMembers(cg: ComdatGroup, elf_file: *Elf) []const u32 {
6483 const object = elf_file.file(cg.file).?.object;
6484 return object.comdat_group_data.items[cg.members_start..][0..cg.members_len];
6485 }
6486
64506487 pub const Index = u32;
64516488};
64526489
src/link/Elf/Archive.zig+32-24
......@@ -1,8 +1,5 @@
1path: []const u8,
2data: []const u8,
3
41objects: std.ArrayListUnmanaged(Object) = .{},
5strtab: []const u8 = &[0]u8{},
2strtab: std.ArrayListUnmanaged(u8) = .{},
63
74pub fn isArchive(path: []const u8) !bool {
85 const file = try std.fs.cwd().openFile(path, .{});
......@@ -14,68 +11,79 @@ pub fn isArchive(path: []const u8) !bool {
1411}
1512
1613pub fn deinit(self: *Archive, allocator: Allocator) void {
17 allocator.free(self.path);
18 allocator.free(self.data);
1914 self.objects.deinit(allocator);
15 self.strtab.deinit(allocator);
2016}
2117
22pub fn parse(self: *Archive, elf_file: *Elf) !void {
18pub fn parse(self: *Archive, elf_file: *Elf, path: []const u8, handle_index: File.HandleIndex) !void {
2319 const comp = elf_file.base.comp;
2420 const gpa = comp.gpa;
21 const handle = elf_file.fileHandle(handle_index);
22 const size = (try handle.stat()).size;
2523
26 var stream = std.io.fixedBufferStream(self.data);
27 const reader = stream.reader();
24 const reader = handle.reader();
2825 _ = try reader.readBytesNoEof(elf.ARMAG.len);
2926
27 var pos: usize = elf.ARMAG.len;
3028 while (true) {
31 if (stream.pos >= self.data.len) break;
32 if (!mem.isAligned(stream.pos, 2)) stream.pos += 1;
29 if (pos >= size) break;
30 if (!mem.isAligned(pos, 2)) {
31 try handle.seekBy(1);
32 pos += 1;
33 }
3334
3435 const hdr = try reader.readStruct(elf.ar_hdr);
36 pos += @sizeOf(elf.ar_hdr);
3537
3638 if (!mem.eql(u8, &hdr.ar_fmag, elf.ARFMAG)) {
37 try elf_file.reportParseError(self.path, "invalid archive header delimiter: {s}", .{
39 try elf_file.reportParseError(path, "invalid archive header delimiter: {s}", .{
3840 std.fmt.fmtSliceEscapeLower(&hdr.ar_fmag),
3941 });
4042 return error.MalformedArchive;
4143 }
4244
43 const size = try hdr.size();
45 const obj_size = try hdr.size();
4446 defer {
45 _ = stream.seekBy(size) catch {};
47 _ = handle.seekBy(obj_size) catch {};
48 pos += obj_size;
4649 }
4750
4851 if (hdr.isSymtab() or hdr.isSymtab64()) continue;
4952 if (hdr.isStrtab()) {
50 self.strtab = self.data[stream.pos..][0..size];
53 try self.strtab.resize(gpa, obj_size);
54 const amt = try handle.preadAll(self.strtab.items, pos);
55 if (amt != obj_size) return error.InputOutput;
5156 continue;
5257 }
5358 if (hdr.isSymdef() or hdr.isSymdefSorted()) continue;
5459
5560 const name = if (hdr.name()) |name|
56 try gpa.dupe(u8, name)
61 name
5762 else if (try hdr.nameOffset()) |off|
58 try gpa.dupe(u8, self.getString(off))
63 self.getString(off)
5964 else
6065 unreachable;
6166
6267 const object = Object{
63 .archive = try gpa.dupe(u8, self.path),
64 .path = name,
65 .data = try gpa.dupe(u8, self.data[stream.pos..][0..size]),
68 .archive = .{
69 .path = try gpa.dupe(u8, path),
70 .offset = pos,
71 },
72 .path = try gpa.dupe(u8, name),
73 .file_handle = handle_index,
6674 .index = undefined,
6775 .alive = false,
6876 };
6977
70 log.debug("extracting object '{s}' from archive '{s}'", .{ object.path, self.path });
78 log.debug("extracting object '{s}' from archive '{s}'", .{ object.path, path });
7179
7280 try self.objects.append(gpa, object);
7381 }
7482}
7583
7684fn getString(self: Archive, off: u32) []const u8 {
77 assert(off < self.strtab.len);
78 const name = mem.sliceTo(@as([*:'\n']const u8, @ptrCast(self.strtab.ptr + off)), 0);
85 assert(off < self.strtab.items.len);
86 const name = mem.sliceTo(@as([*:'\n']const u8, @ptrCast(self.strtab.items.ptr + off)), 0);
7987 return name[0 .. name.len - 1];
8088}
8189
......@@ -86,7 +94,7 @@ pub fn setArHdr(opts: struct {
8694 name: []const u8,
8795 name_off: u32,
8896 },
89 size: u32,
97 size: usize,
9098}) elf.ar_hdr {
9199 var hdr: elf.ar_hdr = .{
92100 .ar_name = undefined,
src/link/Elf/Atom.zig+8-2
......@@ -22,6 +22,12 @@ output_section_index: u16 = 0,
2222/// Index of the input section containing this atom's relocs.
2323relocs_section_index: u32 = 0,
2424
25/// Start index of the relocations belonging to this atom.
26rel_index: u32 = 0,
27
28/// Number of relocations belonging to this atom.
29rel_num: u32 = 0,
30
2531/// Index of this atom in the linker's atoms table.
2632atom_index: Index = 0,
2733
......@@ -52,7 +58,7 @@ pub fn file(self: Atom, elf_file: *Elf) ?File {
5258 return elf_file.file(self.file_index);
5359}
5460
55pub fn inputShdr(self: Atom, elf_file: *Elf) Object.ElfShdr {
61pub fn inputShdr(self: Atom, elf_file: *Elf) elf.Elf64_Shdr {
5662 return switch (self.file(elf_file).?) {
5763 .object => |x| x.shdrs.items[self.input_section_index],
5864 .zig_object => |x| x.inputShdr(self.atom_index, elf_file),
......@@ -289,7 +295,7 @@ pub fn relocs(self: Atom, elf_file: *Elf) []align(1) const elf.Elf64_Rela {
289295 const shndx = self.relocsShndx() orelse return &[0]elf.Elf64_Rela{};
290296 return switch (self.file(elf_file).?) {
291297 .zig_object => |x| x.relocs.items[shndx].items,
292 .object => |x| x.getRelocs(shndx),
298 .object => |x| x.relocs.items[self.rel_index..][0..self.rel_num],
293299 else => unreachable,
294300 };
295301}
src/link/Elf/Object.zig+125-115
......@@ -1,10 +1,10 @@
1archive: ?[]const u8 = null,
1archive: ?InArchive = null,
22path: []const u8,
3data: []const u8,
3file_handle: File.HandleIndex,
44index: File.Index,
55
66header: ?elf.Elf64_Ehdr = null,
7shdrs: std.ArrayListUnmanaged(ElfShdr) = .{},
7shdrs: std.ArrayListUnmanaged(elf.Elf64_Shdr) = .{},
88
99symtab: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{},
1010strtab: std.ArrayListUnmanaged(u8) = .{},
......@@ -12,9 +12,12 @@ first_global: ?Symbol.Index = null,
1212symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
1313atoms: std.ArrayListUnmanaged(Atom.Index) = .{},
1414comdat_groups: std.ArrayListUnmanaged(Elf.ComdatGroup.Index) = .{},
15comdat_group_data: std.ArrayListUnmanaged(u32) = .{},
16relocs: std.ArrayListUnmanaged(elf.Elf64_Rela) = .{},
1517
1618fdes: std.ArrayListUnmanaged(Fde) = .{},
1719cies: std.ArrayListUnmanaged(Cie) = .{},
20eh_frame_data: std.ArrayListUnmanaged(u8) = .{},
1821
1922alive: bool = true,
2023num_dynrelocs: u32 = 0,
......@@ -35,24 +38,30 @@ pub fn isObject(path: []const u8) !bool {
3538}
3639
3740pub fn deinit(self: *Object, allocator: Allocator) void {
38 if (self.archive) |path| allocator.free(path);
41 if (self.archive) |*ar| allocator.free(ar.path);
3942 allocator.free(self.path);
40 allocator.free(self.data);
4143 self.shdrs.deinit(allocator);
4244 self.symtab.deinit(allocator);
4345 self.strtab.deinit(allocator);
4446 self.symbols.deinit(allocator);
4547 self.atoms.deinit(allocator);
4648 self.comdat_groups.deinit(allocator);
49 self.comdat_group_data.deinit(allocator);
50 self.relocs.deinit(allocator);
4751 self.fdes.deinit(allocator);
4852 self.cies.deinit(allocator);
53 self.eh_frame_data.deinit(allocator);
4954}
5055
5156pub fn parse(self: *Object, elf_file: *Elf) !void {
52 var stream = std.io.fixedBufferStream(self.data);
53 const reader = stream.reader();
57 const gpa = elf_file.base.comp.gpa;
58 const offset = if (self.archive) |ar| ar.offset else 0;
59 const handle = elf_file.fileHandle(self.file_handle);
60 const file_size = (try handle.stat()).size;
5461
55 self.header = try reader.readStruct(elf.Elf64_Ehdr);
62 const header_buffer = try Elf.preadAllAlloc(gpa, handle, offset, @sizeOf(elf.Elf64_Ehdr));
63 defer gpa.free(header_buffer);
64 self.header = @as(*align(1) const elf.Elf64_Ehdr, @ptrCast(header_buffer)).*;
5665
5766 const target = elf_file.base.comp.root_mod.resolved_target.result;
5867 if (target.cpu.arch != self.header.?.e_machine.toTargetCpuArch().?) {
......@@ -66,12 +75,10 @@ pub fn parse(self: *Object, elf_file: *Elf) !void {
6675
6776 if (self.header.?.e_shnum == 0) return;
6877
69 const comp = elf_file.base.comp;
70 const gpa = comp.gpa;
71
72 if (self.data.len < self.header.?.e_shoff or
73 self.data.len < self.header.?.e_shoff + @as(u64, @intCast(self.header.?.e_shnum)) * @sizeOf(elf.Elf64_Shdr))
74 {
78 const shoff = math.cast(usize, self.header.?.e_shoff) orelse return error.Overflow;
79 const shnum = math.cast(usize, self.header.?.e_shnum) orelse return error.Overflow;
80 const shsize = shnum * @sizeOf(elf.Elf64_Shdr);
81 if (file_size < offset + shoff or file_size < offset + shoff + shsize) {
7582 try elf_file.reportParseError2(
7683 self.index,
7784 "corrupt header: section header table extends past the end of file",
......@@ -80,25 +87,23 @@ pub fn parse(self: *Object, elf_file: *Elf) !void {
8087 return error.MalformedObject;
8188 }
8289
83 const shoff = math.cast(usize, self.header.?.e_shoff) orelse return error.Overflow;
84 const shdrs = @as(
85 [*]align(1) const elf.Elf64_Shdr,
86 @ptrCast(self.data.ptr + shoff),
87 )[0..self.header.?.e_shnum];
88 try self.shdrs.ensureTotalCapacityPrecise(gpa, shdrs.len);
90 const shdrs_buffer = try Elf.preadAllAlloc(gpa, handle, offset + shoff, shsize);
91 defer gpa.free(shdrs_buffer);
92 const shdrs = @as([*]align(1) const elf.Elf64_Shdr, @ptrCast(shdrs_buffer.ptr))[0..shnum];
93 try self.shdrs.appendUnalignedSlice(gpa, shdrs);
8994
90 for (shdrs) |shdr| {
95 for (self.shdrs.items) |shdr| {
9196 if (shdr.sh_type != elf.SHT_NOBITS) {
92 if (self.data.len < shdr.sh_offset or self.data.len < shdr.sh_offset + shdr.sh_size) {
97 if (file_size < offset + shdr.sh_offset or file_size < offset + shdr.sh_offset + shdr.sh_size) {
9398 try elf_file.reportParseError2(self.index, "corrupt section: extends past the end of file", .{});
9499 return error.MalformedObject;
95100 }
96101 }
97 self.shdrs.appendAssumeCapacity(try ElfShdr.fromElf64Shdr(shdr));
98102 }
99103
100 const shstrtab = self.shdrContents(self.header.?.e_shstrndx);
101 for (shdrs) |shdr| {
104 const shstrtab = try self.preadShdrContentsAlloc(gpa, handle, self.header.?.e_shstrndx);
105 defer gpa.free(shstrtab);
106 for (self.shdrs.items) |shdr| {
102107 if (shdr.sh_name >= shstrtab.len) {
103108 try elf_file.reportParseError2(self.index, "corrupt section name offset", .{});
104109 return error.MalformedObject;
......@@ -112,10 +117,11 @@ pub fn parse(self: *Object, elf_file: *Elf) !void {
112117 } else null;
113118
114119 if (symtab_index) |index| {
115 const shdr = shdrs[index];
120 const shdr = self.shdrs.items[index];
116121 self.first_global = shdr.sh_info;
117122
118 const raw_symtab = self.shdrContents(index);
123 const raw_symtab = try self.preadShdrContentsAlloc(gpa, handle, index);
124 defer gpa.free(raw_symtab);
119125 const nsyms = math.divExact(usize, raw_symtab.len, @sizeOf(elf.Elf64_Sym)) catch {
120126 try elf_file.reportParseError2(self.index, "symbol table not evenly divisible", .{});
121127 return error.MalformedObject;
......@@ -123,7 +129,9 @@ pub fn parse(self: *Object, elf_file: *Elf) !void {
123129 const symtab = @as([*]align(1) const elf.Elf64_Sym, @ptrCast(raw_symtab.ptr))[0..nsyms];
124130
125131 const strtab_bias = @as(u32, @intCast(self.strtab.items.len));
126 try self.strtab.appendSlice(gpa, self.shdrContents(@as(u16, @intCast(shdr.sh_link))));
132 const strtab = try self.preadShdrContentsAlloc(gpa, handle, shdr.sh_link);
133 defer gpa.free(strtab);
134 try self.strtab.appendSlice(gpa, strtab);
127135
128136 try self.symtab.ensureUnusedCapacity(gpa, symtab.len);
129137 for (symtab) |sym| {
......@@ -138,22 +146,23 @@ pub fn parse(self: *Object, elf_file: *Elf) !void {
138146}
139147
140148pub fn init(self: *Object, elf_file: *Elf) !void {
141 try self.initAtoms(elf_file);
142 try self.initSymtab(elf_file);
149 const gpa = elf_file.base.comp.gpa;
150 const handle = elf_file.fileHandle(self.file_handle);
151
152 try self.initAtoms(gpa, handle, elf_file);
153 try self.initSymtab(gpa, elf_file);
143154
144155 for (self.shdrs.items, 0..) |shdr, i| {
145156 const atom = elf_file.atom(self.atoms.items[i]) orelse continue;
146157 if (!atom.flags.alive) continue;
147158 if (shdr.sh_type == elf.SHT_X86_64_UNWIND or mem.eql(u8, atom.name(elf_file), ".eh_frame"))
148 try self.parseEhFrame(@as(u16, @intCast(i)), elf_file);
159 try self.parseEhFrame(gpa, handle, @as(u32, @intCast(i)), elf_file);
149160 }
150161}
151162
152fn initAtoms(self: *Object, elf_file: *Elf) !void {
153 const comp = elf_file.base.comp;
154 const gpa = comp.gpa;
163fn initAtoms(self: *Object, allocator: Allocator, handle: std.fs.File, elf_file: *Elf) !void {
155164 const shdrs = self.shdrs.items;
156 try self.atoms.resize(gpa, shdrs.len);
165 try self.atoms.resize(allocator, shdrs.len);
157166 @memset(self.atoms.items, 0);
158167
159168 for (shdrs, 0..) |shdr, i| {
......@@ -177,8 +186,9 @@ fn initAtoms(self: *Object, elf_file: *Elf) !void {
177186 break :blk self.getString(group_info_sym.st_name);
178187 };
179188
180 const shndx = @as(u16, @intCast(i));
181 const group_raw_data = self.shdrContents(shndx);
189 const shndx = @as(u32, @intCast(i));
190 const group_raw_data = try self.preadShdrContentsAlloc(allocator, handle, shndx);
191 defer allocator.free(group_raw_data);
182192 const group_nmembers = @divExact(group_raw_data.len, @sizeOf(u32));
183193 const group_members = @as([*]align(1) const u32, @ptrCast(group_raw_data.ptr))[0..group_nmembers];
184194
......@@ -188,14 +198,20 @@ fn initAtoms(self: *Object, elf_file: *Elf) !void {
188198 continue;
189199 }
190200
201 const group_start = @as(u32, @intCast(self.comdat_group_data.items.len));
202 try self.comdat_group_data.appendUnalignedSlice(allocator, group_members[1..]);
203
191204 const gop = try elf_file.getOrCreateComdatGroupOwner(group_signature);
192205 const comdat_group_index = try elf_file.addComdatGroup();
193206 const comdat_group = elf_file.comdatGroup(comdat_group_index);
194207 comdat_group.* = .{
195208 .owner = gop.index,
209 .file = self.index,
196210 .shndx = shndx,
211 .members_start = group_start,
212 .members_len = @intCast(group_nmembers - 1),
197213 };
198 try self.comdat_groups.append(gpa, comdat_group_index);
214 try self.comdat_groups.append(allocator, comdat_group_index);
199215 },
200216
201217 elf.SHT_SYMTAB_SHNDX => @panic("TODO SHT_SYMTAB_SHNDX"),
......@@ -210,7 +226,7 @@ fn initAtoms(self: *Object, elf_file: *Elf) !void {
210226 else => {
211227 const shndx = @as(u16, @intCast(i));
212228 if (self.skipShdr(shndx, elf_file)) continue;
213 try self.addAtom(shdr, shndx, elf_file);
229 try self.addAtom(allocator, handle, shdr, shndx, elf_file);
214230 },
215231 }
216232 }
......@@ -220,14 +236,19 @@ fn initAtoms(self: *Object, elf_file: *Elf) !void {
220236 elf.SHT_REL, elf.SHT_RELA => {
221237 const atom_index = self.atoms.items[shdr.sh_info];
222238 if (elf_file.atom(atom_index)) |atom| {
223 atom.relocs_section_index = @as(u16, @intCast(i));
239 const relocs = try self.preadRelocsAlloc(allocator, handle, @intCast(i));
240 defer allocator.free(relocs);
241 atom.relocs_section_index = @intCast(i);
242 atom.rel_index = @intCast(self.relocs.items.len);
243 atom.rel_num = @intCast(relocs.len);
244 try self.relocs.appendUnalignedSlice(allocator, relocs);
224245 }
225246 },
226247 else => {},
227248 };
228249}
229250
230fn addAtom(self: *Object, shdr: ElfShdr, shndx: u16, elf_file: *Elf) error{OutOfMemory}!void {
251fn addAtom(self: *Object, allocator: Allocator, handle: std.fs.File, shdr: elf.Elf64_Shdr, shndx: u32, elf_file: *Elf) !void {
231252 const atom_index = try elf_file.addAtom();
232253 const atom = elf_file.atom(atom_index).?;
233254 atom.atom_index = atom_index;
......@@ -237,7 +258,8 @@ fn addAtom(self: *Object, shdr: ElfShdr, shndx: u16, elf_file: *Elf) error{OutOf
237258 self.atoms.items[shndx] = atom_index;
238259
239260 if (shdr.sh_flags & elf.SHF_COMPRESSED != 0) {
240 const data = self.shdrContents(shndx);
261 const data = try self.preadShdrContentsAlloc(allocator, handle, shndx);
262 defer allocator.free(data);
241263 const chdr = @as(*align(1) const elf.Elf64_Chdr, @ptrCast(data.ptr)).*;
242264 atom.size = chdr.ch_size;
243265 atom.alignment = Alignment.fromNonzeroByteUnits(chdr.ch_addralign);
......@@ -247,7 +269,7 @@ fn addAtom(self: *Object, shdr: ElfShdr, shndx: u16, elf_file: *Elf) error{OutOf
247269 }
248270}
249271
250fn initOutputSection(self: Object, elf_file: *Elf, shdr: ElfShdr) error{OutOfMemory}!u16 {
272fn initOutputSection(self: Object, elf_file: *Elf, shdr: elf.Elf64_Shdr) error{OutOfMemory}!u16 {
251273 const name = blk: {
252274 const name = self.getString(shdr.sh_name);
253275 if (elf_file.base.isRelocatable()) break :blk name;
......@@ -310,12 +332,10 @@ fn skipShdr(self: *Object, index: u16, elf_file: *Elf) bool {
310332 return ignore;
311333}
312334
313fn initSymtab(self: *Object, elf_file: *Elf) !void {
314 const comp = elf_file.base.comp;
315 const gpa = comp.gpa;
335fn initSymtab(self: *Object, allocator: Allocator, elf_file: *Elf) !void {
316336 const first_global = self.first_global orelse self.symtab.items.len;
317337
318 try self.symbols.ensureTotalCapacityPrecise(gpa, self.symtab.items.len);
338 try self.symbols.ensureTotalCapacityPrecise(allocator, self.symtab.items.len);
319339
320340 for (self.symtab.items[0..first_global], 0..) |sym, i| {
321341 const index = try elf_file.addSymbol();
......@@ -335,19 +355,24 @@ fn initSymtab(self: *Object, elf_file: *Elf) !void {
335355 }
336356}
337357
338fn parseEhFrame(self: *Object, shndx: u16, elf_file: *Elf) !void {
358fn parseEhFrame(self: *Object, allocator: Allocator, handle: std.fs.File, shndx: u32, elf_file: *Elf) !void {
339359 const relocs_shndx = for (self.shdrs.items, 0..) |shdr, i| switch (shdr.sh_type) {
340 elf.SHT_RELA => if (shdr.sh_info == shndx) break @as(u16, @intCast(i)),
360 elf.SHT_RELA => if (shdr.sh_info == shndx) break @as(u32, @intCast(i)),
341361 else => {},
342362 } else {
363 // TODO: convert into an error
343364 log.debug("{s}: missing reloc section for unwind info section", .{self.fmtPath()});
344365 return;
345366 };
346367
347 const comp = elf_file.base.comp;
348 const gpa = comp.gpa;
349 const raw = self.shdrContents(shndx);
350 const relocs = self.getRelocs(relocs_shndx);
368 const raw = try self.preadShdrContentsAlloc(allocator, handle, shndx);
369 defer allocator.free(raw);
370 const data_start = @as(u32, @intCast(self.eh_frame_data.items.len));
371 try self.eh_frame_data.appendSlice(allocator, raw);
372 const relocs = try self.preadRelocsAlloc(allocator, handle, relocs_shndx);
373 defer allocator.free(relocs);
374 const rel_start = @as(u32, @intCast(self.relocs.items.len));
375 try self.relocs.appendUnalignedSlice(allocator, relocs);
351376 const fdes_start = self.fdes.items.len;
352377 const cies_start = self.cies.items.len;
353378
......@@ -355,22 +380,20 @@ fn parseEhFrame(self: *Object, shndx: u16, elf_file: *Elf) !void {
355380 while (try it.next()) |rec| {
356381 const rel_range = filterRelocs(relocs, rec.offset, rec.size + 4);
357382 switch (rec.tag) {
358 .cie => try self.cies.append(gpa, .{
359 .offset = rec.offset,
383 .cie => try self.cies.append(allocator, .{
384 .offset = data_start + rec.offset,
360385 .size = rec.size,
361 .rel_index = @as(u32, @intCast(rel_range.start)),
386 .rel_index = rel_start + @as(u32, @intCast(rel_range.start)),
362387 .rel_num = @as(u32, @intCast(rel_range.len)),
363 .rel_section_index = relocs_shndx,
364388 .input_section_index = shndx,
365389 .file_index = self.index,
366390 }),
367 .fde => try self.fdes.append(gpa, .{
368 .offset = rec.offset,
391 .fde => try self.fdes.append(allocator, .{
392 .offset = data_start + rec.offset,
369393 .size = rec.size,
370394 .cie_index = undefined,
371 .rel_index = @as(u32, @intCast(rel_range.start)),
395 .rel_index = rel_start + @as(u32, @intCast(rel_range.start)),
372396 .rel_num = @as(u32, @intCast(rel_range.len)),
373 .rel_section_index = relocs_shndx,
374397 .input_section_index = shndx,
375398 .file_index = self.index,
376399 }),
......@@ -773,21 +796,30 @@ pub fn updateArSymtab(self: Object, ar_symtab: *Archive.ArSymtab, elf_file: *Elf
773796 }
774797}
775798
776pub fn updateArSize(self: *Object) void {
777 self.output_ar_state.size = self.data.len;
799pub fn updateArSize(self: *Object, elf_file: *Elf) !void {
800 const handle = elf_file.fileHandle(self.file_handle);
801 const size = (try handle.stat()).size;
802 self.output_ar_state.size = size;
778803}
779804
780pub fn writeAr(self: Object, writer: anytype) !void {
805pub fn writeAr(self: Object, elf_file: *Elf, writer: anytype) !void {
806 const size = std.math.cast(usize, self.output_ar_state.size) orelse return error.Overflow;
781807 const name = self.path;
782808 const hdr = Archive.setArHdr(.{
783809 .name = if (name.len <= Archive.max_member_name_len)
784810 .{ .name = name }
785811 else
786812 .{ .name_off = self.output_ar_state.name_off },
787 .size = @intCast(self.data.len),
813 .size = size,
788814 });
789815 try writer.writeAll(mem.asBytes(&hdr));
790 try writer.writeAll(self.data);
816 const handle = elf_file.fileHandle(self.file_handle);
817 const gpa = elf_file.base.comp.gpa;
818 const data = try gpa.alloc(u8, size);
819 defer gpa.free(data);
820 const amt = try handle.preadAll(data, 0);
821 if (amt != size) return error.InputOutput;
822 try writer.writeAll(data);
791823}
792824
793825pub fn updateSymtabSize(self: *Object, elf_file: *Elf) !void {
......@@ -859,12 +891,6 @@ pub fn globals(self: Object) []const Symbol.Index {
859891 return self.symbols.items[start..];
860892}
861893
862pub fn shdrContents(self: Object, index: u32) []const u8 {
863 assert(index < self.shdrs.items.len);
864 const shdr = self.shdrs.items[index];
865 return self.data[shdr.sh_offset..][0..shdr.sh_size];
866}
867
868894/// Returns atom's code and optionally uncompresses data if required (for compressed sections).
869895/// Caller owns the memory.
870896pub fn codeDecompressAlloc(self: Object, elf_file: *Elf, atom_index: Atom.Index) ![]u8 {
......@@ -872,8 +898,11 @@ pub fn codeDecompressAlloc(self: Object, elf_file: *Elf, atom_index: Atom.Index)
872898 const gpa = comp.gpa;
873899 const atom_ptr = elf_file.atom(atom_index).?;
874900 assert(atom_ptr.file_index == self.index);
875 const data = self.shdrContents(atom_ptr.input_section_index);
876901 const shdr = atom_ptr.inputShdr(elf_file);
902 const handle = elf_file.fileHandle(self.file_handle);
903 const data = try self.preadShdrContentsAlloc(gpa, handle, atom_ptr.input_section_index);
904 defer if (shdr.sh_flags & elf.SHF_COMPRESSED != 0) gpa.free(data);
905
877906 if (shdr.sh_flags & elf.SHF_COMPRESSED != 0) {
878907 const chdr = @as(*align(1) const elf.Elf64_Chdr, @ptrCast(data.ptr)).*;
879908 switch (chdr.ch_type) {
......@@ -892,31 +921,35 @@ pub fn codeDecompressAlloc(self: Object, elf_file: *Elf, atom_index: Atom.Index)
892921 },
893922 else => @panic("TODO unhandled compression scheme"),
894923 }
895 } else return gpa.dupe(u8, data);
896}
924 }
897925
898pub fn comdatGroupMembers(self: *Object, index: u16) []align(1) const u32 {
899 const raw = self.shdrContents(index);
900 const nmembers = @divExact(raw.len, @sizeOf(u32));
901 const members = @as([*]align(1) const u32, @ptrCast(raw.ptr))[1..nmembers];
902 return members;
926 return data;
903927}
904928
905929pub fn asFile(self: *Object) File {
906930 return .{ .object = self };
907931}
908932
909pub fn getRelocs(self: *Object, shndx: u32) []align(1) const elf.Elf64_Rela {
910 const raw = self.shdrContents(shndx);
911 const num = @divExact(raw.len, @sizeOf(elf.Elf64_Rela));
912 return @as([*]align(1) const elf.Elf64_Rela, @ptrCast(raw.ptr))[0..num];
913}
914
915933pub fn getString(self: Object, off: u32) [:0]const u8 {
916934 assert(off < self.strtab.items.len);
917935 return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.strtab.items.ptr + off)), 0);
918936}
919937
938/// Caller owns the memory.
939fn preadShdrContentsAlloc(self: Object, allocator: Allocator, handle: std.fs.File, index: u32) ![]u8 {
940 assert(index < self.shdrs.items.len);
941 const offset = if (self.archive) |ar| ar.offset else 0;
942 const shdr = self.shdrs.items[index];
943 return Elf.preadAllAlloc(allocator, handle, offset + shdr.sh_offset, shdr.sh_size);
944}
945
946/// Caller owns the memory.
947fn preadRelocsAlloc(self: Object, allocator: Allocator, handle: std.fs.File, shndx: u32) ![]align(1) const elf.Elf64_Rela {
948 const raw = try self.preadShdrContentsAlloc(allocator, handle, shndx);
949 const num = @divExact(raw.len, @sizeOf(elf.Elf64_Rela));
950 return @as([*]align(1) const elf.Elf64_Rela, @ptrCast(raw.ptr))[0..num];
951}
952
920953pub fn format(
921954 self: *Object,
922955 comptime unused_fmt_string: []const u8,
......@@ -1053,7 +1086,7 @@ fn formatComdatGroups(
10531086 const cg_owner = elf_file.comdatGroupOwner(cg.owner);
10541087 if (cg_owner.file != object.index) continue;
10551088 try writer.print(" COMDAT({d})\n", .{cg_index});
1056 const cg_members = object.comdatGroupMembers(cg.shndx);
1089 const cg_members = cg.comdatGroupMembers(elf_file);
10571090 for (cg_members) |shndx| {
10581091 const atom_index = object.atoms.items[shndx];
10591092 const atom = elf_file.atom(atom_index) orelse continue;
......@@ -1074,40 +1107,17 @@ fn formatPath(
10741107) !void {
10751108 _ = unused_fmt_string;
10761109 _ = options;
1077 if (object.archive) |path| {
1078 try writer.writeAll(path);
1110 if (object.archive) |ar| {
1111 try writer.writeAll(ar.path);
10791112 try writer.writeByte('(');
10801113 try writer.writeAll(object.path);
10811114 try writer.writeByte(')');
10821115 } else try writer.writeAll(object.path);
10831116}
10841117
1085pub const ElfShdr = struct {
1086 sh_name: u32,
1087 sh_type: u32,
1088 sh_flags: u64,
1089 sh_addr: u64,
1090 sh_offset: usize,
1091 sh_size: usize,
1092 sh_link: u32,
1093 sh_info: u32,
1094 sh_addralign: u64,
1095 sh_entsize: u64,
1096
1097 pub fn fromElf64Shdr(shdr: elf.Elf64_Shdr) error{Overflow}!ElfShdr {
1098 return .{
1099 .sh_name = shdr.sh_name,
1100 .sh_type = shdr.sh_type,
1101 .sh_flags = shdr.sh_flags,
1102 .sh_addr = shdr.sh_addr,
1103 .sh_offset = math.cast(usize, shdr.sh_offset) orelse return error.Overflow,
1104 .sh_size = math.cast(usize, shdr.sh_size) orelse return error.Overflow,
1105 .sh_link = shdr.sh_link,
1106 .sh_info = shdr.sh_info,
1107 .sh_addralign = shdr.sh_addralign,
1108 .sh_entsize = shdr.sh_entsize,
1109 };
1110 }
1118const InArchive = struct {
1119 path: []const u8,
1120 offset: u64,
11111121};
11121122
11131123const Object = @This();
src/link/Elf/SharedObject.zig+88-77
......@@ -1,22 +1,18 @@
11path: []const u8,
2data: []const u8,
32index: File.Index,
43
54header: ?elf.Elf64_Ehdr = null,
6shdrs: std.ArrayListUnmanaged(ElfShdr) = .{},
5shdrs: std.ArrayListUnmanaged(elf.Elf64_Shdr) = .{},
76
87symtab: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{},
98strtab: std.ArrayListUnmanaged(u8) = .{},
109/// Version symtab contains version strings of the symbols if present.
1110versyms: std.ArrayListUnmanaged(elf.Elf64_Versym) = .{},
1211verstrings: std.ArrayListUnmanaged(u32) = .{},
12
1313symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
1414aliases: ?std.ArrayListUnmanaged(u32) = null,
15
16dynsym_sect_index: ?u16 = null,
17dynamic_sect_index: ?u16 = null,
18versym_sect_index: ?u16 = null,
19verdef_sect_index: ?u16 = null,
15dynamic_table: std.ArrayListUnmanaged(elf.Elf64_Dyn) = .{},
2016
2117needed: bool,
2218alive: bool,
......@@ -36,23 +32,24 @@ pub fn isSharedObject(path: []const u8) !bool {
3632
3733pub fn deinit(self: *SharedObject, allocator: Allocator) void {
3834 allocator.free(self.path);
39 allocator.free(self.data);
35 self.shdrs.deinit(allocator);
4036 self.symtab.deinit(allocator);
4137 self.strtab.deinit(allocator);
4238 self.versyms.deinit(allocator);
4339 self.verstrings.deinit(allocator);
4440 self.symbols.deinit(allocator);
4541 if (self.aliases) |*aliases| aliases.deinit(allocator);
46 self.shdrs.deinit(allocator);
42 self.dynamic_table.deinit(allocator);
4743}
4844
49pub fn parse(self: *SharedObject, elf_file: *Elf) !void {
45pub fn parse(self: *SharedObject, elf_file: *Elf, handle: std.fs.File) !void {
5046 const comp = elf_file.base.comp;
5147 const gpa = comp.gpa;
52 var stream = std.io.fixedBufferStream(self.data);
53 const reader = stream.reader();
48 const file_size = (try handle.stat()).size;
5449
55 self.header = try reader.readStruct(elf.Elf64_Ehdr);
50 const header_buffer = try Elf.preadAllAlloc(gpa, handle, 0, @sizeOf(elf.Elf64_Ehdr));
51 defer gpa.free(header_buffer);
52 self.header = @as(*align(1) const elf.Elf64_Ehdr, @ptrCast(header_buffer)).*;
5653
5754 const target = elf_file.base.comp.root_mod.resolved_target.result;
5855 if (target.cpu.arch != self.header.?.e_machine.toTargetCpuArch().?) {
......@@ -64,9 +61,10 @@ pub fn parse(self: *SharedObject, elf_file: *Elf) !void {
6461 return error.InvalidCpuArch;
6562 }
6663
67 if (self.data.len < self.header.?.e_shoff or
68 self.data.len < self.header.?.e_shoff + @as(u64, @intCast(self.header.?.e_shnum)) * @sizeOf(elf.Elf64_Shdr))
69 {
64 const shoff = std.math.cast(usize, self.header.?.e_shoff) orelse return error.Overflow;
65 const shnum = std.math.cast(usize, self.header.?.e_shnum) orelse return error.Overflow;
66 const shsize = shnum * @sizeOf(elf.Elf64_Shdr);
67 if (file_size < shoff or file_size < shoff + shsize) {
7068 try elf_file.reportParseError2(
7169 self.index,
7270 "corrupted header: section header table extends past the end of file",
......@@ -75,45 +73,84 @@ pub fn parse(self: *SharedObject, elf_file: *Elf) !void {
7573 return error.MalformedObject;
7674 }
7775
78 const shoff = std.math.cast(usize, self.header.?.e_shoff) orelse return error.Overflow;
79
80 const shdrs = @as(
81 [*]align(1) const elf.Elf64_Shdr,
82 @ptrCast(self.data.ptr + shoff),
83 )[0..self.header.?.e_shnum];
84 try self.shdrs.ensureTotalCapacityPrecise(gpa, shdrs.len);
76 const shdrs_buffer = try Elf.preadAllAlloc(gpa, handle, shoff, shsize);
77 defer gpa.free(shdrs_buffer);
78 const shdrs = @as([*]align(1) const elf.Elf64_Shdr, @ptrCast(shdrs_buffer.ptr))[0..shnum];
79 try self.shdrs.appendUnalignedSlice(gpa, shdrs);
8580
86 for (shdrs, 0..) |shdr, i| {
81 var dynsym_sect_index: ?u32 = null;
82 var dynamic_sect_index: ?u32 = null;
83 var versym_sect_index: ?u32 = null;
84 var verdef_sect_index: ?u32 = null;
85 for (self.shdrs.items, 0..) |shdr, i| {
8786 if (shdr.sh_type != elf.SHT_NOBITS) {
88 if (self.data.len < shdr.sh_offset or self.data.len < shdr.sh_offset + shdr.sh_size) {
87 if (file_size < shdr.sh_offset or file_size < shdr.sh_offset + shdr.sh_size) {
8988 try elf_file.reportParseError2(self.index, "corrupted section header", .{});
9089 return error.MalformedObject;
9190 }
9291 }
93 self.shdrs.appendAssumeCapacity(try ElfShdr.fromElf64Shdr(shdr));
9492 switch (shdr.sh_type) {
95 elf.SHT_DYNSYM => self.dynsym_sect_index = @as(u16, @intCast(i)),
96 elf.SHT_DYNAMIC => self.dynamic_sect_index = @as(u16, @intCast(i)),
97 elf.SHT_GNU_VERSYM => self.versym_sect_index = @as(u16, @intCast(i)),
98 elf.SHT_GNU_VERDEF => self.verdef_sect_index = @as(u16, @intCast(i)),
93 elf.SHT_DYNSYM => dynsym_sect_index = @intCast(i),
94 elf.SHT_DYNAMIC => dynamic_sect_index = @intCast(i),
95 elf.SHT_GNU_VERSYM => versym_sect_index = @intCast(i),
96 elf.SHT_GNU_VERDEF => verdef_sect_index = @intCast(i),
9997 else => {},
10098 }
10199 }
102100
103 try self.parseVersions(elf_file);
101 if (dynamic_sect_index) |index| {
102 const shdr = self.shdrs.items[index];
103 const raw = try Elf.preadAllAlloc(gpa, handle, shdr.sh_offset, shdr.sh_size);
104 defer gpa.free(raw);
105 const num = @divExact(raw.len, @sizeOf(elf.Elf64_Dyn));
106 const dyntab = @as([*]align(1) const elf.Elf64_Dyn, @ptrCast(raw.ptr))[0..num];
107 try self.dynamic_table.appendUnalignedSlice(gpa, dyntab);
108 }
109
110 const symtab = if (dynsym_sect_index) |index| blk: {
111 const shdr = self.shdrs.items[index];
112 const buffer = try Elf.preadAllAlloc(gpa, handle, shdr.sh_offset, shdr.sh_size);
113 const nsyms = @divExact(buffer.len, @sizeOf(elf.Elf64_Sym));
114 break :blk @as([*]align(1) const elf.Elf64_Sym, @ptrCast(buffer.ptr))[0..nsyms];
115 } else &[0]elf.Elf64_Sym{};
116 defer gpa.free(symtab);
117
118 const strtab = if (dynsym_sect_index) |index| blk: {
119 const symtab_shdr = self.shdrs.items[index];
120 const shdr = self.shdrs.items[symtab_shdr.sh_link];
121 const buffer = try Elf.preadAllAlloc(gpa, handle, shdr.sh_offset, shdr.sh_size);
122 break :blk buffer;
123 } else &[0]u8{};
124 defer gpa.free(strtab);
125
126 try self.parseVersions(elf_file, handle, .{
127 .symtab = symtab,
128 .verdef_sect_index = verdef_sect_index,
129 .versym_sect_index = versym_sect_index,
130 });
131
132 try self.initSymtab(elf_file, .{
133 .symtab = symtab,
134 .strtab = strtab,
135 });
104136}
105137
106fn parseVersions(self: *SharedObject, elf_file: *Elf) !void {
138fn parseVersions(self: *SharedObject, elf_file: *Elf, handle: std.fs.File, opts: struct {
139 symtab: []align(1) const elf.Elf64_Sym,
140 verdef_sect_index: ?u32,
141 versym_sect_index: ?u32,
142}) !void {
107143 const comp = elf_file.base.comp;
108144 const gpa = comp.gpa;
109 const symtab = self.getSymtabRaw();
110145
111146 try self.verstrings.resize(gpa, 2);
112147 self.verstrings.items[elf.VER_NDX_LOCAL] = 0;
113148 self.verstrings.items[elf.VER_NDX_GLOBAL] = 0;
114149
115 if (self.verdef_sect_index) |shndx| {
116 const verdefs = self.shdrContents(shndx);
150 if (opts.verdef_sect_index) |shndx| {
151 const shdr = self.shdrs.items[shndx];
152 const verdefs = try Elf.preadAllAlloc(gpa, handle, shdr.sh_offset, shdr.sh_size);
153 defer gpa.free(verdefs);
117154 const nverdefs = self.verdefNum();
118155 try self.verstrings.resize(gpa, self.verstrings.items.len + nverdefs);
119156
......@@ -131,10 +168,12 @@ fn parseVersions(self: *SharedObject, elf_file: *Elf) !void {
131168 }
132169 }
133170
134 try self.versyms.ensureTotalCapacityPrecise(gpa, symtab.len);
171 try self.versyms.ensureTotalCapacityPrecise(gpa, opts.symtab.len);
135172
136 if (self.versym_sect_index) |shndx| {
137 const versyms_raw = self.shdrContents(shndx);
173 if (opts.versym_sect_index) |shndx| {
174 const shdr = self.shdrs.items[shndx];
175 const versyms_raw = try Elf.preadAllAlloc(gpa, handle, shdr.sh_offset, shdr.sh_size);
176 defer gpa.free(versyms_raw);
138177 const nversyms = @divExact(versyms_raw.len, @sizeOf(elf.Elf64_Versym));
139178 const versyms = @as([*]align(1) const elf.Elf64_Versym, @ptrCast(versyms_raw.ptr))[0..nversyms];
140179 for (versyms) |ver| {
......@@ -144,22 +183,23 @@ fn parseVersions(self: *SharedObject, elf_file: *Elf) !void {
144183 ver;
145184 self.versyms.appendAssumeCapacity(normalized_ver);
146185 }
147 } else for (0..symtab.len) |_| {
186 } else for (0..opts.symtab.len) |_| {
148187 self.versyms.appendAssumeCapacity(elf.VER_NDX_GLOBAL);
149188 }
150189}
151190
152pub fn init(self: *SharedObject, elf_file: *Elf) !void {
191fn initSymtab(self: *SharedObject, elf_file: *Elf, opts: struct {
192 symtab: []align(1) const elf.Elf64_Sym,
193 strtab: []const u8,
194}) !void {
153195 const comp = elf_file.base.comp;
154196 const gpa = comp.gpa;
155 const symtab = self.getSymtabRaw();
156 const strtab = self.getStrtabRaw();
157197
158 try self.strtab.appendSlice(gpa, strtab);
159 try self.symtab.ensureTotalCapacityPrecise(gpa, symtab.len);
160 try self.symbols.ensureTotalCapacityPrecise(gpa, symtab.len);
198 try self.strtab.appendSlice(gpa, opts.strtab);
199 try self.symtab.ensureTotalCapacityPrecise(gpa, opts.symtab.len);
200 try self.symbols.ensureTotalCapacityPrecise(gpa, opts.symtab.len);
161201
162 for (symtab, 0..) |sym, i| {
202 for (opts.symtab, 0..) |sym, i| {
163203 const hidden = self.versyms.items[i] & elf.VERSYM_HIDDEN != 0;
164204 const name = self.getString(sym.st_name);
165205 // We need to garble up the name so that we don't pick this symbol
......@@ -250,11 +290,6 @@ pub fn writeSymtab(self: SharedObject, elf_file: *Elf) void {
250290 }
251291}
252292
253pub fn shdrContents(self: SharedObject, index: u16) []const u8 {
254 const shdr = self.shdrs.items[index];
255 return self.data[shdr.sh_offset..][0..shdr.sh_size];
256}
257
258293pub fn versionString(self: SharedObject, index: elf.Elf64_Versym) [:0]const u8 {
259294 const off = self.verstrings.items[index & elf.VERSYM_VERSION];
260295 return self.getString(off);
......@@ -264,16 +299,8 @@ pub fn asFile(self: *SharedObject) File {
264299 return .{ .shared_object = self };
265300}
266301
267fn dynamicTable(self: *SharedObject) []align(1) const elf.Elf64_Dyn {
268 const shndx = self.dynamic_sect_index orelse return &[0]elf.Elf64_Dyn{};
269 const raw = self.shdrContents(shndx);
270 const num = @divExact(raw.len, @sizeOf(elf.Elf64_Dyn));
271 return @as([*]align(1) const elf.Elf64_Dyn, @ptrCast(raw.ptr))[0..num];
272}
273
274302fn verdefNum(self: *SharedObject) u32 {
275 const entries = self.dynamicTable();
276 for (entries) |entry| switch (entry.d_tag) {
303 for (self.dynamic_table.items) |entry| switch (entry.d_tag) {
277304 elf.DT_VERDEFNUM => return @as(u32, @intCast(entry.d_val)),
278305 else => {},
279306 };
......@@ -281,8 +308,7 @@ fn verdefNum(self: *SharedObject) u32 {
281308}
282309
283310pub fn soname(self: *SharedObject) []const u8 {
284 const entries = self.dynamicTable();
285 for (entries) |entry| switch (entry.d_tag) {
311 for (self.dynamic_table.items) |entry| switch (entry.d_tag) {
286312 elf.DT_SONAME => return self.getString(@as(u32, @intCast(entry.d_val))),
287313 else => {},
288314 };
......@@ -342,20 +368,6 @@ pub fn getString(self: SharedObject, off: u32) [:0]const u8 {
342368 return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.strtab.items.ptr + off)), 0);
343369}
344370
345pub fn getSymtabRaw(self: SharedObject) []align(1) const elf.Elf64_Sym {
346 const index = self.dynsym_sect_index orelse return &[0]elf.Elf64_Sym{};
347 const raw_symtab = self.shdrContents(index);
348 const nsyms = @divExact(raw_symtab.len, @sizeOf(elf.Elf64_Sym));
349 const symtab = @as([*]align(1) const elf.Elf64_Sym, @ptrCast(raw_symtab.ptr))[0..nsyms];
350 return symtab;
351}
352
353pub fn getStrtabRaw(self: SharedObject) []const u8 {
354 const index = self.dynsym_sect_index orelse return &[0]u8{};
355 const shdr = self.shdrs.items[index];
356 return self.shdrContents(@as(u16, @intCast(shdr.sh_link)));
357}
358
359371pub fn format(
360372 self: SharedObject,
361373 comptime unused_fmt_string: []const u8,
......@@ -407,6 +419,5 @@ const mem = std.mem;
407419
408420const Allocator = mem.Allocator;
409421const Elf = @import("../Elf.zig");
410const ElfShdr = @import("Object.zig").ElfShdr;
411422const File = @import("file.zig").File;
412423const Symbol = @import("Symbol.zig");
src/link/Elf/ZigObject.zig+10-13
......@@ -305,19 +305,16 @@ pub fn addAtom(self: *ZigObject, elf_file: *Elf) !Symbol.Index {
305305}
306306
307307/// TODO actually create fake input shdrs and return that instead.
308pub fn inputShdr(self: ZigObject, atom_index: Atom.Index, elf_file: *Elf) Object.ElfShdr {
308pub fn inputShdr(self: ZigObject, atom_index: Atom.Index, elf_file: *Elf) elf.Elf64_Shdr {
309309 _ = self;
310 const shdr = shdr: {
311 const atom = elf_file.atom(atom_index) orelse break :shdr Elf.null_shdr;
312 const shndx = atom.outputShndx() orelse break :shdr Elf.null_shdr;
313 var shdr = elf_file.shdrs.items[shndx];
314 shdr.sh_addr = 0;
315 shdr.sh_offset = 0;
316 shdr.sh_size = atom.size;
317 shdr.sh_addralign = atom.alignment.toByteUnits(1);
318 break :shdr shdr;
319 };
320 return Object.ElfShdr.fromElf64Shdr(shdr) catch unreachable;
310 const atom = elf_file.atom(atom_index) orelse return Elf.null_shdr;
311 const shndx = atom.outputShndx() orelse return Elf.null_shdr;
312 var shdr = elf_file.shdrs.items[shndx];
313 shdr.sh_addr = 0;
314 shdr.sh_offset = 0;
315 shdr.sh_size = atom.size;
316 shdr.sh_addralign = atom.alignment.toByteUnits(1);
317 return shdr;
321318}
322319
323320pub fn resolveSymbols(self: *ZigObject, elf_file: *Elf) void {
......@@ -525,7 +522,7 @@ pub fn writeAr(self: ZigObject, writer: anytype) !void {
525522 .{ .name = name }
526523 else
527524 .{ .name_off = self.output_ar_state.name_off },
528 .size = @intCast(self.data.items.len),
525 .size = self.data.items.len,
529526 });
530527 try writer.writeAll(mem.asBytes(&hdr));
531528 try writer.writeAll(self.data.items);
src/link/Elf/eh_frame.zig+9-22
......@@ -5,7 +5,6 @@ pub const Fde = struct {
55 cie_index: u32,
66 rel_index: u32 = 0,
77 rel_num: u32 = 0,
8 rel_section_index: u32 = 0,
98 input_section_index: u32 = 0,
109 file_index: u32 = 0,
1110 alive: bool = true,
......@@ -20,10 +19,9 @@ pub const Fde = struct {
2019 return base + fde.out_offset;
2120 }
2221
23 pub fn data(fde: Fde, elf_file: *Elf) []const u8 {
22 pub fn data(fde: Fde, elf_file: *Elf) []u8 {
2423 const object = elf_file.file(fde.file_index).?.object;
25 const contents = object.shdrContents(fde.input_section_index);
26 return contents[fde.offset..][0..fde.calcSize()];
24 return object.eh_frame_data.items[fde.offset..][0..fde.calcSize()];
2725 }
2826
2927 pub fn cie(fde: Fde, elf_file: *Elf) Cie {
......@@ -50,7 +48,7 @@ pub const Fde = struct {
5048
5149 pub fn relocs(fde: Fde, elf_file: *Elf) []align(1) const elf.Elf64_Rela {
5250 const object = elf_file.file(fde.file_index).?.object;
53 return object.getRelocs(fde.rel_section_index)[fde.rel_index..][0..fde.rel_num];
51 return object.relocs.items[fde.rel_index..][0..fde.rel_num];
5452 }
5553
5654 pub fn format(
......@@ -106,7 +104,6 @@ pub const Cie = struct {
106104 size: usize,
107105 rel_index: u32 = 0,
108106 rel_num: u32 = 0,
109 rel_section_index: u32 = 0,
110107 input_section_index: u32 = 0,
111108 file_index: u32 = 0,
112109 /// Includes 4byte size cell.
......@@ -121,10 +118,9 @@ pub const Cie = struct {
121118 return base + cie.out_offset;
122119 }
123120
124 pub fn data(cie: Cie, elf_file: *Elf) []const u8 {
121 pub fn data(cie: Cie, elf_file: *Elf) []u8 {
125122 const object = elf_file.file(cie.file_index).?.object;
126 const contents = object.shdrContents(cie.input_section_index);
127 return contents[cie.offset..][0..cie.calcSize()];
123 return object.eh_frame_data.items[cie.offset..][0..cie.calcSize()];
128124 }
129125
130126 pub fn calcSize(cie: Cie) usize {
......@@ -133,7 +129,7 @@ pub const Cie = struct {
133129
134130 pub fn relocs(cie: Cie, elf_file: *Elf) []align(1) const elf.Elf64_Rela {
135131 const object = elf_file.file(cie.file_index).?.object;
136 return object.getRelocs(cie.rel_section_index)[cie.rel_index..][0..cie.rel_num];
132 return object.relocs.items[cie.rel_index..][0..cie.rel_num];
137133 }
138134
139135 pub fn eql(cie: Cie, other: Cie, elf_file: *Elf) bool {
......@@ -330,9 +326,6 @@ fn resolveReloc(rec: anytype, sym: *const Symbol, rel: elf.Elf64_Rela, elf_file:
330326}
331327
332328pub fn writeEhFrame(elf_file: *Elf, writer: anytype) !void {
333 const comp = elf_file.base.comp;
334 const gpa = comp.gpa;
335
336329 relocs_log.debug("{x}: .eh_frame", .{elf_file.shdrs.items[elf_file.eh_frame_section_index.?].sh_addr});
337330
338331 for (elf_file.objects.items) |index| {
......@@ -341,8 +334,7 @@ pub fn writeEhFrame(elf_file: *Elf, writer: anytype) !void {
341334 for (object.cies.items) |cie| {
342335 if (!cie.alive) continue;
343336
344 const contents = try gpa.dupe(u8, cie.data(elf_file));
345 defer gpa.free(contents);
337 const contents = cie.data(elf_file);
346338
347339 for (cie.relocs(elf_file)) |rel| {
348340 const sym = elf_file.symbol(object.symbols.items[rel.r_sym()]);
......@@ -359,8 +351,7 @@ pub fn writeEhFrame(elf_file: *Elf, writer: anytype) !void {
359351 for (object.fdes.items) |fde| {
360352 if (!fde.alive) continue;
361353
362 const contents = try gpa.dupe(u8, fde.data(elf_file));
363 defer gpa.free(contents);
354 const contents = fde.data(elf_file);
364355
365356 std.mem.writeInt(
366357 i32,
......@@ -382,9 +373,6 @@ pub fn writeEhFrame(elf_file: *Elf, writer: anytype) !void {
382373}
383374
384375pub fn writeEhFrameObject(elf_file: *Elf, writer: anytype) !void {
385 const comp = elf_file.base.comp;
386 const gpa = comp.gpa;
387
388376 for (elf_file.objects.items) |index| {
389377 const object = elf_file.file(index).?.object;
390378
......@@ -400,8 +388,7 @@ pub fn writeEhFrameObject(elf_file: *Elf, writer: anytype) !void {
400388 for (object.fdes.items) |fde| {
401389 if (!fde.alive) continue;
402390
403 const contents = try gpa.dupe(u8, fde.data(elf_file));
404 defer gpa.free(contents);
391 const contents = fde.data(elf_file);
405392
406393 std.mem.writeInt(
407394 i32,
src/link/Elf/file.zig+7-4
......@@ -162,18 +162,18 @@ pub const File = union(enum) {
162162 state.name_off = try ar_strtab.insert(allocator, path);
163163 }
164164
165 pub fn updateArSize(file: File) void {
165 pub fn updateArSize(file: File, elf_file: *Elf) !void {
166166 return switch (file) {
167167 .zig_object => |x| x.updateArSize(),
168 .object => |x| x.updateArSize(),
168 .object => |x| x.updateArSize(elf_file),
169169 inline else => unreachable,
170170 };
171171 }
172172
173 pub fn writeAr(file: File, writer: anytype) !void {
173 pub fn writeAr(file: File, elf_file: *Elf, writer: anytype) !void {
174174 return switch (file) {
175175 .zig_object => |x| x.writeAr(writer),
176 .object => |x| x.writeAr(writer),
176 .object => |x| x.writeAr(elf_file, writer),
177177 inline else => unreachable,
178178 };
179179 }
......@@ -187,6 +187,9 @@ pub const File = union(enum) {
187187 object: Object,
188188 shared_object: SharedObject,
189189 };
190
191 pub const Handle = std.fs.File;
192 pub const HandleIndex = Index;
190193};
191194
192195const std = @import("std");
src/link/Elf/synthetic_sections.zig+2-3
......@@ -1582,15 +1582,14 @@ pub const ComdatGroupSection = struct {
15821582
15831583 pub fn size(cgs: ComdatGroupSection, elf_file: *Elf) usize {
15841584 const cg = elf_file.comdatGroup(cgs.cg_index);
1585 const object = cgs.file(elf_file).?.object;
1586 const members = object.comdatGroupMembers(cg.shndx);
1585 const members = cg.comdatGroupMembers(elf_file);
15871586 return (members.len + 1) * @sizeOf(u32);
15881587 }
15891588
15901589 pub fn write(cgs: ComdatGroupSection, elf_file: *Elf, writer: anytype) !void {
15911590 const cg = elf_file.comdatGroup(cgs.cg_index);
15921591 const object = cgs.file(elf_file).?.object;
1593 const members = object.comdatGroupMembers(cg.shndx);
1592 const members = cg.comdatGroupMembers(elf_file);
15941593 try writer.writeInt(u32, elf.GRP_COMDAT, .little);
15951594 for (members) |shndx| {
15961595 const shdr = object.shdrs.items[shndx];