| author | |
| committer | |
| log | 8bd01eb7a914416a772b365dc75d83890067e26c |
| tree | 712c0c17006e6fc20ee158542df0d585a245530b |
| parent | 616a8f9853e461400f6f5c49dede3bf3a0ca25b6 |
3 files changed, 97 insertions(+), 53 deletions(-)
src/link/Elf.zig+6-12| ... | ... | @@ -1075,6 +1075,10 @@ pub fn flushModule(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node) |
| 1075 | 1075 | // --verbose-link |
| 1076 | 1076 | if (comp.verbose_link) try self.dumpArgv(comp); |
| 1077 | 1077 | |
| 1078 | if (self.zigObjectPtr()) |zig_object| try zig_object.flushModule(self); | |
| 1079 | if (self.base.isStaticLib()) return relocatable.flushStaticLib(self, comp, module_obj_path); | |
| 1080 | if (self.base.isObject()) return relocatable.flushObject(self, comp, module_obj_path); | |
| 1081 | ||
| 1078 | 1082 | const csu = try CsuObjects.init(arena, comp); |
| 1079 | 1083 | const compiler_rt_path: ?[]const u8 = blk: { |
| 1080 | 1084 | if (comp.compiler_rt_lib) |x| break :blk x.full_object_path; |
| ... | ... | @@ -1082,10 +1086,6 @@ pub fn flushModule(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node) |
| 1082 | 1086 | break :blk null; |
| 1083 | 1087 | }; |
| 1084 | 1088 | |
| 1085 | if (self.zigObjectPtr()) |zig_object| try zig_object.flushModule(self); | |
| 1086 | if (self.base.isStaticLib()) return relocatable.flushStaticLib(self, comp, module_obj_path); | |
| 1087 | if (self.base.isObject()) return relocatable.flushObject(self, comp, module_obj_path); | |
| 1088 | ||
| 1089 | 1089 | // Here we will parse input positional and library files (if referenced). |
| 1090 | 1090 | // This will roughly match in any linker backend we support. |
| 1091 | 1091 | var positionals = std.ArrayList(Compilation.LinkObject).init(arena); |
| ... | ... | @@ -1249,13 +1249,6 @@ pub fn flushModule(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node) |
| 1249 | 1249 | |
| 1250 | 1250 | if (comp.link_errors.items.len > 0) return error.FlushFailure; |
| 1251 | 1251 | |
| 1252 | // Init all objects | |
| 1253 | for (self.objects.items) |index| { | |
| 1254 | try self.file(index).?.object.init(self); | |
| 1255 | } | |
| 1256 | ||
| 1257 | if (comp.link_errors.items.len > 0) return error.FlushFailure; | |
| 1258 | ||
| 1259 | 1252 | // Dedup shared objects |
| 1260 | 1253 | { |
| 1261 | 1254 | var seen_dsos = std.StringHashMap(void).init(gpa); |
| ... | ... | @@ -1651,7 +1644,7 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void { |
| 1651 | 1644 | Compilation.dump_argv(argv.items); |
| 1652 | 1645 | } |
| 1653 | 1646 | |
| 1654 | const ParseError = error{ | |
| 1647 | pub const ParseError = error{ | |
| 1655 | 1648 | MalformedObject, |
| 1656 | 1649 | MalformedArchive, |
| 1657 | 1650 | InvalidCpuArch, |
| ... | ... | @@ -1662,6 +1655,7 @@ const ParseError = error{ |
| 1662 | 1655 | FileSystem, |
| 1663 | 1656 | NotSupported, |
| 1664 | 1657 | InvalidCharacter, |
| 1658 | UnknownFileType, | |
| 1665 | 1659 | } || LdScript.Error || std.os.AccessError || std.os.SeekError || std.fs.File.OpenError || std.fs.File.ReadError; |
| 1666 | 1660 | |
| 1667 | 1661 | pub fn parsePositional(self: *Elf, path: []const u8, must_link: bool) ParseError!void { |
src/link/Elf/Object.zig+35-30| ... | ... | @@ -55,12 +55,26 @@ pub fn deinit(self: *Object, allocator: Allocator) void { |
| 55 | 55 | |
| 56 | 56 | pub fn parse(self: *Object, elf_file: *Elf) !void { |
| 57 | 57 | const gpa = elf_file.base.comp.gpa; |
| 58 | const offset = if (self.archive) |ar| ar.offset else 0; | |
| 59 | 58 | const handle = elf_file.fileHandle(self.file_handle); |
| 59 | ||
| 60 | try self.parseCommon(gpa, handle, elf_file); | |
| 61 | try self.initAtoms(gpa, handle, elf_file); | |
| 62 | try self.initSymtab(gpa, elf_file); | |
| 63 | ||
| 64 | for (self.shdrs.items, 0..) |shdr, i| { | |
| 65 | const atom = elf_file.atom(self.atoms.items[i]) orelse continue; | |
| 66 | if (!atom.flags.alive) continue; | |
| 67 | if (shdr.sh_type == elf.SHT_X86_64_UNWIND or mem.eql(u8, atom.name(elf_file), ".eh_frame")) | |
| 68 | try self.parseEhFrame(gpa, handle, @as(u32, @intCast(i)), elf_file); | |
| 69 | } | |
| 70 | } | |
| 71 | ||
| 72 | fn parseCommon(self: *Object, allocator: Allocator, handle: std.fs.File, elf_file: *Elf) !void { | |
| 73 | const offset = if (self.archive) |ar| ar.offset else 0; | |
| 60 | 74 | const file_size = (try handle.stat()).size; |
| 61 | 75 | |
| 62 | const header_buffer = try Elf.preadAllAlloc(gpa, handle, offset, @sizeOf(elf.Elf64_Ehdr)); | |
| 63 | defer gpa.free(header_buffer); | |
| 76 | const header_buffer = try Elf.preadAllAlloc(allocator, handle, offset, @sizeOf(elf.Elf64_Ehdr)); | |
| 77 | defer allocator.free(header_buffer); | |
| 64 | 78 | self.header = @as(*align(1) const elf.Elf64_Ehdr, @ptrCast(header_buffer)).*; |
| 65 | 79 | |
| 66 | 80 | const target = elf_file.base.comp.root_mod.resolved_target.result; |
| ... | ... | @@ -87,10 +101,10 @@ pub fn parse(self: *Object, elf_file: *Elf) !void { |
| 87 | 101 | return error.MalformedObject; |
| 88 | 102 | } |
| 89 | 103 | |
| 90 | const shdrs_buffer = try Elf.preadAllAlloc(gpa, handle, offset + shoff, shsize); | |
| 91 | defer gpa.free(shdrs_buffer); | |
| 104 | const shdrs_buffer = try Elf.preadAllAlloc(allocator, handle, offset + shoff, shsize); | |
| 105 | defer allocator.free(shdrs_buffer); | |
| 92 | 106 | const shdrs = @as([*]align(1) const elf.Elf64_Shdr, @ptrCast(shdrs_buffer.ptr))[0..shnum]; |
| 93 | try self.shdrs.appendUnalignedSlice(gpa, shdrs); | |
| 107 | try self.shdrs.appendUnalignedSlice(allocator, shdrs); | |
| 94 | 108 | |
| 95 | 109 | for (self.shdrs.items) |shdr| { |
| 96 | 110 | if (shdr.sh_type != elf.SHT_NOBITS) { |
| ... | ... | @@ -101,15 +115,15 @@ pub fn parse(self: *Object, elf_file: *Elf) !void { |
| 101 | 115 | } |
| 102 | 116 | } |
| 103 | 117 | |
| 104 | const shstrtab = try self.preadShdrContentsAlloc(gpa, handle, self.header.?.e_shstrndx); | |
| 105 | defer gpa.free(shstrtab); | |
| 118 | const shstrtab = try self.preadShdrContentsAlloc(allocator, handle, self.header.?.e_shstrndx); | |
| 119 | defer allocator.free(shstrtab); | |
| 106 | 120 | for (self.shdrs.items) |shdr| { |
| 107 | 121 | if (shdr.sh_name >= shstrtab.len) { |
| 108 | 122 | try elf_file.reportParseError2(self.index, "corrupt section name offset", .{}); |
| 109 | 123 | return error.MalformedObject; |
| 110 | 124 | } |
| 111 | 125 | } |
| 112 | try self.strtab.appendSlice(gpa, shstrtab); | |
| 126 | try self.strtab.appendSlice(allocator, shstrtab); | |
| 113 | 127 | |
| 114 | 128 | const symtab_index = for (self.shdrs.items, 0..) |shdr, i| switch (shdr.sh_type) { |
| 115 | 129 | elf.SHT_SYMTAB => break @as(u16, @intCast(i)), |
| ... | ... | @@ -120,8 +134,8 @@ pub fn parse(self: *Object, elf_file: *Elf) !void { |
| 120 | 134 | const shdr = self.shdrs.items[index]; |
| 121 | 135 | self.first_global = shdr.sh_info; |
| 122 | 136 | |
| 123 | const raw_symtab = try self.preadShdrContentsAlloc(gpa, handle, index); | |
| 124 | defer gpa.free(raw_symtab); | |
| 137 | const raw_symtab = try self.preadShdrContentsAlloc(allocator, handle, index); | |
| 138 | defer allocator.free(raw_symtab); | |
| 125 | 139 | const nsyms = math.divExact(usize, raw_symtab.len, @sizeOf(elf.Elf64_Sym)) catch { |
| 126 | 140 | try elf_file.reportParseError2(self.index, "symbol table not evenly divisible", .{}); |
| 127 | 141 | return error.MalformedObject; |
| ... | ... | @@ -129,11 +143,11 @@ pub fn parse(self: *Object, elf_file: *Elf) !void { |
| 129 | 143 | const symtab = @as([*]align(1) const elf.Elf64_Sym, @ptrCast(raw_symtab.ptr))[0..nsyms]; |
| 130 | 144 | |
| 131 | 145 | const strtab_bias = @as(u32, @intCast(self.strtab.items.len)); |
| 132 | const strtab = try self.preadShdrContentsAlloc(gpa, handle, shdr.sh_link); | |
| 133 | defer gpa.free(strtab); | |
| 134 | try self.strtab.appendSlice(gpa, strtab); | |
| 146 | const strtab = try self.preadShdrContentsAlloc(allocator, handle, shdr.sh_link); | |
| 147 | defer allocator.free(strtab); | |
| 148 | try self.strtab.appendSlice(allocator, strtab); | |
| 135 | 149 | |
| 136 | try self.symtab.ensureUnusedCapacity(gpa, symtab.len); | |
| 150 | try self.symtab.ensureUnusedCapacity(allocator, symtab.len); | |
| 137 | 151 | for (symtab) |sym| { |
| 138 | 152 | const out_sym = self.symtab.addOneAssumeCapacity(); |
| 139 | 153 | out_sym.* = sym; |
| ... | ... | @@ -145,21 +159,6 @@ pub fn parse(self: *Object, elf_file: *Elf) !void { |
| 145 | 159 | } |
| 146 | 160 | } |
| 147 | 161 | |
| 148 | pub fn init(self: *Object, elf_file: *Elf) !void { | |
| 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); | |
| 154 | ||
| 155 | for (self.shdrs.items, 0..) |shdr, i| { | |
| 156 | const atom = elf_file.atom(self.atoms.items[i]) orelse continue; | |
| 157 | if (!atom.flags.alive) continue; | |
| 158 | if (shdr.sh_type == elf.SHT_X86_64_UNWIND or mem.eql(u8, atom.name(elf_file), ".eh_frame")) | |
| 159 | try self.parseEhFrame(gpa, handle, @as(u32, @intCast(i)), elf_file); | |
| 160 | } | |
| 161 | } | |
| 162 | ||
| 163 | 162 | fn initAtoms(self: *Object, allocator: Allocator, handle: std.fs.File, elf_file: *Elf) !void { |
| 164 | 163 | const shdrs = self.shdrs.items; |
| 165 | 164 | try self.atoms.resize(allocator, shdrs.len); |
| ... | ... | @@ -782,6 +781,12 @@ pub fn addAtomsToRelaSections(self: Object, elf_file: *Elf) !void { |
| 782 | 781 | } |
| 783 | 782 | } |
| 784 | 783 | |
| 784 | pub fn parseAr(self: *Object, elf_file: *Elf) !void { | |
| 785 | const gpa = elf_file.base.comp.gpa; | |
| 786 | const handle = elf_file.fileHandle(self.file_handle); | |
| 787 | try self.parseCommon(gpa, handle, elf_file); | |
| 788 | } | |
| 789 | ||
| 785 | 790 | pub fn updateArSymtab(self: Object, ar_symtab: *Archive.ArSymtab, elf_file: *Elf) !void { |
| 786 | 791 | const comp = elf_file.base.comp; |
| 787 | 792 | const gpa = comp.gpa; |
src/link/Elf/relocatable.zig+56-11| ... | ... | @@ -7,18 +7,20 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]co |
| 7 | 7 | try positionals.ensureUnusedCapacity(comp.objects.len); |
| 8 | 8 | positionals.appendSliceAssumeCapacity(comp.objects); |
| 9 | 9 | |
| 10 | // This is a set of object files emitted by clang in a single `build-exe` invocation. | |
| 11 | // For instance, the implicit `a.o` as compiled by `zig build-exe a.c` will end up | |
| 12 | // in this set. | |
| 13 | 10 | for (comp.c_object_table.keys()) |key| { |
| 14 | 11 | try positionals.append(.{ .path = key.status.success.object_path }); |
| 15 | 12 | } |
| 16 | 13 | |
| 17 | 14 | if (module_obj_path) |path| try positionals.append(.{ .path = path }); |
| 18 | 15 | |
| 16 | if (comp.include_compiler_rt) { | |
| 17 | try positionals.append(.{ .path = comp.compiler_rt_obj.?.full_object_path }); | |
| 18 | } | |
| 19 | ||
| 19 | 20 | for (positionals.items) |obj| { |
| 20 | elf_file.parsePositional(obj.path, obj.must_link) catch |err| switch (err) { | |
| 21 | parsePositional(elf_file, obj.path) catch |err| switch (err) { | |
| 21 | 22 | error.MalformedObject, error.MalformedArchive, error.InvalidCpuArch => continue, // already reported |
| 23 | error.UnknownFileType => try elf_file.reportParseError(obj.path, "unknown file type for an object file", .{}), | |
| 22 | 24 | else => |e| try elf_file.reportParseError( |
| 23 | 25 | obj.path, |
| 24 | 26 | "unexpected error: parsing input file failed with error {s}", |
| ... | ... | @@ -172,13 +174,6 @@ pub fn flushObject(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]const |
| 172 | 174 | |
| 173 | 175 | if (comp.link_errors.items.len > 0) return error.FlushFailure; |
| 174 | 176 | |
| 175 | // Init all objects | |
| 176 | for (elf_file.objects.items) |index| { | |
| 177 | try elf_file.file(index).?.object.init(elf_file); | |
| 178 | } | |
| 179 | ||
| 180 | if (comp.link_errors.items.len > 0) return error.FlushFailure; | |
| 181 | ||
| 182 | 177 | // Now, we are ready to resolve the symbols across all input files. |
| 183 | 178 | // We will first resolve the files in the ZigObject, next in the parsed |
| 184 | 179 | // input Object files. |
| ... | ... | @@ -214,6 +209,55 @@ pub fn flushObject(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]const |
| 214 | 209 | if (comp.link_errors.items.len > 0) return error.FlushFailure; |
| 215 | 210 | } |
| 216 | 211 | |
| 212 | fn parsePositional(elf_file: *Elf, path: []const u8) Elf.ParseError!void { | |
| 213 | if (try Object.isObject(path)) { | |
| 214 | try parseObject(elf_file, path); | |
| 215 | } else if (try Archive.isArchive(path)) { | |
| 216 | try parseArchive(elf_file, path); | |
| 217 | } else return error.UnknownFileType; | |
| 218 | // TODO: should we check for LD script? | |
| 219 | // Actually, should we even unpack an archive? | |
| 220 | } | |
| 221 | ||
| 222 | fn parseObject(elf_file: *Elf, path: []const u8) Elf.ParseError!void { | |
| 223 | const gpa = elf_file.base.comp.gpa; | |
| 224 | const handle = try std.fs.cwd().openFile(path, .{}); | |
| 225 | const fh = try elf_file.addFileHandle(handle); | |
| 226 | ||
| 227 | const index = @as(File.Index, @intCast(try elf_file.files.addOne(gpa))); | |
| 228 | elf_file.files.set(index, .{ .object = .{ | |
| 229 | .path = try gpa.dupe(u8, path), | |
| 230 | .file_handle = fh, | |
| 231 | .index = index, | |
| 232 | } }); | |
| 233 | try elf_file.objects.append(gpa, index); | |
| 234 | ||
| 235 | const object = elf_file.file(index).?.object; | |
| 236 | try object.parseAr(elf_file); | |
| 237 | } | |
| 238 | ||
| 239 | fn parseArchive(elf_file: *Elf, path: []const u8) Elf.ParseError!void { | |
| 240 | const gpa = elf_file.base.comp.gpa; | |
| 241 | const handle = try std.fs.cwd().openFile(path, .{}); | |
| 242 | const fh = try elf_file.addFileHandle(handle); | |
| 243 | ||
| 244 | var archive = Archive{}; | |
| 245 | defer archive.deinit(gpa); | |
| 246 | try archive.parse(elf_file, path, fh); | |
| 247 | ||
| 248 | const objects = try archive.objects.toOwnedSlice(gpa); | |
| 249 | defer gpa.free(objects); | |
| 250 | ||
| 251 | for (objects) |extracted| { | |
| 252 | const index = @as(File.Index, @intCast(try elf_file.files.addOne(gpa))); | |
| 253 | elf_file.files.set(index, .{ .object = extracted }); | |
| 254 | const object = &elf_file.files.items(.data)[index].object; | |
| 255 | object.index = index; | |
| 256 | try object.parseAr(elf_file); | |
| 257 | try elf_file.objects.append(gpa, index); | |
| 258 | } | |
| 259 | } | |
| 260 | ||
| 217 | 261 | fn claimUnresolved(elf_file: *Elf) void { |
| 218 | 262 | if (elf_file.zigObjectPtr()) |zig_object| { |
| 219 | 263 | zig_object.claimUnresolvedObject(elf_file); |
| ... | ... | @@ -518,3 +562,4 @@ const Archive = @import("Archive.zig"); |
| 518 | 562 | const Compilation = @import("../../Compilation.zig"); |
| 519 | 563 | const Elf = @import("../Elf.zig"); |
| 520 | 564 | const File = @import("file.zig").File; |
| 565 | const Object = @import("Object.zig"); |