| author | |
| committer | |
| log | a94d5895cfbc7b2e695ba1edaad8f4af3d2081ab |
| tree | dc05ede8334a06346fc7b3339657a7132e5fd973 |
| parent | fad5e7a997344eddc45511df581472acaf0e880e |
9 files changed, 339 insertions(+), 281 deletions(-)
src/link/Elf.zig+58-21| ... | ... | @@ -35,6 +35,10 @@ llvm_object: ?*LlvmObject = null, |
| 35 | 35 | /// Index of each input file also encodes the priority or precedence of one input file |
| 36 | 36 | /// over another. |
| 37 | 37 | files: 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. | |
| 41 | file_handles: std.ArrayListUnmanaged(File.Handle) = .{}, | |
| 38 | 42 | zig_object_index: ?File.Index = null, |
| 39 | 43 | linker_defined_index: ?File.Index = null, |
| 40 | 44 | objects: std.ArrayListUnmanaged(File.Index) = .{}, |
| ... | ... | @@ -444,6 +448,11 @@ pub fn deinit(self: *Elf) void { |
| 444 | 448 | |
| 445 | 449 | if (self.llvm_object) |llvm_object| llvm_object.deinit(); |
| 446 | 450 | |
| 451 | for (self.file_handles.items) |fh| { | |
| 452 | fh.close(); | |
| 453 | } | |
| 454 | self.file_handles.deinit(gpa); | |
| 455 | ||
| 447 | 456 | for (self.files.items(.tags), self.files.items(.data)) |tag, *data| switch (tag) { |
| 448 | 457 | .null => {}, |
| 449 | 458 | .zig_object => data.zig_object.deinit(gpa), |
| ... | ... | @@ -1244,9 +1253,6 @@ pub fn flushModule(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node) |
| 1244 | 1253 | for (self.objects.items) |index| { |
| 1245 | 1254 | try self.file(index).?.object.init(self); |
| 1246 | 1255 | } |
| 1247 | for (self.shared_objects.items) |index| { | |
| 1248 | try self.file(index).?.shared_object.init(self); | |
| 1249 | } | |
| 1250 | 1256 | |
| 1251 | 1257 | if (comp.link_errors.items.len > 0) return error.FlushFailure; |
| 1252 | 1258 | |
| ... | ... | @@ -1463,7 +1469,7 @@ pub fn flushStaticLib(self: *Elf, comp: *Compilation, module_obj_path: ?[]const |
| 1463 | 1469 | for (files.items) |index| { |
| 1464 | 1470 | const file_ptr = self.file(index).?; |
| 1465 | 1471 | try file_ptr.updateArStrtab(gpa, &ar_strtab); |
| 1466 | file_ptr.updateArSize(); | |
| 1472 | try file_ptr.updateArSize(self); | |
| 1467 | 1473 | } |
| 1468 | 1474 | |
| 1469 | 1475 | // Update file offsets of contributing objects. |
| ... | ... | @@ -1515,7 +1521,7 @@ pub fn flushStaticLib(self: *Elf, comp: *Compilation, module_obj_path: ?[]const |
| 1515 | 1521 | // Write object files |
| 1516 | 1522 | for (files.items) |index| { |
| 1517 | 1523 | 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()); | |
| 1519 | 1525 | } |
| 1520 | 1526 | |
| 1521 | 1527 | assert(buffer.items.len == total_size); |
| ... | ... | @@ -1902,13 +1908,13 @@ fn parseObject(self: *Elf, path: []const u8) ParseError!void { |
| 1902 | 1908 | defer tracy.end(); |
| 1903 | 1909 | |
| 1904 | 1910 | 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 | ||
| 1908 | 1914 | const index = @as(File.Index, @intCast(try self.files.addOne(gpa))); |
| 1909 | 1915 | self.files.set(index, .{ .object = .{ |
| 1910 | 1916 | .path = try gpa.dupe(u8, path), |
| 1911 | .data = data, | |
| 1917 | .file_handle = fh, | |
| 1912 | 1918 | .index = index, |
| 1913 | 1919 | } }); |
| 1914 | 1920 | try self.objects.append(gpa, index); |
| ... | ... | @@ -1922,12 +1928,12 @@ fn parseArchive(self: *Elf, path: []const u8, must_link: bool) ParseError!void { |
| 1922 | 1928 | defer tracy.end(); |
| 1923 | 1929 | |
| 1924 | 1930 | 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{}; | |
| 1929 | 1935 | defer archive.deinit(gpa); |
| 1930 | try archive.parse(self); | |
| 1936 | try archive.parse(self, path, fh); | |
| 1931 | 1937 | |
| 1932 | 1938 | const objects = try archive.objects.toOwnedSlice(gpa); |
| 1933 | 1939 | defer gpa.free(objects); |
| ... | ... | @@ -1948,13 +1954,12 @@ fn parseSharedObject(self: *Elf, lib: SystemLib) ParseError!void { |
| 1948 | 1954 | defer tracy.end(); |
| 1949 | 1955 | |
| 1950 | 1956 | 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 | ||
| 1954 | 1960 | const index = @as(File.Index, @intCast(try self.files.addOne(gpa))); |
| 1955 | 1961 | self.files.set(index, .{ .shared_object = .{ |
| 1956 | 1962 | .path = try gpa.dupe(u8, lib.path), |
| 1957 | .data = data, | |
| 1958 | 1963 | .index = index, |
| 1959 | 1964 | .needed = lib.needed, |
| 1960 | 1965 | .alive = lib.needed, |
| ... | ... | @@ -1962,7 +1967,7 @@ fn parseSharedObject(self: *Elf, lib: SystemLib) ParseError!void { |
| 1962 | 1967 | try self.shared_objects.append(gpa, index); |
| 1963 | 1968 | |
| 1964 | 1969 | const shared_object = self.file(index).?.shared_object; |
| 1965 | try shared_object.parse(self); | |
| 1970 | try shared_object.parse(self, handle); | |
| 1966 | 1971 | } |
| 1967 | 1972 | |
| 1968 | 1973 | fn parseLdScript(self: *Elf, lib: SystemLib) ParseError!void { |
| ... | ... | @@ -2135,7 +2140,7 @@ fn resolveSymbols(self: *Elf) void { |
| 2135 | 2140 | const cg = self.comdatGroup(cg_index); |
| 2136 | 2141 | const cg_owner = self.comdatGroupOwner(cg.owner); |
| 2137 | 2142 | if (cg_owner.file != index) { |
| 2138 | for (object.comdatGroupMembers(cg.shndx)) |shndx| { | |
| 2143 | for (cg.comdatGroupMembers(self)) |shndx| { | |
| 2139 | 2144 | const atom_index = object.atoms.items[shndx]; |
| 2140 | 2145 | if (self.atom(atom_index)) |atom_ptr| { |
| 2141 | 2146 | atom_ptr.flags.alive = false; |
| ... | ... | @@ -5862,6 +5867,19 @@ pub fn file(self: *Elf, index: File.Index) ?File { |
| 5862 | 5867 | }; |
| 5863 | 5868 | } |
| 5864 | 5869 | |
| 5870 | pub 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 | ||
| 5878 | pub 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 | ||
| 5865 | 5883 | /// Returns pointer-to-symbol described at sym_index. |
| 5866 | 5884 | pub fn symbol(self: *Elf, sym_index: Symbol.Index) *Symbol { |
| 5867 | 5885 | return &self.symbols.items[sym_index]; |
| ... | ... | @@ -6395,6 +6413,15 @@ fn fmtDumpState( |
| 6395 | 6413 | } |
| 6396 | 6414 | } |
| 6397 | 6415 | |
| 6416 | /// Caller owns the memory. | |
| 6417 | pub 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 | ||
| 6398 | 6425 | /// Binary search |
| 6399 | 6426 | pub fn bsearch(comptime T: type, haystack: []align(1) const T, predicate: anytype) usize { |
| 6400 | 6427 | if (!@hasDecl(@TypeOf(predicate), "predicate")) |
| ... | ... | @@ -6441,12 +6468,22 @@ pub const base_tag: link.File.Tag = .elf; |
| 6441 | 6468 | |
| 6442 | 6469 | const ComdatGroupOwner = struct { |
| 6443 | 6470 | file: File.Index = 0, |
| 6471 | ||
| 6444 | 6472 | const Index = u32; |
| 6445 | 6473 | }; |
| 6446 | 6474 | |
| 6447 | 6475 | pub const ComdatGroup = struct { |
| 6448 | 6476 | 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 | ||
| 6450 | 6487 | pub const Index = u32; |
| 6451 | 6488 | }; |
| 6452 | 6489 |
src/link/Elf/Archive.zig+32-24| ... | ... | @@ -1,8 +1,5 @@ |
| 1 | path: []const u8, | |
| 2 | data: []const u8, | |
| 3 | ||
| 4 | 1 | objects: std.ArrayListUnmanaged(Object) = .{}, |
| 5 | strtab: []const u8 = &[0]u8{}, | |
| 2 | strtab: std.ArrayListUnmanaged(u8) = .{}, | |
| 6 | 3 | |
| 7 | 4 | pub fn isArchive(path: []const u8) !bool { |
| 8 | 5 | const file = try std.fs.cwd().openFile(path, .{}); |
| ... | ... | @@ -14,68 +11,79 @@ pub fn isArchive(path: []const u8) !bool { |
| 14 | 11 | } |
| 15 | 12 | |
| 16 | 13 | pub fn deinit(self: *Archive, allocator: Allocator) void { |
| 17 | allocator.free(self.path); | |
| 18 | allocator.free(self.data); | |
| 19 | 14 | self.objects.deinit(allocator); |
| 15 | self.strtab.deinit(allocator); | |
| 20 | 16 | } |
| 21 | 17 | |
| 22 | pub fn parse(self: *Archive, elf_file: *Elf) !void { | |
| 18 | pub fn parse(self: *Archive, elf_file: *Elf, path: []const u8, handle_index: File.HandleIndex) !void { | |
| 23 | 19 | const comp = elf_file.base.comp; |
| 24 | 20 | const gpa = comp.gpa; |
| 21 | const handle = elf_file.fileHandle(handle_index); | |
| 22 | const size = (try handle.stat()).size; | |
| 25 | 23 | |
| 26 | var stream = std.io.fixedBufferStream(self.data); | |
| 27 | const reader = stream.reader(); | |
| 24 | const reader = handle.reader(); | |
| 28 | 25 | _ = try reader.readBytesNoEof(elf.ARMAG.len); |
| 29 | 26 | |
| 27 | var pos: usize = elf.ARMAG.len; | |
| 30 | 28 | 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 | } | |
| 33 | 34 | |
| 34 | 35 | const hdr = try reader.readStruct(elf.ar_hdr); |
| 36 | pos += @sizeOf(elf.ar_hdr); | |
| 35 | 37 | |
| 36 | 38 | 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}", .{ | |
| 38 | 40 | std.fmt.fmtSliceEscapeLower(&hdr.ar_fmag), |
| 39 | 41 | }); |
| 40 | 42 | return error.MalformedArchive; |
| 41 | 43 | } |
| 42 | 44 | |
| 43 | const size = try hdr.size(); | |
| 45 | const obj_size = try hdr.size(); | |
| 44 | 46 | defer { |
| 45 | _ = stream.seekBy(size) catch {}; | |
| 47 | _ = handle.seekBy(obj_size) catch {}; | |
| 48 | pos += obj_size; | |
| 46 | 49 | } |
| 47 | 50 | |
| 48 | 51 | if (hdr.isSymtab() or hdr.isSymtab64()) continue; |
| 49 | 52 | 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; | |
| 51 | 56 | continue; |
| 52 | 57 | } |
| 53 | 58 | if (hdr.isSymdef() or hdr.isSymdefSorted()) continue; |
| 54 | 59 | |
| 55 | 60 | const name = if (hdr.name()) |name| |
| 56 | try gpa.dupe(u8, name) | |
| 61 | name | |
| 57 | 62 | else if (try hdr.nameOffset()) |off| |
| 58 | try gpa.dupe(u8, self.getString(off)) | |
| 63 | self.getString(off) | |
| 59 | 64 | else |
| 60 | 65 | unreachable; |
| 61 | 66 | |
| 62 | 67 | 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, | |
| 66 | 74 | .index = undefined, |
| 67 | 75 | .alive = false, |
| 68 | 76 | }; |
| 69 | 77 | |
| 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 }); | |
| 71 | 79 | |
| 72 | 80 | try self.objects.append(gpa, object); |
| 73 | 81 | } |
| 74 | 82 | } |
| 75 | 83 | |
| 76 | 84 | fn 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); | |
| 79 | 87 | return name[0 .. name.len - 1]; |
| 80 | 88 | } |
| 81 | 89 | |
| ... | ... | @@ -86,7 +94,7 @@ pub fn setArHdr(opts: struct { |
| 86 | 94 | name: []const u8, |
| 87 | 95 | name_off: u32, |
| 88 | 96 | }, |
| 89 | size: u32, | |
| 97 | size: usize, | |
| 90 | 98 | }) elf.ar_hdr { |
| 91 | 99 | var hdr: elf.ar_hdr = .{ |
| 92 | 100 | .ar_name = undefined, |
src/link/Elf/Atom.zig+8-2| ... | ... | @@ -22,6 +22,12 @@ output_section_index: u16 = 0, |
| 22 | 22 | /// Index of the input section containing this atom's relocs. |
| 23 | 23 | relocs_section_index: u32 = 0, |
| 24 | 24 | |
| 25 | /// Start index of the relocations belonging to this atom. | |
| 26 | rel_index: u32 = 0, | |
| 27 | ||
| 28 | /// Number of relocations belonging to this atom. | |
| 29 | rel_num: u32 = 0, | |
| 30 | ||
| 25 | 31 | /// Index of this atom in the linker's atoms table. |
| 26 | 32 | atom_index: Index = 0, |
| 27 | 33 | |
| ... | ... | @@ -52,7 +58,7 @@ pub fn file(self: Atom, elf_file: *Elf) ?File { |
| 52 | 58 | return elf_file.file(self.file_index); |
| 53 | 59 | } |
| 54 | 60 | |
| 55 | pub fn inputShdr(self: Atom, elf_file: *Elf) Object.ElfShdr { | |
| 61 | pub fn inputShdr(self: Atom, elf_file: *Elf) elf.Elf64_Shdr { | |
| 56 | 62 | return switch (self.file(elf_file).?) { |
| 57 | 63 | .object => |x| x.shdrs.items[self.input_section_index], |
| 58 | 64 | .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 { |
| 289 | 295 | const shndx = self.relocsShndx() orelse return &[0]elf.Elf64_Rela{}; |
| 290 | 296 | return switch (self.file(elf_file).?) { |
| 291 | 297 | .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], | |
| 293 | 299 | else => unreachable, |
| 294 | 300 | }; |
| 295 | 301 | } |
src/link/Elf/Object.zig+125-115| ... | ... | @@ -1,10 +1,10 @@ |
| 1 | archive: ?[]const u8 = null, | |
| 1 | archive: ?InArchive = null, | |
| 2 | 2 | path: []const u8, |
| 3 | data: []const u8, | |
| 3 | file_handle: File.HandleIndex, | |
| 4 | 4 | index: File.Index, |
| 5 | 5 | |
| 6 | 6 | header: ?elf.Elf64_Ehdr = null, |
| 7 | shdrs: std.ArrayListUnmanaged(ElfShdr) = .{}, | |
| 7 | shdrs: std.ArrayListUnmanaged(elf.Elf64_Shdr) = .{}, | |
| 8 | 8 | |
| 9 | 9 | symtab: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{}, |
| 10 | 10 | strtab: std.ArrayListUnmanaged(u8) = .{}, |
| ... | ... | @@ -12,9 +12,12 @@ first_global: ?Symbol.Index = null, |
| 12 | 12 | symbols: std.ArrayListUnmanaged(Symbol.Index) = .{}, |
| 13 | 13 | atoms: std.ArrayListUnmanaged(Atom.Index) = .{}, |
| 14 | 14 | comdat_groups: std.ArrayListUnmanaged(Elf.ComdatGroup.Index) = .{}, |
| 15 | comdat_group_data: std.ArrayListUnmanaged(u32) = .{}, | |
| 16 | relocs: std.ArrayListUnmanaged(elf.Elf64_Rela) = .{}, | |
| 15 | 17 | |
| 16 | 18 | fdes: std.ArrayListUnmanaged(Fde) = .{}, |
| 17 | 19 | cies: std.ArrayListUnmanaged(Cie) = .{}, |
| 20 | eh_frame_data: std.ArrayListUnmanaged(u8) = .{}, | |
| 18 | 21 | |
| 19 | 22 | alive: bool = true, |
| 20 | 23 | num_dynrelocs: u32 = 0, |
| ... | ... | @@ -35,24 +38,30 @@ pub fn isObject(path: []const u8) !bool { |
| 35 | 38 | } |
| 36 | 39 | |
| 37 | 40 | pub fn deinit(self: *Object, allocator: Allocator) void { |
| 38 | if (self.archive) |path| allocator.free(path); | |
| 41 | if (self.archive) |*ar| allocator.free(ar.path); | |
| 39 | 42 | allocator.free(self.path); |
| 40 | allocator.free(self.data); | |
| 41 | 43 | self.shdrs.deinit(allocator); |
| 42 | 44 | self.symtab.deinit(allocator); |
| 43 | 45 | self.strtab.deinit(allocator); |
| 44 | 46 | self.symbols.deinit(allocator); |
| 45 | 47 | self.atoms.deinit(allocator); |
| 46 | 48 | self.comdat_groups.deinit(allocator); |
| 49 | self.comdat_group_data.deinit(allocator); | |
| 50 | self.relocs.deinit(allocator); | |
| 47 | 51 | self.fdes.deinit(allocator); |
| 48 | 52 | self.cies.deinit(allocator); |
| 53 | self.eh_frame_data.deinit(allocator); | |
| 49 | 54 | } |
| 50 | 55 | |
| 51 | 56 | pub 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; | |
| 54 | 61 | |
| 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)).*; | |
| 56 | 65 | |
| 57 | 66 | const target = elf_file.base.comp.root_mod.resolved_target.result; |
| 58 | 67 | if (target.cpu.arch != self.header.?.e_machine.toTargetCpuArch().?) { |
| ... | ... | @@ -66,12 +75,10 @@ pub fn parse(self: *Object, elf_file: *Elf) !void { |
| 66 | 75 | |
| 67 | 76 | if (self.header.?.e_shnum == 0) return; |
| 68 | 77 | |
| 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) { | |
| 75 | 82 | try elf_file.reportParseError2( |
| 76 | 83 | self.index, |
| 77 | 84 | "corrupt header: section header table extends past the end of file", |
| ... | ... | @@ -80,25 +87,23 @@ pub fn parse(self: *Object, elf_file: *Elf) !void { |
| 80 | 87 | return error.MalformedObject; |
| 81 | 88 | } |
| 82 | 89 | |
| 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); | |
| 89 | 94 | |
| 90 | for (shdrs) |shdr| { | |
| 95 | for (self.shdrs.items) |shdr| { | |
| 91 | 96 | 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) { | |
| 93 | 98 | try elf_file.reportParseError2(self.index, "corrupt section: extends past the end of file", .{}); |
| 94 | 99 | return error.MalformedObject; |
| 95 | 100 | } |
| 96 | 101 | } |
| 97 | self.shdrs.appendAssumeCapacity(try ElfShdr.fromElf64Shdr(shdr)); | |
| 98 | 102 | } |
| 99 | 103 | |
| 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| { | |
| 102 | 107 | if (shdr.sh_name >= shstrtab.len) { |
| 103 | 108 | try elf_file.reportParseError2(self.index, "corrupt section name offset", .{}); |
| 104 | 109 | return error.MalformedObject; |
| ... | ... | @@ -112,10 +117,11 @@ pub fn parse(self: *Object, elf_file: *Elf) !void { |
| 112 | 117 | } else null; |
| 113 | 118 | |
| 114 | 119 | if (symtab_index) |index| { |
| 115 | const shdr = shdrs[index]; | |
| 120 | const shdr = self.shdrs.items[index]; | |
| 116 | 121 | self.first_global = shdr.sh_info; |
| 117 | 122 | |
| 118 | const raw_symtab = self.shdrContents(index); | |
| 123 | const raw_symtab = try self.preadShdrContentsAlloc(gpa, handle, index); | |
| 124 | defer gpa.free(raw_symtab); | |
| 119 | 125 | const nsyms = math.divExact(usize, raw_symtab.len, @sizeOf(elf.Elf64_Sym)) catch { |
| 120 | 126 | try elf_file.reportParseError2(self.index, "symbol table not evenly divisible", .{}); |
| 121 | 127 | return error.MalformedObject; |
| ... | ... | @@ -123,7 +129,9 @@ pub fn parse(self: *Object, elf_file: *Elf) !void { |
| 123 | 129 | const symtab = @as([*]align(1) const elf.Elf64_Sym, @ptrCast(raw_symtab.ptr))[0..nsyms]; |
| 124 | 130 | |
| 125 | 131 | 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); | |
| 127 | 135 | |
| 128 | 136 | try self.symtab.ensureUnusedCapacity(gpa, symtab.len); |
| 129 | 137 | for (symtab) |sym| { |
| ... | ... | @@ -138,22 +146,23 @@ pub fn parse(self: *Object, elf_file: *Elf) !void { |
| 138 | 146 | } |
| 139 | 147 | |
| 140 | 148 | pub 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); | |
| 143 | 154 | |
| 144 | 155 | for (self.shdrs.items, 0..) |shdr, i| { |
| 145 | 156 | const atom = elf_file.atom(self.atoms.items[i]) orelse continue; |
| 146 | 157 | if (!atom.flags.alive) continue; |
| 147 | 158 | 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); | |
| 149 | 160 | } |
| 150 | 161 | } |
| 151 | 162 | |
| 152 | fn initAtoms(self: *Object, elf_file: *Elf) !void { | |
| 153 | const comp = elf_file.base.comp; | |
| 154 | const gpa = comp.gpa; | |
| 163 | fn initAtoms(self: *Object, allocator: Allocator, handle: std.fs.File, elf_file: *Elf) !void { | |
| 155 | 164 | const shdrs = self.shdrs.items; |
| 156 | try self.atoms.resize(gpa, shdrs.len); | |
| 165 | try self.atoms.resize(allocator, shdrs.len); | |
| 157 | 166 | @memset(self.atoms.items, 0); |
| 158 | 167 | |
| 159 | 168 | for (shdrs, 0..) |shdr, i| { |
| ... | ... | @@ -177,8 +186,9 @@ fn initAtoms(self: *Object, elf_file: *Elf) !void { |
| 177 | 186 | break :blk self.getString(group_info_sym.st_name); |
| 178 | 187 | }; |
| 179 | 188 | |
| 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); | |
| 182 | 192 | const group_nmembers = @divExact(group_raw_data.len, @sizeOf(u32)); |
| 183 | 193 | const group_members = @as([*]align(1) const u32, @ptrCast(group_raw_data.ptr))[0..group_nmembers]; |
| 184 | 194 | |
| ... | ... | @@ -188,14 +198,20 @@ fn initAtoms(self: *Object, elf_file: *Elf) !void { |
| 188 | 198 | continue; |
| 189 | 199 | } |
| 190 | 200 | |
| 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 | ||
| 191 | 204 | const gop = try elf_file.getOrCreateComdatGroupOwner(group_signature); |
| 192 | 205 | const comdat_group_index = try elf_file.addComdatGroup(); |
| 193 | 206 | const comdat_group = elf_file.comdatGroup(comdat_group_index); |
| 194 | 207 | comdat_group.* = .{ |
| 195 | 208 | .owner = gop.index, |
| 209 | .file = self.index, | |
| 196 | 210 | .shndx = shndx, |
| 211 | .members_start = group_start, | |
| 212 | .members_len = @intCast(group_nmembers - 1), | |
| 197 | 213 | }; |
| 198 | try self.comdat_groups.append(gpa, comdat_group_index); | |
| 214 | try self.comdat_groups.append(allocator, comdat_group_index); | |
| 199 | 215 | }, |
| 200 | 216 | |
| 201 | 217 | elf.SHT_SYMTAB_SHNDX => @panic("TODO SHT_SYMTAB_SHNDX"), |
| ... | ... | @@ -210,7 +226,7 @@ fn initAtoms(self: *Object, elf_file: *Elf) !void { |
| 210 | 226 | else => { |
| 211 | 227 | const shndx = @as(u16, @intCast(i)); |
| 212 | 228 | 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); | |
| 214 | 230 | }, |
| 215 | 231 | } |
| 216 | 232 | } |
| ... | ... | @@ -220,14 +236,19 @@ fn initAtoms(self: *Object, elf_file: *Elf) !void { |
| 220 | 236 | elf.SHT_REL, elf.SHT_RELA => { |
| 221 | 237 | const atom_index = self.atoms.items[shdr.sh_info]; |
| 222 | 238 | 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); | |
| 224 | 245 | } |
| 225 | 246 | }, |
| 226 | 247 | else => {}, |
| 227 | 248 | }; |
| 228 | 249 | } |
| 229 | 250 | |
| 230 | fn addAtom(self: *Object, shdr: ElfShdr, shndx: u16, elf_file: *Elf) error{OutOfMemory}!void { | |
| 251 | fn addAtom(self: *Object, allocator: Allocator, handle: std.fs.File, shdr: elf.Elf64_Shdr, shndx: u32, elf_file: *Elf) !void { | |
| 231 | 252 | const atom_index = try elf_file.addAtom(); |
| 232 | 253 | const atom = elf_file.atom(atom_index).?; |
| 233 | 254 | atom.atom_index = atom_index; |
| ... | ... | @@ -237,7 +258,8 @@ fn addAtom(self: *Object, shdr: ElfShdr, shndx: u16, elf_file: *Elf) error{OutOf |
| 237 | 258 | self.atoms.items[shndx] = atom_index; |
| 238 | 259 | |
| 239 | 260 | 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); | |
| 241 | 263 | const chdr = @as(*align(1) const elf.Elf64_Chdr, @ptrCast(data.ptr)).*; |
| 242 | 264 | atom.size = chdr.ch_size; |
| 243 | 265 | atom.alignment = Alignment.fromNonzeroByteUnits(chdr.ch_addralign); |
| ... | ... | @@ -247,7 +269,7 @@ fn addAtom(self: *Object, shdr: ElfShdr, shndx: u16, elf_file: *Elf) error{OutOf |
| 247 | 269 | } |
| 248 | 270 | } |
| 249 | 271 | |
| 250 | fn initOutputSection(self: Object, elf_file: *Elf, shdr: ElfShdr) error{OutOfMemory}!u16 { | |
| 272 | fn initOutputSection(self: Object, elf_file: *Elf, shdr: elf.Elf64_Shdr) error{OutOfMemory}!u16 { | |
| 251 | 273 | const name = blk: { |
| 252 | 274 | const name = self.getString(shdr.sh_name); |
| 253 | 275 | if (elf_file.base.isRelocatable()) break :blk name; |
| ... | ... | @@ -310,12 +332,10 @@ fn skipShdr(self: *Object, index: u16, elf_file: *Elf) bool { |
| 310 | 332 | return ignore; |
| 311 | 333 | } |
| 312 | 334 | |
| 313 | fn initSymtab(self: *Object, elf_file: *Elf) !void { | |
| 314 | const comp = elf_file.base.comp; | |
| 315 | const gpa = comp.gpa; | |
| 335 | fn initSymtab(self: *Object, allocator: Allocator, elf_file: *Elf) !void { | |
| 316 | 336 | const first_global = self.first_global orelse self.symtab.items.len; |
| 317 | 337 | |
| 318 | try self.symbols.ensureTotalCapacityPrecise(gpa, self.symtab.items.len); | |
| 338 | try self.symbols.ensureTotalCapacityPrecise(allocator, self.symtab.items.len); | |
| 319 | 339 | |
| 320 | 340 | for (self.symtab.items[0..first_global], 0..) |sym, i| { |
| 321 | 341 | const index = try elf_file.addSymbol(); |
| ... | ... | @@ -335,19 +355,24 @@ fn initSymtab(self: *Object, elf_file: *Elf) !void { |
| 335 | 355 | } |
| 336 | 356 | } |
| 337 | 357 | |
| 338 | fn parseEhFrame(self: *Object, shndx: u16, elf_file: *Elf) !void { | |
| 358 | fn parseEhFrame(self: *Object, allocator: Allocator, handle: std.fs.File, shndx: u32, elf_file: *Elf) !void { | |
| 339 | 359 | 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)), | |
| 341 | 361 | else => {}, |
| 342 | 362 | } else { |
| 363 | // TODO: convert into an error | |
| 343 | 364 | log.debug("{s}: missing reloc section for unwind info section", .{self.fmtPath()}); |
| 344 | 365 | return; |
| 345 | 366 | }; |
| 346 | 367 | |
| 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); | |
| 351 | 376 | const fdes_start = self.fdes.items.len; |
| 352 | 377 | const cies_start = self.cies.items.len; |
| 353 | 378 | |
| ... | ... | @@ -355,22 +380,20 @@ fn parseEhFrame(self: *Object, shndx: u16, elf_file: *Elf) !void { |
| 355 | 380 | while (try it.next()) |rec| { |
| 356 | 381 | const rel_range = filterRelocs(relocs, rec.offset, rec.size + 4); |
| 357 | 382 | 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, | |
| 360 | 385 | .size = rec.size, |
| 361 | .rel_index = @as(u32, @intCast(rel_range.start)), | |
| 386 | .rel_index = rel_start + @as(u32, @intCast(rel_range.start)), | |
| 362 | 387 | .rel_num = @as(u32, @intCast(rel_range.len)), |
| 363 | .rel_section_index = relocs_shndx, | |
| 364 | 388 | .input_section_index = shndx, |
| 365 | 389 | .file_index = self.index, |
| 366 | 390 | }), |
| 367 | .fde => try self.fdes.append(gpa, .{ | |
| 368 | .offset = rec.offset, | |
| 391 | .fde => try self.fdes.append(allocator, .{ | |
| 392 | .offset = data_start + rec.offset, | |
| 369 | 393 | .size = rec.size, |
| 370 | 394 | .cie_index = undefined, |
| 371 | .rel_index = @as(u32, @intCast(rel_range.start)), | |
| 395 | .rel_index = rel_start + @as(u32, @intCast(rel_range.start)), | |
| 372 | 396 | .rel_num = @as(u32, @intCast(rel_range.len)), |
| 373 | .rel_section_index = relocs_shndx, | |
| 374 | 397 | .input_section_index = shndx, |
| 375 | 398 | .file_index = self.index, |
| 376 | 399 | }), |
| ... | ... | @@ -773,21 +796,30 @@ pub fn updateArSymtab(self: Object, ar_symtab: *Archive.ArSymtab, elf_file: *Elf |
| 773 | 796 | } |
| 774 | 797 | } |
| 775 | 798 | |
| 776 | pub fn updateArSize(self: *Object) void { | |
| 777 | self.output_ar_state.size = self.data.len; | |
| 799 | pub 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; | |
| 778 | 803 | } |
| 779 | 804 | |
| 780 | pub fn writeAr(self: Object, writer: anytype) !void { | |
| 805 | pub 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; | |
| 781 | 807 | const name = self.path; |
| 782 | 808 | const hdr = Archive.setArHdr(.{ |
| 783 | 809 | .name = if (name.len <= Archive.max_member_name_len) |
| 784 | 810 | .{ .name = name } |
| 785 | 811 | else |
| 786 | 812 | .{ .name_off = self.output_ar_state.name_off }, |
| 787 | .size = @intCast(self.data.len), | |
| 813 | .size = size, | |
| 788 | 814 | }); |
| 789 | 815 | 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); | |
| 791 | 823 | } |
| 792 | 824 | |
| 793 | 825 | pub fn updateSymtabSize(self: *Object, elf_file: *Elf) !void { |
| ... | ... | @@ -859,12 +891,6 @@ pub fn globals(self: Object) []const Symbol.Index { |
| 859 | 891 | return self.symbols.items[start..]; |
| 860 | 892 | } |
| 861 | 893 | |
| 862 | pub 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 | ||
| 868 | 894 | /// Returns atom's code and optionally uncompresses data if required (for compressed sections). |
| 869 | 895 | /// Caller owns the memory. |
| 870 | 896 | 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) |
| 872 | 898 | const gpa = comp.gpa; |
| 873 | 899 | const atom_ptr = elf_file.atom(atom_index).?; |
| 874 | 900 | assert(atom_ptr.file_index == self.index); |
| 875 | const data = self.shdrContents(atom_ptr.input_section_index); | |
| 876 | 901 | 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 | ||
| 877 | 906 | if (shdr.sh_flags & elf.SHF_COMPRESSED != 0) { |
| 878 | 907 | const chdr = @as(*align(1) const elf.Elf64_Chdr, @ptrCast(data.ptr)).*; |
| 879 | 908 | switch (chdr.ch_type) { |
| ... | ... | @@ -892,31 +921,35 @@ pub fn codeDecompressAlloc(self: Object, elf_file: *Elf, atom_index: Atom.Index) |
| 892 | 921 | }, |
| 893 | 922 | else => @panic("TODO unhandled compression scheme"), |
| 894 | 923 | } |
| 895 | } else return gpa.dupe(u8, data); | |
| 896 | } | |
| 924 | } | |
| 897 | 925 | |
| 898 | pub 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; | |
| 903 | 927 | } |
| 904 | 928 | |
| 905 | 929 | pub fn asFile(self: *Object) File { |
| 906 | 930 | return .{ .object = self }; |
| 907 | 931 | } |
| 908 | 932 | |
| 909 | pub 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 | ||
| 915 | 933 | pub fn getString(self: Object, off: u32) [:0]const u8 { |
| 916 | 934 | assert(off < self.strtab.items.len); |
| 917 | 935 | return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.strtab.items.ptr + off)), 0); |
| 918 | 936 | } |
| 919 | 937 | |
| 938 | /// Caller owns the memory. | |
| 939 | fn 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. | |
| 947 | fn 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 | ||
| 920 | 953 | pub fn format( |
| 921 | 954 | self: *Object, |
| 922 | 955 | comptime unused_fmt_string: []const u8, |
| ... | ... | @@ -1053,7 +1086,7 @@ fn formatComdatGroups( |
| 1053 | 1086 | const cg_owner = elf_file.comdatGroupOwner(cg.owner); |
| 1054 | 1087 | if (cg_owner.file != object.index) continue; |
| 1055 | 1088 | try writer.print(" COMDAT({d})\n", .{cg_index}); |
| 1056 | const cg_members = object.comdatGroupMembers(cg.shndx); | |
| 1089 | const cg_members = cg.comdatGroupMembers(elf_file); | |
| 1057 | 1090 | for (cg_members) |shndx| { |
| 1058 | 1091 | const atom_index = object.atoms.items[shndx]; |
| 1059 | 1092 | const atom = elf_file.atom(atom_index) orelse continue; |
| ... | ... | @@ -1074,40 +1107,17 @@ fn formatPath( |
| 1074 | 1107 | ) !void { |
| 1075 | 1108 | _ = unused_fmt_string; |
| 1076 | 1109 | _ = options; |
| 1077 | if (object.archive) |path| { | |
| 1078 | try writer.writeAll(path); | |
| 1110 | if (object.archive) |ar| { | |
| 1111 | try writer.writeAll(ar.path); | |
| 1079 | 1112 | try writer.writeByte('('); |
| 1080 | 1113 | try writer.writeAll(object.path); |
| 1081 | 1114 | try writer.writeByte(')'); |
| 1082 | 1115 | } else try writer.writeAll(object.path); |
| 1083 | 1116 | } |
| 1084 | 1117 | |
| 1085 | pub 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 | } | |
| 1118 | const InArchive = struct { | |
| 1119 | path: []const u8, | |
| 1120 | offset: u64, | |
| 1111 | 1121 | }; |
| 1112 | 1122 | |
| 1113 | 1123 | const Object = @This(); |
src/link/Elf/SharedObject.zig+88-77| ... | ... | @@ -1,22 +1,18 @@ |
| 1 | 1 | path: []const u8, |
| 2 | data: []const u8, | |
| 3 | 2 | index: File.Index, |
| 4 | 3 | |
| 5 | 4 | header: ?elf.Elf64_Ehdr = null, |
| 6 | shdrs: std.ArrayListUnmanaged(ElfShdr) = .{}, | |
| 5 | shdrs: std.ArrayListUnmanaged(elf.Elf64_Shdr) = .{}, | |
| 7 | 6 | |
| 8 | 7 | symtab: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{}, |
| 9 | 8 | strtab: std.ArrayListUnmanaged(u8) = .{}, |
| 10 | 9 | /// Version symtab contains version strings of the symbols if present. |
| 11 | 10 | versyms: std.ArrayListUnmanaged(elf.Elf64_Versym) = .{}, |
| 12 | 11 | verstrings: std.ArrayListUnmanaged(u32) = .{}, |
| 12 | ||
| 13 | 13 | symbols: std.ArrayListUnmanaged(Symbol.Index) = .{}, |
| 14 | 14 | aliases: ?std.ArrayListUnmanaged(u32) = null, |
| 15 | ||
| 16 | dynsym_sect_index: ?u16 = null, | |
| 17 | dynamic_sect_index: ?u16 = null, | |
| 18 | versym_sect_index: ?u16 = null, | |
| 19 | verdef_sect_index: ?u16 = null, | |
| 15 | dynamic_table: std.ArrayListUnmanaged(elf.Elf64_Dyn) = .{}, | |
| 20 | 16 | |
| 21 | 17 | needed: bool, |
| 22 | 18 | alive: bool, |
| ... | ... | @@ -36,23 +32,24 @@ pub fn isSharedObject(path: []const u8) !bool { |
| 36 | 32 | |
| 37 | 33 | pub fn deinit(self: *SharedObject, allocator: Allocator) void { |
| 38 | 34 | allocator.free(self.path); |
| 39 | allocator.free(self.data); | |
| 35 | self.shdrs.deinit(allocator); | |
| 40 | 36 | self.symtab.deinit(allocator); |
| 41 | 37 | self.strtab.deinit(allocator); |
| 42 | 38 | self.versyms.deinit(allocator); |
| 43 | 39 | self.verstrings.deinit(allocator); |
| 44 | 40 | self.symbols.deinit(allocator); |
| 45 | 41 | if (self.aliases) |*aliases| aliases.deinit(allocator); |
| 46 | self.shdrs.deinit(allocator); | |
| 42 | self.dynamic_table.deinit(allocator); | |
| 47 | 43 | } |
| 48 | 44 | |
| 49 | pub fn parse(self: *SharedObject, elf_file: *Elf) !void { | |
| 45 | pub fn parse(self: *SharedObject, elf_file: *Elf, handle: std.fs.File) !void { | |
| 50 | 46 | const comp = elf_file.base.comp; |
| 51 | 47 | 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; | |
| 54 | 49 | |
| 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)).*; | |
| 56 | 53 | |
| 57 | 54 | const target = elf_file.base.comp.root_mod.resolved_target.result; |
| 58 | 55 | if (target.cpu.arch != self.header.?.e_machine.toTargetCpuArch().?) { |
| ... | ... | @@ -64,9 +61,10 @@ pub fn parse(self: *SharedObject, elf_file: *Elf) !void { |
| 64 | 61 | return error.InvalidCpuArch; |
| 65 | 62 | } |
| 66 | 63 | |
| 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) { | |
| 70 | 68 | try elf_file.reportParseError2( |
| 71 | 69 | self.index, |
| 72 | 70 | "corrupted header: section header table extends past the end of file", |
| ... | ... | @@ -75,45 +73,84 @@ pub fn parse(self: *SharedObject, elf_file: *Elf) !void { |
| 75 | 73 | return error.MalformedObject; |
| 76 | 74 | } |
| 77 | 75 | |
| 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); | |
| 85 | 80 | |
| 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| { | |
| 87 | 86 | 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) { | |
| 89 | 88 | try elf_file.reportParseError2(self.index, "corrupted section header", .{}); |
| 90 | 89 | return error.MalformedObject; |
| 91 | 90 | } |
| 92 | 91 | } |
| 93 | self.shdrs.appendAssumeCapacity(try ElfShdr.fromElf64Shdr(shdr)); | |
| 94 | 92 | 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), | |
| 99 | 97 | else => {}, |
| 100 | 98 | } |
| 101 | 99 | } |
| 102 | 100 | |
| 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 | }); | |
| 104 | 136 | } |
| 105 | 137 | |
| 106 | fn parseVersions(self: *SharedObject, elf_file: *Elf) !void { | |
| 138 | fn 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 { | |
| 107 | 143 | const comp = elf_file.base.comp; |
| 108 | 144 | const gpa = comp.gpa; |
| 109 | const symtab = self.getSymtabRaw(); | |
| 110 | 145 | |
| 111 | 146 | try self.verstrings.resize(gpa, 2); |
| 112 | 147 | self.verstrings.items[elf.VER_NDX_LOCAL] = 0; |
| 113 | 148 | self.verstrings.items[elf.VER_NDX_GLOBAL] = 0; |
| 114 | 149 | |
| 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); | |
| 117 | 154 | const nverdefs = self.verdefNum(); |
| 118 | 155 | try self.verstrings.resize(gpa, self.verstrings.items.len + nverdefs); |
| 119 | 156 | |
| ... | ... | @@ -131,10 +168,12 @@ fn parseVersions(self: *SharedObject, elf_file: *Elf) !void { |
| 131 | 168 | } |
| 132 | 169 | } |
| 133 | 170 | |
| 134 | try self.versyms.ensureTotalCapacityPrecise(gpa, symtab.len); | |
| 171 | try self.versyms.ensureTotalCapacityPrecise(gpa, opts.symtab.len); | |
| 135 | 172 | |
| 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); | |
| 138 | 177 | const nversyms = @divExact(versyms_raw.len, @sizeOf(elf.Elf64_Versym)); |
| 139 | 178 | const versyms = @as([*]align(1) const elf.Elf64_Versym, @ptrCast(versyms_raw.ptr))[0..nversyms]; |
| 140 | 179 | for (versyms) |ver| { |
| ... | ... | @@ -144,22 +183,23 @@ fn parseVersions(self: *SharedObject, elf_file: *Elf) !void { |
| 144 | 183 | ver; |
| 145 | 184 | self.versyms.appendAssumeCapacity(normalized_ver); |
| 146 | 185 | } |
| 147 | } else for (0..symtab.len) |_| { | |
| 186 | } else for (0..opts.symtab.len) |_| { | |
| 148 | 187 | self.versyms.appendAssumeCapacity(elf.VER_NDX_GLOBAL); |
| 149 | 188 | } |
| 150 | 189 | } |
| 151 | 190 | |
| 152 | pub fn init(self: *SharedObject, elf_file: *Elf) !void { | |
| 191 | fn initSymtab(self: *SharedObject, elf_file: *Elf, opts: struct { | |
| 192 | symtab: []align(1) const elf.Elf64_Sym, | |
| 193 | strtab: []const u8, | |
| 194 | }) !void { | |
| 153 | 195 | const comp = elf_file.base.comp; |
| 154 | 196 | const gpa = comp.gpa; |
| 155 | const symtab = self.getSymtabRaw(); | |
| 156 | const strtab = self.getStrtabRaw(); | |
| 157 | 197 | |
| 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); | |
| 161 | 201 | |
| 162 | for (symtab, 0..) |sym, i| { | |
| 202 | for (opts.symtab, 0..) |sym, i| { | |
| 163 | 203 | const hidden = self.versyms.items[i] & elf.VERSYM_HIDDEN != 0; |
| 164 | 204 | const name = self.getString(sym.st_name); |
| 165 | 205 | // 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 { |
| 250 | 290 | } |
| 251 | 291 | } |
| 252 | 292 | |
| 253 | pub 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 | ||
| 258 | 293 | pub fn versionString(self: SharedObject, index: elf.Elf64_Versym) [:0]const u8 { |
| 259 | 294 | const off = self.verstrings.items[index & elf.VERSYM_VERSION]; |
| 260 | 295 | return self.getString(off); |
| ... | ... | @@ -264,16 +299,8 @@ pub fn asFile(self: *SharedObject) File { |
| 264 | 299 | return .{ .shared_object = self }; |
| 265 | 300 | } |
| 266 | 301 | |
| 267 | fn 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 | ||
| 274 | 302 | fn 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) { | |
| 277 | 304 | elf.DT_VERDEFNUM => return @as(u32, @intCast(entry.d_val)), |
| 278 | 305 | else => {}, |
| 279 | 306 | }; |
| ... | ... | @@ -281,8 +308,7 @@ fn verdefNum(self: *SharedObject) u32 { |
| 281 | 308 | } |
| 282 | 309 | |
| 283 | 310 | pub 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) { | |
| 286 | 312 | elf.DT_SONAME => return self.getString(@as(u32, @intCast(entry.d_val))), |
| 287 | 313 | else => {}, |
| 288 | 314 | }; |
| ... | ... | @@ -342,20 +368,6 @@ pub fn getString(self: SharedObject, off: u32) [:0]const u8 { |
| 342 | 368 | return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.strtab.items.ptr + off)), 0); |
| 343 | 369 | } |
| 344 | 370 | |
| 345 | pub 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 | ||
| 353 | pub 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 | ||
| 359 | 371 | pub fn format( |
| 360 | 372 | self: SharedObject, |
| 361 | 373 | comptime unused_fmt_string: []const u8, |
| ... | ... | @@ -407,6 +419,5 @@ const mem = std.mem; |
| 407 | 419 | |
| 408 | 420 | const Allocator = mem.Allocator; |
| 409 | 421 | const Elf = @import("../Elf.zig"); |
| 410 | const ElfShdr = @import("Object.zig").ElfShdr; | |
| 411 | 422 | const File = @import("file.zig").File; |
| 412 | 423 | const 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 { |
| 305 | 305 | } |
| 306 | 306 | |
| 307 | 307 | /// TODO actually create fake input shdrs and return that instead. |
| 308 | pub fn inputShdr(self: ZigObject, atom_index: Atom.Index, elf_file: *Elf) Object.ElfShdr { | |
| 308 | pub fn inputShdr(self: ZigObject, atom_index: Atom.Index, elf_file: *Elf) elf.Elf64_Shdr { | |
| 309 | 309 | _ = 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; | |
| 321 | 318 | } |
| 322 | 319 | |
| 323 | 320 | pub fn resolveSymbols(self: *ZigObject, elf_file: *Elf) void { |
| ... | ... | @@ -525,7 +522,7 @@ pub fn writeAr(self: ZigObject, writer: anytype) !void { |
| 525 | 522 | .{ .name = name } |
| 526 | 523 | else |
| 527 | 524 | .{ .name_off = self.output_ar_state.name_off }, |
| 528 | .size = @intCast(self.data.items.len), | |
| 525 | .size = self.data.items.len, | |
| 529 | 526 | }); |
| 530 | 527 | try writer.writeAll(mem.asBytes(&hdr)); |
| 531 | 528 | try writer.writeAll(self.data.items); |
src/link/Elf/eh_frame.zig+9-22| ... | ... | @@ -5,7 +5,6 @@ pub const Fde = struct { |
| 5 | 5 | cie_index: u32, |
| 6 | 6 | rel_index: u32 = 0, |
| 7 | 7 | rel_num: u32 = 0, |
| 8 | rel_section_index: u32 = 0, | |
| 9 | 8 | input_section_index: u32 = 0, |
| 10 | 9 | file_index: u32 = 0, |
| 11 | 10 | alive: bool = true, |
| ... | ... | @@ -20,10 +19,9 @@ pub const Fde = struct { |
| 20 | 19 | return base + fde.out_offset; |
| 21 | 20 | } |
| 22 | 21 | |
| 23 | pub fn data(fde: Fde, elf_file: *Elf) []const u8 { | |
| 22 | pub fn data(fde: Fde, elf_file: *Elf) []u8 { | |
| 24 | 23 | 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()]; | |
| 27 | 25 | } |
| 28 | 26 | |
| 29 | 27 | pub fn cie(fde: Fde, elf_file: *Elf) Cie { |
| ... | ... | @@ -50,7 +48,7 @@ pub const Fde = struct { |
| 50 | 48 | |
| 51 | 49 | pub fn relocs(fde: Fde, elf_file: *Elf) []align(1) const elf.Elf64_Rela { |
| 52 | 50 | 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]; | |
| 54 | 52 | } |
| 55 | 53 | |
| 56 | 54 | pub fn format( |
| ... | ... | @@ -106,7 +104,6 @@ pub const Cie = struct { |
| 106 | 104 | size: usize, |
| 107 | 105 | rel_index: u32 = 0, |
| 108 | 106 | rel_num: u32 = 0, |
| 109 | rel_section_index: u32 = 0, | |
| 110 | 107 | input_section_index: u32 = 0, |
| 111 | 108 | file_index: u32 = 0, |
| 112 | 109 | /// Includes 4byte size cell. |
| ... | ... | @@ -121,10 +118,9 @@ pub const Cie = struct { |
| 121 | 118 | return base + cie.out_offset; |
| 122 | 119 | } |
| 123 | 120 | |
| 124 | pub fn data(cie: Cie, elf_file: *Elf) []const u8 { | |
| 121 | pub fn data(cie: Cie, elf_file: *Elf) []u8 { | |
| 125 | 122 | 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()]; | |
| 128 | 124 | } |
| 129 | 125 | |
| 130 | 126 | pub fn calcSize(cie: Cie) usize { |
| ... | ... | @@ -133,7 +129,7 @@ pub const Cie = struct { |
| 133 | 129 | |
| 134 | 130 | pub fn relocs(cie: Cie, elf_file: *Elf) []align(1) const elf.Elf64_Rela { |
| 135 | 131 | 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]; | |
| 137 | 133 | } |
| 138 | 134 | |
| 139 | 135 | 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: |
| 330 | 326 | } |
| 331 | 327 | |
| 332 | 328 | pub fn writeEhFrame(elf_file: *Elf, writer: anytype) !void { |
| 333 | const comp = elf_file.base.comp; | |
| 334 | const gpa = comp.gpa; | |
| 335 | ||
| 336 | 329 | relocs_log.debug("{x}: .eh_frame", .{elf_file.shdrs.items[elf_file.eh_frame_section_index.?].sh_addr}); |
| 337 | 330 | |
| 338 | 331 | for (elf_file.objects.items) |index| { |
| ... | ... | @@ -341,8 +334,7 @@ pub fn writeEhFrame(elf_file: *Elf, writer: anytype) !void { |
| 341 | 334 | for (object.cies.items) |cie| { |
| 342 | 335 | if (!cie.alive) continue; |
| 343 | 336 | |
| 344 | const contents = try gpa.dupe(u8, cie.data(elf_file)); | |
| 345 | defer gpa.free(contents); | |
| 337 | const contents = cie.data(elf_file); | |
| 346 | 338 | |
| 347 | 339 | for (cie.relocs(elf_file)) |rel| { |
| 348 | 340 | const sym = elf_file.symbol(object.symbols.items[rel.r_sym()]); |
| ... | ... | @@ -359,8 +351,7 @@ pub fn writeEhFrame(elf_file: *Elf, writer: anytype) !void { |
| 359 | 351 | for (object.fdes.items) |fde| { |
| 360 | 352 | if (!fde.alive) continue; |
| 361 | 353 | |
| 362 | const contents = try gpa.dupe(u8, fde.data(elf_file)); | |
| 363 | defer gpa.free(contents); | |
| 354 | const contents = fde.data(elf_file); | |
| 364 | 355 | |
| 365 | 356 | std.mem.writeInt( |
| 366 | 357 | i32, |
| ... | ... | @@ -382,9 +373,6 @@ pub fn writeEhFrame(elf_file: *Elf, writer: anytype) !void { |
| 382 | 373 | } |
| 383 | 374 | |
| 384 | 375 | pub fn writeEhFrameObject(elf_file: *Elf, writer: anytype) !void { |
| 385 | const comp = elf_file.base.comp; | |
| 386 | const gpa = comp.gpa; | |
| 387 | ||
| 388 | 376 | for (elf_file.objects.items) |index| { |
| 389 | 377 | const object = elf_file.file(index).?.object; |
| 390 | 378 | |
| ... | ... | @@ -400,8 +388,7 @@ pub fn writeEhFrameObject(elf_file: *Elf, writer: anytype) !void { |
| 400 | 388 | for (object.fdes.items) |fde| { |
| 401 | 389 | if (!fde.alive) continue; |
| 402 | 390 | |
| 403 | const contents = try gpa.dupe(u8, fde.data(elf_file)); | |
| 404 | defer gpa.free(contents); | |
| 391 | const contents = fde.data(elf_file); | |
| 405 | 392 | |
| 406 | 393 | std.mem.writeInt( |
| 407 | 394 | i32, |
src/link/Elf/file.zig+7-4| ... | ... | @@ -162,18 +162,18 @@ pub const File = union(enum) { |
| 162 | 162 | state.name_off = try ar_strtab.insert(allocator, path); |
| 163 | 163 | } |
| 164 | 164 | |
| 165 | pub fn updateArSize(file: File) void { | |
| 165 | pub fn updateArSize(file: File, elf_file: *Elf) !void { | |
| 166 | 166 | return switch (file) { |
| 167 | 167 | .zig_object => |x| x.updateArSize(), |
| 168 | .object => |x| x.updateArSize(), | |
| 168 | .object => |x| x.updateArSize(elf_file), | |
| 169 | 169 | inline else => unreachable, |
| 170 | 170 | }; |
| 171 | 171 | } |
| 172 | 172 | |
| 173 | pub fn writeAr(file: File, writer: anytype) !void { | |
| 173 | pub fn writeAr(file: File, elf_file: *Elf, writer: anytype) !void { | |
| 174 | 174 | return switch (file) { |
| 175 | 175 | .zig_object => |x| x.writeAr(writer), |
| 176 | .object => |x| x.writeAr(writer), | |
| 176 | .object => |x| x.writeAr(elf_file, writer), | |
| 177 | 177 | inline else => unreachable, |
| 178 | 178 | }; |
| 179 | 179 | } |
| ... | ... | @@ -187,6 +187,9 @@ pub const File = union(enum) { |
| 187 | 187 | object: Object, |
| 188 | 188 | shared_object: SharedObject, |
| 189 | 189 | }; |
| 190 | ||
| 191 | pub const Handle = std.fs.File; | |
| 192 | pub const HandleIndex = Index; | |
| 190 | 193 | }; |
| 191 | 194 | |
| 192 | 195 | const std = @import("std"); |
src/link/Elf/synthetic_sections.zig+2-3| ... | ... | @@ -1582,15 +1582,14 @@ pub const ComdatGroupSection = struct { |
| 1582 | 1582 | |
| 1583 | 1583 | pub fn size(cgs: ComdatGroupSection, elf_file: *Elf) usize { |
| 1584 | 1584 | 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); | |
| 1587 | 1586 | return (members.len + 1) * @sizeOf(u32); |
| 1588 | 1587 | } |
| 1589 | 1588 | |
| 1590 | 1589 | pub fn write(cgs: ComdatGroupSection, elf_file: *Elf, writer: anytype) !void { |
| 1591 | 1590 | const cg = elf_file.comdatGroup(cgs.cg_index); |
| 1592 | 1591 | const object = cgs.file(elf_file).?.object; |
| 1593 | const members = object.comdatGroupMembers(cg.shndx); | |
| 1592 | const members = cg.comdatGroupMembers(elf_file); | |
| 1594 | 1593 | try writer.writeInt(u32, elf.GRP_COMDAT, .little); |
| 1595 | 1594 | for (members) |shndx| { |
| 1596 | 1595 | const shdr = object.shdrs.items[shndx]; |