diff options
| author | Jakub Konka <kubkon@jakubkonka.com> | 2024-02-12 21:45:15 +0100 |
|---|---|---|
| committer | Jakub Konka <kubkon@jakubkonka.com> | 2024-02-12 23:07:51 +0100 |
| commit | a94d5895cfbc7b2e695ba1edaad8f4af3d2081ab (patch) | |
| tree | dc05ede8334a06346fc7b3339657a7132e5fd973 /src | |
| parent | fad5e7a997344eddc45511df581472acaf0e880e (diff) | |
| download | zig-a94d5895cfbc7b2e695ba1edaad8f4af3d2081ab.tar.gz zig-a94d5895cfbc7b2e695ba1edaad8f4af3d2081ab.zip | |
elf: do not prealloc input objects, pread selectively
Diffstat (limited to 'src')
| -rw-r--r-- | src/link/Elf.zig | 79 | ||||
| -rw-r--r-- | src/link/Elf/Archive.zig | 56 | ||||
| -rw-r--r-- | src/link/Elf/Atom.zig | 10 | ||||
| -rw-r--r-- | src/link/Elf/Object.zig | 240 | ||||
| -rw-r--r-- | src/link/Elf/SharedObject.zig | 165 | ||||
| -rw-r--r-- | src/link/Elf/ZigObject.zig | 23 | ||||
| -rw-r--r-- | src/link/Elf/eh_frame.zig | 31 | ||||
| -rw-r--r-- | src/link/Elf/file.zig | 11 | ||||
| -rw-r--r-- | src/link/Elf/synthetic_sections.zig | 5 |
9 files changed, 339 insertions, 281 deletions
diff --git a/src/link/Elf.zig b/src/link/Elf.zig index b139605f75..fc8e82176f 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -35,6 +35,10 @@ llvm_object: ?*LlvmObject = null, /// Index of each input file also encodes the priority or precedence of one input file /// over another. files: std.MultiArrayList(File.Entry) = .{}, +/// Long-lived list of all file descriptors. +/// We store them globally rather than per actual File so that we can re-use +/// one file handle per every object file within an archive. +file_handles: std.ArrayListUnmanaged(File.Handle) = .{}, zig_object_index: ?File.Index = null, linker_defined_index: ?File.Index = null, objects: std.ArrayListUnmanaged(File.Index) = .{}, @@ -444,6 +448,11 @@ pub fn deinit(self: *Elf) void { if (self.llvm_object) |llvm_object| llvm_object.deinit(); + for (self.file_handles.items) |fh| { + fh.close(); + } + self.file_handles.deinit(gpa); + for (self.files.items(.tags), self.files.items(.data)) |tag, *data| switch (tag) { .null => {}, .zig_object => data.zig_object.deinit(gpa), @@ -1244,9 +1253,6 @@ pub fn flushModule(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node) for (self.objects.items) |index| { try self.file(index).?.object.init(self); } - for (self.shared_objects.items) |index| { - try self.file(index).?.shared_object.init(self); - } if (comp.link_errors.items.len > 0) return error.FlushFailure; @@ -1463,7 +1469,7 @@ pub fn flushStaticLib(self: *Elf, comp: *Compilation, module_obj_path: ?[]const for (files.items) |index| { const file_ptr = self.file(index).?; try file_ptr.updateArStrtab(gpa, &ar_strtab); - file_ptr.updateArSize(); + try file_ptr.updateArSize(self); } // Update file offsets of contributing objects. @@ -1515,7 +1521,7 @@ pub fn flushStaticLib(self: *Elf, comp: *Compilation, module_obj_path: ?[]const // Write object files for (files.items) |index| { if (!mem.isAligned(buffer.items.len, 2)) try buffer.writer().writeByte(0); - try self.file(index).?.writeAr(buffer.writer()); + try self.file(index).?.writeAr(self, buffer.writer()); } assert(buffer.items.len == total_size); @@ -1902,13 +1908,13 @@ fn parseObject(self: *Elf, path: []const u8) ParseError!void { defer tracy.end(); const gpa = self.base.comp.gpa; - const in_file = try std.fs.cwd().openFile(path, .{}); - defer in_file.close(); - const data = try in_file.readToEndAlloc(gpa, std.math.maxInt(u32)); + const handle = try std.fs.cwd().openFile(path, .{}); + const fh = try self.addFileHandle(handle); + const index = @as(File.Index, @intCast(try self.files.addOne(gpa))); self.files.set(index, .{ .object = .{ .path = try gpa.dupe(u8, path), - .data = data, + .file_handle = fh, .index = index, } }); try self.objects.append(gpa, index); @@ -1922,12 +1928,12 @@ fn parseArchive(self: *Elf, path: []const u8, must_link: bool) ParseError!void { defer tracy.end(); const gpa = self.base.comp.gpa; - const in_file = try std.fs.cwd().openFile(path, .{}); - defer in_file.close(); - const data = try in_file.readToEndAlloc(gpa, std.math.maxInt(u32)); - var archive = Archive{ .path = try gpa.dupe(u8, path), .data = data }; + const handle = try std.fs.cwd().openFile(path, .{}); + const fh = try self.addFileHandle(handle); + + var archive = Archive{}; defer archive.deinit(gpa); - try archive.parse(self); + try archive.parse(self, path, fh); const objects = try archive.objects.toOwnedSlice(gpa); defer gpa.free(objects); @@ -1948,13 +1954,12 @@ fn parseSharedObject(self: *Elf, lib: SystemLib) ParseError!void { defer tracy.end(); const gpa = self.base.comp.gpa; - const in_file = try std.fs.cwd().openFile(lib.path, .{}); - defer in_file.close(); - const data = try in_file.readToEndAlloc(gpa, std.math.maxInt(u32)); + const handle = try std.fs.cwd().openFile(lib.path, .{}); + defer handle.close(); + const index = @as(File.Index, @intCast(try self.files.addOne(gpa))); self.files.set(index, .{ .shared_object = .{ .path = try gpa.dupe(u8, lib.path), - .data = data, .index = index, .needed = lib.needed, .alive = lib.needed, @@ -1962,7 +1967,7 @@ fn parseSharedObject(self: *Elf, lib: SystemLib) ParseError!void { try self.shared_objects.append(gpa, index); const shared_object = self.file(index).?.shared_object; - try shared_object.parse(self); + try shared_object.parse(self, handle); } fn parseLdScript(self: *Elf, lib: SystemLib) ParseError!void { @@ -2135,7 +2140,7 @@ fn resolveSymbols(self: *Elf) void { const cg = self.comdatGroup(cg_index); const cg_owner = self.comdatGroupOwner(cg.owner); if (cg_owner.file != index) { - for (object.comdatGroupMembers(cg.shndx)) |shndx| { + for (cg.comdatGroupMembers(self)) |shndx| { const atom_index = object.atoms.items[shndx]; if (self.atom(atom_index)) |atom_ptr| { atom_ptr.flags.alive = false; @@ -5862,6 +5867,19 @@ pub fn file(self: *Elf, index: File.Index) ?File { }; } +pub fn addFileHandle(self: *Elf, handle: std.fs.File) !File.HandleIndex { + const gpa = self.base.comp.gpa; + const index: File.HandleIndex = @intCast(self.file_handles.items.len); + const fh = try self.file_handles.addOne(gpa); + fh.* = handle; + return index; +} + +pub fn fileHandle(self: Elf, index: File.HandleIndex) File.Handle { + assert(index < self.file_handles.items.len); + return self.file_handles.items[index]; +} + /// Returns pointer-to-symbol described at sym_index. pub fn symbol(self: *Elf, sym_index: Symbol.Index) *Symbol { return &self.symbols.items[sym_index]; @@ -6395,6 +6413,15 @@ fn fmtDumpState( } } +/// Caller owns the memory. +pub fn preadAllAlloc(allocator: Allocator, handle: std.fs.File, offset: usize, size: usize) ![]u8 { + const buffer = try allocator.alloc(u8, size); + errdefer allocator.free(buffer); + const amt = try handle.preadAll(buffer, offset); + if (amt != size) return error.InputOutput; + return buffer; +} + /// Binary search pub fn bsearch(comptime T: type, haystack: []align(1) const T, predicate: anytype) usize { if (!@hasDecl(@TypeOf(predicate), "predicate")) @@ -6441,12 +6468,22 @@ pub const base_tag: link.File.Tag = .elf; const ComdatGroupOwner = struct { file: File.Index = 0, + const Index = u32; }; pub const ComdatGroup = struct { owner: ComdatGroupOwner.Index, - shndx: u16, + file: File.Index, + shndx: u32, + members_start: u32, + members_len: u32, + + pub fn comdatGroupMembers(cg: ComdatGroup, elf_file: *Elf) []const u32 { + const object = elf_file.file(cg.file).?.object; + return object.comdat_group_data.items[cg.members_start..][0..cg.members_len]; + } + pub const Index = u32; }; diff --git a/src/link/Elf/Archive.zig b/src/link/Elf/Archive.zig index 65135abbc7..a2f83dda5a 100644 --- a/src/link/Elf/Archive.zig +++ b/src/link/Elf/Archive.zig @@ -1,8 +1,5 @@ -path: []const u8, -data: []const u8, - objects: std.ArrayListUnmanaged(Object) = .{}, -strtab: []const u8 = &[0]u8{}, +strtab: std.ArrayListUnmanaged(u8) = .{}, pub fn isArchive(path: []const u8) !bool { const file = try std.fs.cwd().openFile(path, .{}); @@ -14,68 +11,79 @@ pub fn isArchive(path: []const u8) !bool { } pub fn deinit(self: *Archive, allocator: Allocator) void { - allocator.free(self.path); - allocator.free(self.data); self.objects.deinit(allocator); + self.strtab.deinit(allocator); } -pub fn parse(self: *Archive, elf_file: *Elf) !void { +pub fn parse(self: *Archive, elf_file: *Elf, path: []const u8, handle_index: File.HandleIndex) !void { const comp = elf_file.base.comp; const gpa = comp.gpa; + const handle = elf_file.fileHandle(handle_index); + const size = (try handle.stat()).size; - var stream = std.io.fixedBufferStream(self.data); - const reader = stream.reader(); + const reader = handle.reader(); _ = try reader.readBytesNoEof(elf.ARMAG.len); + var pos: usize = elf.ARMAG.len; while (true) { - if (stream.pos >= self.data.len) break; - if (!mem.isAligned(stream.pos, 2)) stream.pos += 1; + if (pos >= size) break; + if (!mem.isAligned(pos, 2)) { + try handle.seekBy(1); + pos += 1; + } const hdr = try reader.readStruct(elf.ar_hdr); + pos += @sizeOf(elf.ar_hdr); if (!mem.eql(u8, &hdr.ar_fmag, elf.ARFMAG)) { - try elf_file.reportParseError(self.path, "invalid archive header delimiter: {s}", .{ + try elf_file.reportParseError(path, "invalid archive header delimiter: {s}", .{ std.fmt.fmtSliceEscapeLower(&hdr.ar_fmag), }); return error.MalformedArchive; } - const size = try hdr.size(); + const obj_size = try hdr.size(); defer { - _ = stream.seekBy(size) catch {}; + _ = handle.seekBy(obj_size) catch {}; + pos += obj_size; } if (hdr.isSymtab() or hdr.isSymtab64()) continue; if (hdr.isStrtab()) { - self.strtab = self.data[stream.pos..][0..size]; + try self.strtab.resize(gpa, obj_size); + const amt = try handle.preadAll(self.strtab.items, pos); + if (amt != obj_size) return error.InputOutput; continue; } if (hdr.isSymdef() or hdr.isSymdefSorted()) continue; const name = if (hdr.name()) |name| - try gpa.dupe(u8, name) + name else if (try hdr.nameOffset()) |off| - try gpa.dupe(u8, self.getString(off)) + self.getString(off) else unreachable; const object = Object{ - .archive = try gpa.dupe(u8, self.path), - .path = name, - .data = try gpa.dupe(u8, self.data[stream.pos..][0..size]), + .archive = .{ + .path = try gpa.dupe(u8, path), + .offset = pos, + }, + .path = try gpa.dupe(u8, name), + .file_handle = handle_index, .index = undefined, .alive = false, }; - log.debug("extracting object '{s}' from archive '{s}'", .{ object.path, self.path }); + log.debug("extracting object '{s}' from archive '{s}'", .{ object.path, path }); try self.objects.append(gpa, object); } } fn getString(self: Archive, off: u32) []const u8 { - assert(off < self.strtab.len); - const name = mem.sliceTo(@as([*:'\n']const u8, @ptrCast(self.strtab.ptr + off)), 0); + assert(off < self.strtab.items.len); + const name = mem.sliceTo(@as([*:'\n']const u8, @ptrCast(self.strtab.items.ptr + off)), 0); return name[0 .. name.len - 1]; } @@ -86,7 +94,7 @@ pub fn setArHdr(opts: struct { name: []const u8, name_off: u32, }, - size: u32, + size: usize, }) elf.ar_hdr { var hdr: elf.ar_hdr = .{ .ar_name = undefined, diff --git a/src/link/Elf/Atom.zig b/src/link/Elf/Atom.zig index a7b876f619..cb3e7718b2 100644 --- a/src/link/Elf/Atom.zig +++ b/src/link/Elf/Atom.zig @@ -22,6 +22,12 @@ output_section_index: u16 = 0, /// Index of the input section containing this atom's relocs. relocs_section_index: u32 = 0, +/// Start index of the relocations belonging to this atom. +rel_index: u32 = 0, + +/// Number of relocations belonging to this atom. +rel_num: u32 = 0, + /// Index of this atom in the linker's atoms table. atom_index: Index = 0, @@ -52,7 +58,7 @@ pub fn file(self: Atom, elf_file: *Elf) ?File { return elf_file.file(self.file_index); } -pub fn inputShdr(self: Atom, elf_file: *Elf) Object.ElfShdr { +pub fn inputShdr(self: Atom, elf_file: *Elf) elf.Elf64_Shdr { return switch (self.file(elf_file).?) { .object => |x| x.shdrs.items[self.input_section_index], .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 { const shndx = self.relocsShndx() orelse return &[0]elf.Elf64_Rela{}; return switch (self.file(elf_file).?) { .zig_object => |x| x.relocs.items[shndx].items, - .object => |x| x.getRelocs(shndx), + .object => |x| x.relocs.items[self.rel_index..][0..self.rel_num], else => unreachable, }; } diff --git a/src/link/Elf/Object.zig b/src/link/Elf/Object.zig index 1f01f471c9..3a9d32f51c 100644 --- a/src/link/Elf/Object.zig +++ b/src/link/Elf/Object.zig @@ -1,10 +1,10 @@ -archive: ?[]const u8 = null, +archive: ?InArchive = null, path: []const u8, -data: []const u8, +file_handle: File.HandleIndex, index: File.Index, header: ?elf.Elf64_Ehdr = null, -shdrs: std.ArrayListUnmanaged(ElfShdr) = .{}, +shdrs: std.ArrayListUnmanaged(elf.Elf64_Shdr) = .{}, symtab: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{}, strtab: std.ArrayListUnmanaged(u8) = .{}, @@ -12,9 +12,12 @@ first_global: ?Symbol.Index = null, symbols: std.ArrayListUnmanaged(Symbol.Index) = .{}, atoms: std.ArrayListUnmanaged(Atom.Index) = .{}, comdat_groups: std.ArrayListUnmanaged(Elf.ComdatGroup.Index) = .{}, +comdat_group_data: std.ArrayListUnmanaged(u32) = .{}, +relocs: std.ArrayListUnmanaged(elf.Elf64_Rela) = .{}, fdes: std.ArrayListUnmanaged(Fde) = .{}, cies: std.ArrayListUnmanaged(Cie) = .{}, +eh_frame_data: std.ArrayListUnmanaged(u8) = .{}, alive: bool = true, num_dynrelocs: u32 = 0, @@ -35,24 +38,30 @@ pub fn isObject(path: []const u8) !bool { } pub fn deinit(self: *Object, allocator: Allocator) void { - if (self.archive) |path| allocator.free(path); + if (self.archive) |*ar| allocator.free(ar.path); allocator.free(self.path); - allocator.free(self.data); self.shdrs.deinit(allocator); self.symtab.deinit(allocator); self.strtab.deinit(allocator); self.symbols.deinit(allocator); self.atoms.deinit(allocator); self.comdat_groups.deinit(allocator); + self.comdat_group_data.deinit(allocator); + self.relocs.deinit(allocator); self.fdes.deinit(allocator); self.cies.deinit(allocator); + self.eh_frame_data.deinit(allocator); } pub fn parse(self: *Object, elf_file: *Elf) !void { - var stream = std.io.fixedBufferStream(self.data); - const reader = stream.reader(); + const gpa = elf_file.base.comp.gpa; + const offset = if (self.archive) |ar| ar.offset else 0; + const handle = elf_file.fileHandle(self.file_handle); + const file_size = (try handle.stat()).size; - self.header = try reader.readStruct(elf.Elf64_Ehdr); + const header_buffer = try Elf.preadAllAlloc(gpa, handle, offset, @sizeOf(elf.Elf64_Ehdr)); + defer gpa.free(header_buffer); + self.header = @as(*align(1) const elf.Elf64_Ehdr, @ptrCast(header_buffer)).*; const target = elf_file.base.comp.root_mod.resolved_target.result; if (target.cpu.arch != self.header.?.e_machine.toTargetCpuArch().?) { @@ -66,12 +75,10 @@ pub fn parse(self: *Object, elf_file: *Elf) !void { if (self.header.?.e_shnum == 0) return; - const comp = elf_file.base.comp; - const gpa = comp.gpa; - - if (self.data.len < self.header.?.e_shoff or - self.data.len < self.header.?.e_shoff + @as(u64, @intCast(self.header.?.e_shnum)) * @sizeOf(elf.Elf64_Shdr)) - { + const shoff = math.cast(usize, self.header.?.e_shoff) orelse return error.Overflow; + const shnum = math.cast(usize, self.header.?.e_shnum) orelse return error.Overflow; + const shsize = shnum * @sizeOf(elf.Elf64_Shdr); + if (file_size < offset + shoff or file_size < offset + shoff + shsize) { try elf_file.reportParseError2( self.index, "corrupt header: section header table extends past the end of file", @@ -80,25 +87,23 @@ pub fn parse(self: *Object, elf_file: *Elf) !void { return error.MalformedObject; } - const shoff = math.cast(usize, self.header.?.e_shoff) orelse return error.Overflow; - const shdrs = @as( - [*]align(1) const elf.Elf64_Shdr, - @ptrCast(self.data.ptr + shoff), - )[0..self.header.?.e_shnum]; - try self.shdrs.ensureTotalCapacityPrecise(gpa, shdrs.len); + const shdrs_buffer = try Elf.preadAllAlloc(gpa, handle, offset + shoff, shsize); + defer gpa.free(shdrs_buffer); + const shdrs = @as([*]align(1) const elf.Elf64_Shdr, @ptrCast(shdrs_buffer.ptr))[0..shnum]; + try self.shdrs.appendUnalignedSlice(gpa, shdrs); - for (shdrs) |shdr| { + for (self.shdrs.items) |shdr| { if (shdr.sh_type != elf.SHT_NOBITS) { - if (self.data.len < shdr.sh_offset or self.data.len < shdr.sh_offset + shdr.sh_size) { + if (file_size < offset + shdr.sh_offset or file_size < offset + shdr.sh_offset + shdr.sh_size) { try elf_file.reportParseError2(self.index, "corrupt section: extends past the end of file", .{}); return error.MalformedObject; } } - self.shdrs.appendAssumeCapacity(try ElfShdr.fromElf64Shdr(shdr)); } - const shstrtab = self.shdrContents(self.header.?.e_shstrndx); - for (shdrs) |shdr| { + const shstrtab = try self.preadShdrContentsAlloc(gpa, handle, self.header.?.e_shstrndx); + defer gpa.free(shstrtab); + for (self.shdrs.items) |shdr| { if (shdr.sh_name >= shstrtab.len) { try elf_file.reportParseError2(self.index, "corrupt section name offset", .{}); return error.MalformedObject; @@ -112,10 +117,11 @@ pub fn parse(self: *Object, elf_file: *Elf) !void { } else null; if (symtab_index) |index| { - const shdr = shdrs[index]; + const shdr = self.shdrs.items[index]; self.first_global = shdr.sh_info; - const raw_symtab = self.shdrContents(index); + const raw_symtab = try self.preadShdrContentsAlloc(gpa, handle, index); + defer gpa.free(raw_symtab); const nsyms = math.divExact(usize, raw_symtab.len, @sizeOf(elf.Elf64_Sym)) catch { try elf_file.reportParseError2(self.index, "symbol table not evenly divisible", .{}); return error.MalformedObject; @@ -123,7 +129,9 @@ pub fn parse(self: *Object, elf_file: *Elf) !void { const symtab = @as([*]align(1) const elf.Elf64_Sym, @ptrCast(raw_symtab.ptr))[0..nsyms]; const strtab_bias = @as(u32, @intCast(self.strtab.items.len)); - try self.strtab.appendSlice(gpa, self.shdrContents(@as(u16, @intCast(shdr.sh_link)))); + const strtab = try self.preadShdrContentsAlloc(gpa, handle, shdr.sh_link); + defer gpa.free(strtab); + try self.strtab.appendSlice(gpa, strtab); try self.symtab.ensureUnusedCapacity(gpa, symtab.len); for (symtab) |sym| { @@ -138,22 +146,23 @@ pub fn parse(self: *Object, elf_file: *Elf) !void { } pub fn init(self: *Object, elf_file: *Elf) !void { - try self.initAtoms(elf_file); - try self.initSymtab(elf_file); + const gpa = elf_file.base.comp.gpa; + const handle = elf_file.fileHandle(self.file_handle); + + try self.initAtoms(gpa, handle, elf_file); + try self.initSymtab(gpa, elf_file); for (self.shdrs.items, 0..) |shdr, i| { const atom = elf_file.atom(self.atoms.items[i]) orelse continue; if (!atom.flags.alive) continue; if (shdr.sh_type == elf.SHT_X86_64_UNWIND or mem.eql(u8, atom.name(elf_file), ".eh_frame")) - try self.parseEhFrame(@as(u16, @intCast(i)), elf_file); + try self.parseEhFrame(gpa, handle, @as(u32, @intCast(i)), elf_file); } } -fn initAtoms(self: *Object, elf_file: *Elf) !void { - const comp = elf_file.base.comp; - const gpa = comp.gpa; +fn initAtoms(self: *Object, allocator: Allocator, handle: std.fs.File, elf_file: *Elf) !void { const shdrs = self.shdrs.items; - try self.atoms.resize(gpa, shdrs.len); + try self.atoms.resize(allocator, shdrs.len); @memset(self.atoms.items, 0); for (shdrs, 0..) |shdr, i| { @@ -177,8 +186,9 @@ fn initAtoms(self: *Object, elf_file: *Elf) !void { break :blk self.getString(group_info_sym.st_name); }; - const shndx = @as(u16, @intCast(i)); - const group_raw_data = self.shdrContents(shndx); + const shndx = @as(u32, @intCast(i)); + const group_raw_data = try self.preadShdrContentsAlloc(allocator, handle, shndx); + defer allocator.free(group_raw_data); const group_nmembers = @divExact(group_raw_data.len, @sizeOf(u32)); const group_members = @as([*]align(1) const u32, @ptrCast(group_raw_data.ptr))[0..group_nmembers]; @@ -188,14 +198,20 @@ fn initAtoms(self: *Object, elf_file: *Elf) !void { continue; } + const group_start = @as(u32, @intCast(self.comdat_group_data.items.len)); + try self.comdat_group_data.appendUnalignedSlice(allocator, group_members[1..]); + const gop = try elf_file.getOrCreateComdatGroupOwner(group_signature); const comdat_group_index = try elf_file.addComdatGroup(); const comdat_group = elf_file.comdatGroup(comdat_group_index); comdat_group.* = .{ .owner = gop.index, + .file = self.index, .shndx = shndx, + .members_start = group_start, + .members_len = @intCast(group_nmembers - 1), }; - try self.comdat_groups.append(gpa, comdat_group_index); + try self.comdat_groups.append(allocator, comdat_group_index); }, elf.SHT_SYMTAB_SHNDX => @panic("TODO SHT_SYMTAB_SHNDX"), @@ -210,7 +226,7 @@ fn initAtoms(self: *Object, elf_file: *Elf) !void { else => { const shndx = @as(u16, @intCast(i)); if (self.skipShdr(shndx, elf_file)) continue; - try self.addAtom(shdr, shndx, elf_file); + try self.addAtom(allocator, handle, shdr, shndx, elf_file); }, } } @@ -220,14 +236,19 @@ fn initAtoms(self: *Object, elf_file: *Elf) !void { elf.SHT_REL, elf.SHT_RELA => { const atom_index = self.atoms.items[shdr.sh_info]; if (elf_file.atom(atom_index)) |atom| { - atom.relocs_section_index = @as(u16, @intCast(i)); + const relocs = try self.preadRelocsAlloc(allocator, handle, @intCast(i)); + defer allocator.free(relocs); + atom.relocs_section_index = @intCast(i); + atom.rel_index = @intCast(self.relocs.items.len); + atom.rel_num = @intCast(relocs.len); + try self.relocs.appendUnalignedSlice(allocator, relocs); } }, else => {}, }; } -fn addAtom(self: *Object, shdr: ElfShdr, shndx: u16, elf_file: *Elf) error{OutOfMemory}!void { +fn addAtom(self: *Object, allocator: Allocator, handle: std.fs.File, shdr: elf.Elf64_Shdr, shndx: u32, elf_file: *Elf) !void { const atom_index = try elf_file.addAtom(); const atom = elf_file.atom(atom_index).?; atom.atom_index = atom_index; @@ -237,7 +258,8 @@ fn addAtom(self: *Object, shdr: ElfShdr, shndx: u16, elf_file: *Elf) error{OutOf self.atoms.items[shndx] = atom_index; if (shdr.sh_flags & elf.SHF_COMPRESSED != 0) { - const data = self.shdrContents(shndx); + const data = try self.preadShdrContentsAlloc(allocator, handle, shndx); + defer allocator.free(data); const chdr = @as(*align(1) const elf.Elf64_Chdr, @ptrCast(data.ptr)).*; atom.size = chdr.ch_size; atom.alignment = Alignment.fromNonzeroByteUnits(chdr.ch_addralign); @@ -247,7 +269,7 @@ fn addAtom(self: *Object, shdr: ElfShdr, shndx: u16, elf_file: *Elf) error{OutOf } } -fn initOutputSection(self: Object, elf_file: *Elf, shdr: ElfShdr) error{OutOfMemory}!u16 { +fn initOutputSection(self: Object, elf_file: *Elf, shdr: elf.Elf64_Shdr) error{OutOfMemory}!u16 { const name = blk: { const name = self.getString(shdr.sh_name); if (elf_file.base.isRelocatable()) break :blk name; @@ -310,12 +332,10 @@ fn skipShdr(self: *Object, index: u16, elf_file: *Elf) bool { return ignore; } -fn initSymtab(self: *Object, elf_file: *Elf) !void { - const comp = elf_file.base.comp; - const gpa = comp.gpa; +fn initSymtab(self: *Object, allocator: Allocator, elf_file: *Elf) !void { const first_global = self.first_global orelse self.symtab.items.len; - try self.symbols.ensureTotalCapacityPrecise(gpa, self.symtab.items.len); + try self.symbols.ensureTotalCapacityPrecise(allocator, self.symtab.items.len); for (self.symtab.items[0..first_global], 0..) |sym, i| { const index = try elf_file.addSymbol(); @@ -335,19 +355,24 @@ fn initSymtab(self: *Object, elf_file: *Elf) !void { } } -fn parseEhFrame(self: *Object, shndx: u16, elf_file: *Elf) !void { +fn parseEhFrame(self: *Object, allocator: Allocator, handle: std.fs.File, shndx: u32, elf_file: *Elf) !void { const relocs_shndx = for (self.shdrs.items, 0..) |shdr, i| switch (shdr.sh_type) { - elf.SHT_RELA => if (shdr.sh_info == shndx) break @as(u16, @intCast(i)), + elf.SHT_RELA => if (shdr.sh_info == shndx) break @as(u32, @intCast(i)), else => {}, } else { + // TODO: convert into an error log.debug("{s}: missing reloc section for unwind info section", .{self.fmtPath()}); return; }; - const comp = elf_file.base.comp; - const gpa = comp.gpa; - const raw = self.shdrContents(shndx); - const relocs = self.getRelocs(relocs_shndx); + const raw = try self.preadShdrContentsAlloc(allocator, handle, shndx); + defer allocator.free(raw); + const data_start = @as(u32, @intCast(self.eh_frame_data.items.len)); + try self.eh_frame_data.appendSlice(allocator, raw); + const relocs = try self.preadRelocsAlloc(allocator, handle, relocs_shndx); + defer allocator.free(relocs); + const rel_start = @as(u32, @intCast(self.relocs.items.len)); + try self.relocs.appendUnalignedSlice(allocator, relocs); const fdes_start = self.fdes.items.len; const cies_start = self.cies.items.len; @@ -355,22 +380,20 @@ fn parseEhFrame(self: *Object, shndx: u16, elf_file: *Elf) !void { while (try it.next()) |rec| { const rel_range = filterRelocs(relocs, rec.offset, rec.size + 4); switch (rec.tag) { - .cie => try self.cies.append(gpa, .{ - .offset = rec.offset, + .cie => try self.cies.append(allocator, .{ + .offset = data_start + rec.offset, .size = rec.size, - .rel_index = @as(u32, @intCast(rel_range.start)), + .rel_index = rel_start + @as(u32, @intCast(rel_range.start)), .rel_num = @as(u32, @intCast(rel_range.len)), - .rel_section_index = relocs_shndx, .input_section_index = shndx, .file_index = self.index, }), - .fde => try self.fdes.append(gpa, .{ - .offset = rec.offset, + .fde => try self.fdes.append(allocator, .{ + .offset = data_start + rec.offset, .size = rec.size, .cie_index = undefined, - .rel_index = @as(u32, @intCast(rel_range.start)), + .rel_index = rel_start + @as(u32, @intCast(rel_range.start)), .rel_num = @as(u32, @intCast(rel_range.len)), - .rel_section_index = relocs_shndx, .input_section_index = shndx, .file_index = self.index, }), @@ -773,21 +796,30 @@ pub fn updateArSymtab(self: Object, ar_symtab: *Archive.ArSymtab, elf_file: *Elf } } -pub fn updateArSize(self: *Object) void { - self.output_ar_state.size = self.data.len; +pub fn updateArSize(self: *Object, elf_file: *Elf) !void { + const handle = elf_file.fileHandle(self.file_handle); + const size = (try handle.stat()).size; + self.output_ar_state.size = size; } -pub fn writeAr(self: Object, writer: anytype) !void { +pub fn writeAr(self: Object, elf_file: *Elf, writer: anytype) !void { + const size = std.math.cast(usize, self.output_ar_state.size) orelse return error.Overflow; const name = self.path; const hdr = Archive.setArHdr(.{ .name = if (name.len <= Archive.max_member_name_len) .{ .name = name } else .{ .name_off = self.output_ar_state.name_off }, - .size = @intCast(self.data.len), + .size = size, }); try writer.writeAll(mem.asBytes(&hdr)); - try writer.writeAll(self.data); + const handle = elf_file.fileHandle(self.file_handle); + const gpa = elf_file.base.comp.gpa; + const data = try gpa.alloc(u8, size); + defer gpa.free(data); + const amt = try handle.preadAll(data, 0); + if (amt != size) return error.InputOutput; + try writer.writeAll(data); } pub fn updateSymtabSize(self: *Object, elf_file: *Elf) !void { @@ -859,12 +891,6 @@ pub fn globals(self: Object) []const Symbol.Index { return self.symbols.items[start..]; } -pub fn shdrContents(self: Object, index: u32) []const u8 { - assert(index < self.shdrs.items.len); - const shdr = self.shdrs.items[index]; - return self.data[shdr.sh_offset..][0..shdr.sh_size]; -} - /// Returns atom's code and optionally uncompresses data if required (for compressed sections). /// Caller owns the memory. pub 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) const gpa = comp.gpa; const atom_ptr = elf_file.atom(atom_index).?; assert(atom_ptr.file_index == self.index); - const data = self.shdrContents(atom_ptr.input_section_index); const shdr = atom_ptr.inputShdr(elf_file); + const handle = elf_file.fileHandle(self.file_handle); + const data = try self.preadShdrContentsAlloc(gpa, handle, atom_ptr.input_section_index); + defer if (shdr.sh_flags & elf.SHF_COMPRESSED != 0) gpa.free(data); + if (shdr.sh_flags & elf.SHF_COMPRESSED != 0) { const chdr = @as(*align(1) const elf.Elf64_Chdr, @ptrCast(data.ptr)).*; switch (chdr.ch_type) { @@ -892,31 +921,35 @@ pub fn codeDecompressAlloc(self: Object, elf_file: *Elf, atom_index: Atom.Index) }, else => @panic("TODO unhandled compression scheme"), } - } else return gpa.dupe(u8, data); -} + } -pub fn comdatGroupMembers(self: *Object, index: u16) []align(1) const u32 { - const raw = self.shdrContents(index); - const nmembers = @divExact(raw.len, @sizeOf(u32)); - const members = @as([*]align(1) const u32, @ptrCast(raw.ptr))[1..nmembers]; - return members; + return data; } pub fn asFile(self: *Object) File { return .{ .object = self }; } -pub fn getRelocs(self: *Object, shndx: u32) []align(1) const elf.Elf64_Rela { - const raw = self.shdrContents(shndx); - const num = @divExact(raw.len, @sizeOf(elf.Elf64_Rela)); - return @as([*]align(1) const elf.Elf64_Rela, @ptrCast(raw.ptr))[0..num]; -} - pub fn getString(self: Object, off: u32) [:0]const u8 { assert(off < self.strtab.items.len); return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.strtab.items.ptr + off)), 0); } +/// Caller owns the memory. +fn preadShdrContentsAlloc(self: Object, allocator: Allocator, handle: std.fs.File, index: u32) ![]u8 { + assert(index < self.shdrs.items.len); + const offset = if (self.archive) |ar| ar.offset else 0; + const shdr = self.shdrs.items[index]; + return Elf.preadAllAlloc(allocator, handle, offset + shdr.sh_offset, shdr.sh_size); +} + +/// Caller owns the memory. +fn preadRelocsAlloc(self: Object, allocator: Allocator, handle: std.fs.File, shndx: u32) ![]align(1) const elf.Elf64_Rela { + const raw = try self.preadShdrContentsAlloc(allocator, handle, shndx); + const num = @divExact(raw.len, @sizeOf(elf.Elf64_Rela)); + return @as([*]align(1) const elf.Elf64_Rela, @ptrCast(raw.ptr))[0..num]; +} + pub fn format( self: *Object, comptime unused_fmt_string: []const u8, @@ -1053,7 +1086,7 @@ fn formatComdatGroups( const cg_owner = elf_file.comdatGroupOwner(cg.owner); if (cg_owner.file != object.index) continue; try writer.print(" COMDAT({d})\n", .{cg_index}); - const cg_members = object.comdatGroupMembers(cg.shndx); + const cg_members = cg.comdatGroupMembers(elf_file); for (cg_members) |shndx| { const atom_index = object.atoms.items[shndx]; const atom = elf_file.atom(atom_index) orelse continue; @@ -1074,40 +1107,17 @@ fn formatPath( ) !void { _ = unused_fmt_string; _ = options; - if (object.archive) |path| { - try writer.writeAll(path); + if (object.archive) |ar| { + try writer.writeAll(ar.path); try writer.writeByte('('); try writer.writeAll(object.path); try writer.writeByte(')'); } else try writer.writeAll(object.path); } -pub const ElfShdr = struct { - sh_name: u32, - sh_type: u32, - sh_flags: u64, - sh_addr: u64, - sh_offset: usize, - sh_size: usize, - sh_link: u32, - sh_info: u32, - sh_addralign: u64, - sh_entsize: u64, - - pub fn fromElf64Shdr(shdr: elf.Elf64_Shdr) error{Overflow}!ElfShdr { - return .{ - .sh_name = shdr.sh_name, - .sh_type = shdr.sh_type, - .sh_flags = shdr.sh_flags, - .sh_addr = shdr.sh_addr, - .sh_offset = math.cast(usize, shdr.sh_offset) orelse return error.Overflow, - .sh_size = math.cast(usize, shdr.sh_size) orelse return error.Overflow, - .sh_link = shdr.sh_link, - .sh_info = shdr.sh_info, - .sh_addralign = shdr.sh_addralign, - .sh_entsize = shdr.sh_entsize, - }; - } +const InArchive = struct { + path: []const u8, + offset: u64, }; const Object = @This(); diff --git a/src/link/Elf/SharedObject.zig b/src/link/Elf/SharedObject.zig index 658090ef51..d40367f304 100644 --- a/src/link/Elf/SharedObject.zig +++ b/src/link/Elf/SharedObject.zig @@ -1,22 +1,18 @@ path: []const u8, -data: []const u8, index: File.Index, header: ?elf.Elf64_Ehdr = null, -shdrs: std.ArrayListUnmanaged(ElfShdr) = .{}, +shdrs: std.ArrayListUnmanaged(elf.Elf64_Shdr) = .{}, symtab: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{}, strtab: std.ArrayListUnmanaged(u8) = .{}, /// Version symtab contains version strings of the symbols if present. versyms: std.ArrayListUnmanaged(elf.Elf64_Versym) = .{}, verstrings: std.ArrayListUnmanaged(u32) = .{}, + symbols: std.ArrayListUnmanaged(Symbol.Index) = .{}, aliases: ?std.ArrayListUnmanaged(u32) = null, - -dynsym_sect_index: ?u16 = null, -dynamic_sect_index: ?u16 = null, -versym_sect_index: ?u16 = null, -verdef_sect_index: ?u16 = null, +dynamic_table: std.ArrayListUnmanaged(elf.Elf64_Dyn) = .{}, needed: bool, alive: bool, @@ -36,23 +32,24 @@ pub fn isSharedObject(path: []const u8) !bool { pub fn deinit(self: *SharedObject, allocator: Allocator) void { allocator.free(self.path); - allocator.free(self.data); + self.shdrs.deinit(allocator); self.symtab.deinit(allocator); self.strtab.deinit(allocator); self.versyms.deinit(allocator); self.verstrings.deinit(allocator); self.symbols.deinit(allocator); if (self.aliases) |*aliases| aliases.deinit(allocator); - self.shdrs.deinit(allocator); + self.dynamic_table.deinit(allocator); } -pub fn parse(self: *SharedObject, elf_file: *Elf) !void { +pub fn parse(self: *SharedObject, elf_file: *Elf, handle: std.fs.File) !void { const comp = elf_file.base.comp; const gpa = comp.gpa; - var stream = std.io.fixedBufferStream(self.data); - const reader = stream.reader(); + const file_size = (try handle.stat()).size; - self.header = try reader.readStruct(elf.Elf64_Ehdr); + const header_buffer = try Elf.preadAllAlloc(gpa, handle, 0, @sizeOf(elf.Elf64_Ehdr)); + defer gpa.free(header_buffer); + self.header = @as(*align(1) const elf.Elf64_Ehdr, @ptrCast(header_buffer)).*; const target = elf_file.base.comp.root_mod.resolved_target.result; if (target.cpu.arch != self.header.?.e_machine.toTargetCpuArch().?) { @@ -64,9 +61,10 @@ pub fn parse(self: *SharedObject, elf_file: *Elf) !void { return error.InvalidCpuArch; } - if (self.data.len < self.header.?.e_shoff or - self.data.len < self.header.?.e_shoff + @as(u64, @intCast(self.header.?.e_shnum)) * @sizeOf(elf.Elf64_Shdr)) - { + const shoff = std.math.cast(usize, self.header.?.e_shoff) orelse return error.Overflow; + const shnum = std.math.cast(usize, self.header.?.e_shnum) orelse return error.Overflow; + const shsize = shnum * @sizeOf(elf.Elf64_Shdr); + if (file_size < shoff or file_size < shoff + shsize) { try elf_file.reportParseError2( self.index, "corrupted header: section header table extends past the end of file", @@ -75,45 +73,84 @@ pub fn parse(self: *SharedObject, elf_file: *Elf) !void { return error.MalformedObject; } - const shoff = std.math.cast(usize, self.header.?.e_shoff) orelse return error.Overflow; - - const shdrs = @as( - [*]align(1) const elf.Elf64_Shdr, - @ptrCast(self.data.ptr + shoff), - )[0..self.header.?.e_shnum]; - try self.shdrs.ensureTotalCapacityPrecise(gpa, shdrs.len); + const shdrs_buffer = try Elf.preadAllAlloc(gpa, handle, shoff, shsize); + defer gpa.free(shdrs_buffer); + const shdrs = @as([*]align(1) const elf.Elf64_Shdr, @ptrCast(shdrs_buffer.ptr))[0..shnum]; + try self.shdrs.appendUnalignedSlice(gpa, shdrs); - for (shdrs, 0..) |shdr, i| { + var dynsym_sect_index: ?u32 = null; + var dynamic_sect_index: ?u32 = null; + var versym_sect_index: ?u32 = null; + var verdef_sect_index: ?u32 = null; + for (self.shdrs.items, 0..) |shdr, i| { if (shdr.sh_type != elf.SHT_NOBITS) { - if (self.data.len < shdr.sh_offset or self.data.len < shdr.sh_offset + shdr.sh_size) { + if (file_size < shdr.sh_offset or file_size < shdr.sh_offset + shdr.sh_size) { try elf_file.reportParseError2(self.index, "corrupted section header", .{}); return error.MalformedObject; } } - self.shdrs.appendAssumeCapacity(try ElfShdr.fromElf64Shdr(shdr)); switch (shdr.sh_type) { - elf.SHT_DYNSYM => self.dynsym_sect_index = @as(u16, @intCast(i)), - elf.SHT_DYNAMIC => self.dynamic_sect_index = @as(u16, @intCast(i)), - elf.SHT_GNU_VERSYM => self.versym_sect_index = @as(u16, @intCast(i)), - elf.SHT_GNU_VERDEF => self.verdef_sect_index = @as(u16, @intCast(i)), + elf.SHT_DYNSYM => dynsym_sect_index = @intCast(i), + elf.SHT_DYNAMIC => dynamic_sect_index = @intCast(i), + elf.SHT_GNU_VERSYM => versym_sect_index = @intCast(i), + elf.SHT_GNU_VERDEF => verdef_sect_index = @intCast(i), else => {}, } } - try self.parseVersions(elf_file); + if (dynamic_sect_index) |index| { + const shdr = self.shdrs.items[index]; + const raw = try Elf.preadAllAlloc(gpa, handle, shdr.sh_offset, shdr.sh_size); + defer gpa.free(raw); + const num = @divExact(raw.len, @sizeOf(elf.Elf64_Dyn)); + const dyntab = @as([*]align(1) const elf.Elf64_Dyn, @ptrCast(raw.ptr))[0..num]; + try self.dynamic_table.appendUnalignedSlice(gpa, dyntab); + } + + const symtab = if (dynsym_sect_index) |index| blk: { + const shdr = self.shdrs.items[index]; + const buffer = try Elf.preadAllAlloc(gpa, handle, shdr.sh_offset, shdr.sh_size); + const nsyms = @divExact(buffer.len, @sizeOf(elf.Elf64_Sym)); + break :blk @as([*]align(1) const elf.Elf64_Sym, @ptrCast(buffer.ptr))[0..nsyms]; + } else &[0]elf.Elf64_Sym{}; + defer gpa.free(symtab); + + const strtab = if (dynsym_sect_index) |index| blk: { + const symtab_shdr = self.shdrs.items[index]; + const shdr = self.shdrs.items[symtab_shdr.sh_link]; + const buffer = try Elf.preadAllAlloc(gpa, handle, shdr.sh_offset, shdr.sh_size); + break :blk buffer; + } else &[0]u8{}; + defer gpa.free(strtab); + + try self.parseVersions(elf_file, handle, .{ + .symtab = symtab, + .verdef_sect_index = verdef_sect_index, + .versym_sect_index = versym_sect_index, + }); + + try self.initSymtab(elf_file, .{ + .symtab = symtab, + .strtab = strtab, + }); } -fn parseVersions(self: *SharedObject, elf_file: *Elf) !void { +fn parseVersions(self: *SharedObject, elf_file: *Elf, handle: std.fs.File, opts: struct { + symtab: []align(1) const elf.Elf64_Sym, + verdef_sect_index: ?u32, + versym_sect_index: ?u32, +}) !void { const comp = elf_file.base.comp; const gpa = comp.gpa; - const symtab = self.getSymtabRaw(); try self.verstrings.resize(gpa, 2); self.verstrings.items[elf.VER_NDX_LOCAL] = 0; self.verstrings.items[elf.VER_NDX_GLOBAL] = 0; - if (self.verdef_sect_index) |shndx| { - const verdefs = self.shdrContents(shndx); + if (opts.verdef_sect_index) |shndx| { + const shdr = self.shdrs.items[shndx]; + const verdefs = try Elf.preadAllAlloc(gpa, handle, shdr.sh_offset, shdr.sh_size); + defer gpa.free(verdefs); const nverdefs = self.verdefNum(); try self.verstrings.resize(gpa, self.verstrings.items.len + nverdefs); @@ -131,10 +168,12 @@ fn parseVersions(self: *SharedObject, elf_file: *Elf) !void { } } - try self.versyms.ensureTotalCapacityPrecise(gpa, symtab.len); + try self.versyms.ensureTotalCapacityPrecise(gpa, opts.symtab.len); - if (self.versym_sect_index) |shndx| { - const versyms_raw = self.shdrContents(shndx); + if (opts.versym_sect_index) |shndx| { + const shdr = self.shdrs.items[shndx]; + const versyms_raw = try Elf.preadAllAlloc(gpa, handle, shdr.sh_offset, shdr.sh_size); + defer gpa.free(versyms_raw); const nversyms = @divExact(versyms_raw.len, @sizeOf(elf.Elf64_Versym)); const versyms = @as([*]align(1) const elf.Elf64_Versym, @ptrCast(versyms_raw.ptr))[0..nversyms]; for (versyms) |ver| { @@ -144,22 +183,23 @@ fn parseVersions(self: *SharedObject, elf_file: *Elf) !void { ver; self.versyms.appendAssumeCapacity(normalized_ver); } - } else for (0..symtab.len) |_| { + } else for (0..opts.symtab.len) |_| { self.versyms.appendAssumeCapacity(elf.VER_NDX_GLOBAL); } } -pub fn init(self: *SharedObject, elf_file: *Elf) !void { +fn initSymtab(self: *SharedObject, elf_file: *Elf, opts: struct { + symtab: []align(1) const elf.Elf64_Sym, + strtab: []const u8, +}) !void { const comp = elf_file.base.comp; const gpa = comp.gpa; - const symtab = self.getSymtabRaw(); - const strtab = self.getStrtabRaw(); - try self.strtab.appendSlice(gpa, strtab); - try self.symtab.ensureTotalCapacityPrecise(gpa, symtab.len); - try self.symbols.ensureTotalCapacityPrecise(gpa, symtab.len); + try self.strtab.appendSlice(gpa, opts.strtab); + try self.symtab.ensureTotalCapacityPrecise(gpa, opts.symtab.len); + try self.symbols.ensureTotalCapacityPrecise(gpa, opts.symtab.len); - for (symtab, 0..) |sym, i| { + for (opts.symtab, 0..) |sym, i| { const hidden = self.versyms.items[i] & elf.VERSYM_HIDDEN != 0; const name = self.getString(sym.st_name); // 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 { } } -pub fn shdrContents(self: SharedObject, index: u16) []const u8 { - const shdr = self.shdrs.items[index]; - return self.data[shdr.sh_offset..][0..shdr.sh_size]; -} - pub fn versionString(self: SharedObject, index: elf.Elf64_Versym) [:0]const u8 { const off = self.verstrings.items[index & elf.VERSYM_VERSION]; return self.getString(off); @@ -264,16 +299,8 @@ pub fn asFile(self: *SharedObject) File { return .{ .shared_object = self }; } -fn dynamicTable(self: *SharedObject) []align(1) const elf.Elf64_Dyn { - const shndx = self.dynamic_sect_index orelse return &[0]elf.Elf64_Dyn{}; - const raw = self.shdrContents(shndx); - const num = @divExact(raw.len, @sizeOf(elf.Elf64_Dyn)); - return @as([*]align(1) const elf.Elf64_Dyn, @ptrCast(raw.ptr))[0..num]; -} - fn verdefNum(self: *SharedObject) u32 { - const entries = self.dynamicTable(); - for (entries) |entry| switch (entry.d_tag) { + for (self.dynamic_table.items) |entry| switch (entry.d_tag) { elf.DT_VERDEFNUM => return @as(u32, @intCast(entry.d_val)), else => {}, }; @@ -281,8 +308,7 @@ fn verdefNum(self: *SharedObject) u32 { } pub fn soname(self: *SharedObject) []const u8 { - const entries = self.dynamicTable(); - for (entries) |entry| switch (entry.d_tag) { + for (self.dynamic_table.items) |entry| switch (entry.d_tag) { elf.DT_SONAME => return self.getString(@as(u32, @intCast(entry.d_val))), else => {}, }; @@ -342,20 +368,6 @@ pub fn getString(self: SharedObject, off: u32) [:0]const u8 { return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.strtab.items.ptr + off)), 0); } -pub fn getSymtabRaw(self: SharedObject) []align(1) const elf.Elf64_Sym { - const index = self.dynsym_sect_index orelse return &[0]elf.Elf64_Sym{}; - const raw_symtab = self.shdrContents(index); - const nsyms = @divExact(raw_symtab.len, @sizeOf(elf.Elf64_Sym)); - const symtab = @as([*]align(1) const elf.Elf64_Sym, @ptrCast(raw_symtab.ptr))[0..nsyms]; - return symtab; -} - -pub fn getStrtabRaw(self: SharedObject) []const u8 { - const index = self.dynsym_sect_index orelse return &[0]u8{}; - const shdr = self.shdrs.items[index]; - return self.shdrContents(@as(u16, @intCast(shdr.sh_link))); -} - pub fn format( self: SharedObject, comptime unused_fmt_string: []const u8, @@ -407,6 +419,5 @@ const mem = std.mem; const Allocator = mem.Allocator; const Elf = @import("../Elf.zig"); -const ElfShdr = @import("Object.zig").ElfShdr; const File = @import("file.zig").File; const Symbol = @import("Symbol.zig"); diff --git a/src/link/Elf/ZigObject.zig b/src/link/Elf/ZigObject.zig index f3ba16f243..a132b1d453 100644 --- a/src/link/Elf/ZigObject.zig +++ b/src/link/Elf/ZigObject.zig @@ -305,19 +305,16 @@ pub fn addAtom(self: *ZigObject, elf_file: *Elf) !Symbol.Index { } /// TODO actually create fake input shdrs and return that instead. -pub fn inputShdr(self: ZigObject, atom_index: Atom.Index, elf_file: *Elf) Object.ElfShdr { +pub fn inputShdr(self: ZigObject, atom_index: Atom.Index, elf_file: *Elf) elf.Elf64_Shdr { _ = self; - const shdr = shdr: { - const atom = elf_file.atom(atom_index) orelse break :shdr Elf.null_shdr; - const shndx = atom.outputShndx() orelse break :shdr Elf.null_shdr; - var shdr = elf_file.shdrs.items[shndx]; - shdr.sh_addr = 0; - shdr.sh_offset = 0; - shdr.sh_size = atom.size; - shdr.sh_addralign = atom.alignment.toByteUnits(1); - break :shdr shdr; - }; - return Object.ElfShdr.fromElf64Shdr(shdr) catch unreachable; + const atom = elf_file.atom(atom_index) orelse return Elf.null_shdr; + const shndx = atom.outputShndx() orelse return Elf.null_shdr; + var shdr = elf_file.shdrs.items[shndx]; + shdr.sh_addr = 0; + shdr.sh_offset = 0; + shdr.sh_size = atom.size; + shdr.sh_addralign = atom.alignment.toByteUnits(1); + return shdr; } pub fn resolveSymbols(self: *ZigObject, elf_file: *Elf) void { @@ -525,7 +522,7 @@ pub fn writeAr(self: ZigObject, writer: anytype) !void { .{ .name = name } else .{ .name_off = self.output_ar_state.name_off }, - .size = @intCast(self.data.items.len), + .size = self.data.items.len, }); try writer.writeAll(mem.asBytes(&hdr)); try writer.writeAll(self.data.items); diff --git a/src/link/Elf/eh_frame.zig b/src/link/Elf/eh_frame.zig index 75401824ab..4825ddb476 100644 --- a/src/link/Elf/eh_frame.zig +++ b/src/link/Elf/eh_frame.zig @@ -5,7 +5,6 @@ pub const Fde = struct { cie_index: u32, rel_index: u32 = 0, rel_num: u32 = 0, - rel_section_index: u32 = 0, input_section_index: u32 = 0, file_index: u32 = 0, alive: bool = true, @@ -20,10 +19,9 @@ pub const Fde = struct { return base + fde.out_offset; } - pub fn data(fde: Fde, elf_file: *Elf) []const u8 { + pub fn data(fde: Fde, elf_file: *Elf) []u8 { const object = elf_file.file(fde.file_index).?.object; - const contents = object.shdrContents(fde.input_section_index); - return contents[fde.offset..][0..fde.calcSize()]; + return object.eh_frame_data.items[fde.offset..][0..fde.calcSize()]; } pub fn cie(fde: Fde, elf_file: *Elf) Cie { @@ -50,7 +48,7 @@ pub const Fde = struct { pub fn relocs(fde: Fde, elf_file: *Elf) []align(1) const elf.Elf64_Rela { const object = elf_file.file(fde.file_index).?.object; - return object.getRelocs(fde.rel_section_index)[fde.rel_index..][0..fde.rel_num]; + return object.relocs.items[fde.rel_index..][0..fde.rel_num]; } pub fn format( @@ -106,7 +104,6 @@ pub const Cie = struct { size: usize, rel_index: u32 = 0, rel_num: u32 = 0, - rel_section_index: u32 = 0, input_section_index: u32 = 0, file_index: u32 = 0, /// Includes 4byte size cell. @@ -121,10 +118,9 @@ pub const Cie = struct { return base + cie.out_offset; } - pub fn data(cie: Cie, elf_file: *Elf) []const u8 { + pub fn data(cie: Cie, elf_file: *Elf) []u8 { const object = elf_file.file(cie.file_index).?.object; - const contents = object.shdrContents(cie.input_section_index); - return contents[cie.offset..][0..cie.calcSize()]; + return object.eh_frame_data.items[cie.offset..][0..cie.calcSize()]; } pub fn calcSize(cie: Cie) usize { @@ -133,7 +129,7 @@ pub const Cie = struct { pub fn relocs(cie: Cie, elf_file: *Elf) []align(1) const elf.Elf64_Rela { const object = elf_file.file(cie.file_index).?.object; - return object.getRelocs(cie.rel_section_index)[cie.rel_index..][0..cie.rel_num]; + return object.relocs.items[cie.rel_index..][0..cie.rel_num]; } 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: } pub fn writeEhFrame(elf_file: *Elf, writer: anytype) !void { - const comp = elf_file.base.comp; - const gpa = comp.gpa; - relocs_log.debug("{x}: .eh_frame", .{elf_file.shdrs.items[elf_file.eh_frame_section_index.?].sh_addr}); for (elf_file.objects.items) |index| { @@ -341,8 +334,7 @@ pub fn writeEhFrame(elf_file: *Elf, writer: anytype) !void { for (object.cies.items) |cie| { if (!cie.alive) continue; - const contents = try gpa.dupe(u8, cie.data(elf_file)); - defer gpa.free(contents); + const contents = cie.data(elf_file); for (cie.relocs(elf_file)) |rel| { const sym = elf_file.symbol(object.symbols.items[rel.r_sym()]); @@ -359,8 +351,7 @@ pub fn writeEhFrame(elf_file: *Elf, writer: anytype) !void { for (object.fdes.items) |fde| { if (!fde.alive) continue; - const contents = try gpa.dupe(u8, fde.data(elf_file)); - defer gpa.free(contents); + const contents = fde.data(elf_file); std.mem.writeInt( i32, @@ -382,9 +373,6 @@ pub fn writeEhFrame(elf_file: *Elf, writer: anytype) !void { } pub fn writeEhFrameObject(elf_file: *Elf, writer: anytype) !void { - const comp = elf_file.base.comp; - const gpa = comp.gpa; - for (elf_file.objects.items) |index| { const object = elf_file.file(index).?.object; @@ -400,8 +388,7 @@ pub fn writeEhFrameObject(elf_file: *Elf, writer: anytype) !void { for (object.fdes.items) |fde| { if (!fde.alive) continue; - const contents = try gpa.dupe(u8, fde.data(elf_file)); - defer gpa.free(contents); + const contents = fde.data(elf_file); std.mem.writeInt( i32, diff --git a/src/link/Elf/file.zig b/src/link/Elf/file.zig index 30222b148a..9f03cb7852 100644 --- a/src/link/Elf/file.zig +++ b/src/link/Elf/file.zig @@ -162,18 +162,18 @@ pub const File = union(enum) { state.name_off = try ar_strtab.insert(allocator, path); } - pub fn updateArSize(file: File) void { + pub fn updateArSize(file: File, elf_file: *Elf) !void { return switch (file) { .zig_object => |x| x.updateArSize(), - .object => |x| x.updateArSize(), + .object => |x| x.updateArSize(elf_file), inline else => unreachable, }; } - pub fn writeAr(file: File, writer: anytype) !void { + pub fn writeAr(file: File, elf_file: *Elf, writer: anytype) !void { return switch (file) { .zig_object => |x| x.writeAr(writer), - .object => |x| x.writeAr(writer), + .object => |x| x.writeAr(elf_file, writer), inline else => unreachable, }; } @@ -187,6 +187,9 @@ pub const File = union(enum) { object: Object, shared_object: SharedObject, }; + + pub const Handle = std.fs.File; + pub const HandleIndex = Index; }; const std = @import("std"); diff --git a/src/link/Elf/synthetic_sections.zig b/src/link/Elf/synthetic_sections.zig index 68a36e14ce..6f76605e31 100644 --- a/src/link/Elf/synthetic_sections.zig +++ b/src/link/Elf/synthetic_sections.zig @@ -1582,15 +1582,14 @@ pub const ComdatGroupSection = struct { pub fn size(cgs: ComdatGroupSection, elf_file: *Elf) usize { const cg = elf_file.comdatGroup(cgs.cg_index); - const object = cgs.file(elf_file).?.object; - const members = object.comdatGroupMembers(cg.shndx); + const members = cg.comdatGroupMembers(elf_file); return (members.len + 1) * @sizeOf(u32); } pub fn write(cgs: ComdatGroupSection, elf_file: *Elf, writer: anytype) !void { const cg = elf_file.comdatGroup(cgs.cg_index); const object = cgs.file(elf_file).?.object; - const members = object.comdatGroupMembers(cg.shndx); + const members = cg.comdatGroupMembers(elf_file); try writer.writeInt(u32, elf.GRP_COMDAT, .little); for (members) |shndx| { const shdr = object.shdrs.items[shndx]; |
