| ... | @@ -9,7 +9,9 @@ shdrs: std.ArrayListUnmanaged(elf.Elf64_Shdr) = .{}, | ... | @@ -9,7 +9,9 @@ shdrs: std.ArrayListUnmanaged(elf.Elf64_Shdr) = .{}, |
| 9 | symtab: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{}, | 9 | symtab: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{}, |
| 10 | strtab: std.ArrayListUnmanaged(u8) = .{}, | 10 | strtab: std.ArrayListUnmanaged(u8) = .{}, |
| 11 | first_global: ?Symbol.Index = null, | 11 | first_global: ?Symbol.Index = null, |
| 12 | symbols: std.ArrayListUnmanaged(Symbol.Index) = .{}, | 12 | symbols: std.ArrayListUnmanaged(Symbol) = .{}, |
| | 13 | symbols_extra: std.ArrayListUnmanaged(u32) = .{}, |
| | 14 | symbols_resolver: std.ArrayListUnmanaged(Elf.SymbolResolver.Index) = .{}, |
| 13 | relocs: std.ArrayListUnmanaged(elf.Elf64_Rela) = .{}, | 15 | relocs: std.ArrayListUnmanaged(elf.Elf64_Rela) = .{}, |
| 14 | | 16 | |
| 15 | atoms: std.ArrayListUnmanaged(Atom) = .{}, | 17 | atoms: std.ArrayListUnmanaged(Atom) = .{}, |
| ... | @@ -51,6 +53,8 @@ pub fn deinit(self: *Object, allocator: Allocator) void { | ... | @@ -51,6 +53,8 @@ pub fn deinit(self: *Object, allocator: Allocator) void { |
| 51 | self.symtab.deinit(allocator); | 53 | self.symtab.deinit(allocator); |
| 52 | self.strtab.deinit(allocator); | 54 | self.strtab.deinit(allocator); |
| 53 | self.symbols.deinit(allocator); | 55 | self.symbols.deinit(allocator); |
| | 56 | self.symbols_extra.deinit(allocator); |
| | 57 | self.symbols_resolver.deinit(allocator); |
| 54 | self.atoms.deinit(allocator); | 58 | self.atoms.deinit(allocator); |
| 55 | self.atoms_indexes.deinit(allocator); | 59 | self.atoms_indexes.deinit(allocator); |
| 56 | self.atoms_extra.deinit(allocator); | 60 | self.atoms_extra.deinit(allocator); |
| ... | @@ -80,7 +84,7 @@ pub fn parse(self: *Object, elf_file: *Elf) !void { | ... | @@ -80,7 +84,7 @@ pub fn parse(self: *Object, elf_file: *Elf) !void { |
| 80 | try self.atoms.append(gpa, .{ .extra_index = try self.addAtomExtra(gpa, .{}) }); | 84 | try self.atoms.append(gpa, .{ .extra_index = try self.addAtomExtra(gpa, .{}) }); |
| 81 | | 85 | |
| 82 | try self.initAtoms(gpa, handle, elf_file); | 86 | try self.initAtoms(gpa, handle, elf_file); |
| 83 | try self.initSymtab(gpa, elf_file); | 87 | try self.initSymbols(gpa, elf_file); |
| 84 | | 88 | |
| 85 | for (self.shdrs.items, 0..) |shdr, i| { | 89 | for (self.shdrs.items, 0..) |shdr, i| { |
| 86 | const atom_ptr = self.atom(self.atoms_indexes.items[i]) orelse continue; | 90 | const atom_ptr = self.atom(self.atoms_indexes.items[i]) orelse continue; |
| ... | @@ -374,30 +378,30 @@ fn skipShdr(self: *Object, index: u32, elf_file: *Elf) bool { | ... | @@ -374,30 +378,30 @@ fn skipShdr(self: *Object, index: u32, elf_file: *Elf) bool { |
| 374 | return ignore; | 378 | return ignore; |
| 375 | } | 379 | } |
| 376 | | 380 | |
| 377 | fn initSymtab(self: *Object, allocator: Allocator, elf_file: *Elf) !void { | 381 | fn initSymbols(self: *Object, allocator: Allocator, elf_file: *Elf) !void { |
| 378 | const first_global = self.first_global orelse self.symtab.items.len; | 382 | const first_global = self.first_global orelse self.symtab.items.len; |
| | 383 | const nglobals = self.symtab.items.len - first_global; |
| 379 | | 384 | |
| 380 | try self.symbols.ensureTotalCapacityPrecise(allocator, self.symtab.items.len); | 385 | try self.symbols.ensureTotalCapacityPrecise(allocator, self.symtab.items.len); |
| 381 | | 386 | try self.symbols_extra.ensureTotalCapacityPrecise(allocator, self.symtab.items.len * @sizeOf(Symbol.Extra)); |
| 382 | for (self.symtab.items[0..first_global], 0..) |sym, i| { | 387 | try self.symbols_resolver.ensureTotalCapacityPrecise(allocator, nglobals); |
| 383 | const index = try elf_file.addSymbol(); | 388 | self.symbols_resolver.resize(allocator, nglobals) catch unreachable; |
| 384 | self.symbols.appendAssumeCapacity(index); | 389 | @memset(self.symbols_resolver.items, 0); |
| 385 | const sym_ptr = elf_file.symbol(index); | 390 | |
| | 391 | for (self.symtab.items, 0..) |sym, i| { |
| | 392 | const index = self.addSymbolAssumeCapacity(); |
| | 393 | const sym_ptr = &self.symbols.items[index]; |
| 386 | sym_ptr.value = @intCast(sym.st_value); | 394 | sym_ptr.value = @intCast(sym.st_value); |
| 387 | sym_ptr.name_offset = sym.st_name; | 395 | sym_ptr.name_offset = sym.st_name; |
| 388 | sym_ptr.esym_index = @as(u32, @intCast(i)); | 396 | sym_ptr.esym_index = @intCast(i); |
| 389 | sym_ptr.file_index = self.index; | 397 | sym_ptr.extra_index = self.addSymbolExtraAssumeCapacity(.{ |
| 390 | sym_ptr.extra_index = try elf_file.addSymbolExtra(.{}); | 398 | .weak = sym.st_bind() == elf.STB_WEAK, |
| 391 | if (sym.st_shndx != elf.SHN_ABS) { | 399 | }); |
| | 400 | sym_ptr.version_index = if (i >= first_global) elf_file.default_sym_version else elf.VER_NDX_LOCAL; |
| | 401 | if (sym.st_shndx != elf.SHN_ABS and sym.st_shndx != elf.SHN_COMMON) { |
| 392 | sym_ptr.ref = .{ .index = self.atoms_indexes.items[sym.st_shndx], .file = self.index }; | 402 | sym_ptr.ref = .{ .index = self.atoms_indexes.items[sym.st_shndx], .file = self.index }; |
| 393 | } | 403 | } |
| 394 | } | 404 | } |
| 395 | | | |
| 396 | for (self.symtab.items[first_global..]) |sym| { | | |
| 397 | const name = self.getString(sym.st_name); | | |
| 398 | const gop = try elf_file.getOrPutGlobal(name); | | |
| 399 | self.symbols.addOneAssumeCapacity().* = gop.index; | | |
| 400 | } | | |
| 401 | } | 405 | } |
| 402 | | 406 | |
| 403 | fn parseEhFrame(self: *Object, allocator: Allocator, handle: std.fs.File, shndx: u32, elf_file: *Elf) !void { | 407 | fn parseEhFrame(self: *Object, allocator: Allocator, handle: std.fs.File, shndx: u32, elf_file: *Elf) !void { |
| ... | @@ -544,7 +548,7 @@ pub fn scanRelocs(self: *Object, elf_file: *Elf, undefs: anytype) !void { | ... | @@ -544,7 +548,7 @@ pub fn scanRelocs(self: *Object, elf_file: *Elf, undefs: anytype) !void { |
| 544 | | 548 | |
| 545 | for (self.cies.items) |cie| { | 549 | for (self.cies.items) |cie| { |
| 546 | for (cie.relocs(elf_file)) |rel| { | 550 | for (cie.relocs(elf_file)) |rel| { |
| 547 | const sym = elf_file.symbol(self.symbols.items[rel.r_sym()]); | 551 | const sym = elf_file.symbol(self.resolveSymbol(rel.r_sym())); |
| 548 | if (sym.flags.import) { | 552 | if (sym.flags.import) { |
| 549 | if (sym.type(elf_file) != elf.STT_FUNC) | 553 | if (sym.type(elf_file) != elf.STT_FUNC) |
| 550 | // TODO convert into an error | 554 | // TODO convert into an error |
| ... | @@ -559,48 +563,46 @@ pub fn scanRelocs(self: *Object, elf_file: *Elf, undefs: anytype) !void { | ... | @@ -559,48 +563,46 @@ pub fn scanRelocs(self: *Object, elf_file: *Elf, undefs: anytype) !void { |
| 559 | } | 563 | } |
| 560 | | 564 | |
| 561 | pub fn resolveSymbols(self: *Object, elf_file: *Elf) void { | 565 | pub fn resolveSymbols(self: *Object, elf_file: *Elf) void { |
| 562 | const first_global = self.first_global orelse return; | 566 | const gpa = elf_file.base.comp.gpa; |
| 563 | for (self.globals(), 0..) |index, i| { | | |
| 564 | const esym_index = @as(Symbol.Index, @intCast(first_global + i)); | | |
| 565 | const esym = self.symtab.items[esym_index]; | | |
| 566 | | | |
| 567 | if (esym.st_shndx == elf.SHN_UNDEF) continue; | | |
| 568 | | 567 | |
| | 568 | const first_global = self.first_global orelse return; |
| | 569 | for (self.globals(), first_global..) |_, i| { |
| | 570 | const esym = self.symtab.items[i]; |
| 569 | if (esym.st_shndx != elf.SHN_ABS and esym.st_shndx != elf.SHN_COMMON) { | 571 | if (esym.st_shndx != elf.SHN_ABS and esym.st_shndx != elf.SHN_COMMON) { |
| 570 | const atom_index = self.atoms_indexes.items[esym.st_shndx]; | 572 | const atom_index = self.atoms_indexes.items[esym.st_shndx]; |
| 571 | const atom_ptr = self.atom(atom_index) orelse continue; | 573 | const atom_ptr = self.atom(atom_index) orelse continue; |
| 572 | if (!atom_ptr.alive) continue; | 574 | if (!atom_ptr.alive) continue; |
| 573 | } | 575 | } |
| 574 | | 576 | |
| 575 | const global = elf_file.symbol(index); | 577 | const resolv = &self.symbols_resolver.items[i - first_global]; |
| 576 | if (self.asFile().symbolRank(esym, !self.alive) < global.symbolRank(elf_file)) { | 578 | const gop = try elf_file.resolver.getOrPut(gpa, .{ |
| 577 | switch (esym.st_shndx) { | 579 | .index = @intCast(i), |
| 578 | elf.SHN_ABS, elf.SHN_COMMON => {}, | 580 | .file = self.index, |
| 579 | else => global.ref = .{ | 581 | }, elf_file); |
| 580 | .index = self.atoms_indexes.items[esym.st_shndx], | 582 | if (!gop.found_existing) { |
| 581 | .file = self.index, | 583 | gop.ref.* = .{ .index = 0, .file = 0 }; |
| 582 | }, | 584 | } |
| 583 | } | 585 | resolv.* = gop.index; |
| 584 | global.value = @intCast(esym.st_value); | 586 | |
| 585 | global.esym_index = esym_index; | 587 | if (esym.st_shndx == elf.SHN_UNDEF) continue; |
| 586 | global.file_index = self.index; | 588 | if (elf_file.symbol(gop.ref) == null) { |
| 587 | global.version_index = elf_file.default_sym_version; | 589 | gop.ref.* = .{ .index = @intCast(i), .file = self.index }; |
| 588 | if (esym.st_bind() == elf.STB_WEAK) global.flags.weak = true; | 590 | continue; |
| | 591 | } |
| | 592 | |
| | 593 | if (self.asFile().symbolRank(esym, !self.alive) < elf_file.symbol(gop.ref).?.symbolRank(elf_file)) { |
| | 594 | gop.ref.* = .{ .index = @intCast(i), .file = self.index }; |
| 589 | } | 595 | } |
| 590 | } | 596 | } |
| 591 | } | 597 | } |
| 592 | | 598 | |
| 593 | pub fn claimUnresolved(self: *Object, elf_file: *Elf) void { | 599 | pub fn claimUnresolved(self: *Object, elf_file: *Elf) void { |
| 594 | const first_global = self.first_global orelse return; | 600 | const first_global = self.first_global orelse return; |
| 595 | for (self.globals(), 0..) |index, i| { | 601 | for (self.globals(), 0..) |*sym, i| { |
| 596 | const esym_index = @as(u32, @intCast(first_global + i)); | 602 | const esym_index = @as(u32, @intCast(first_global + i)); |
| 597 | const esym = self.symtab.items[esym_index]; | 603 | const esym = self.symtab.items[esym_index]; |
| 598 | if (esym.st_shndx != elf.SHN_UNDEF) continue; | 604 | if (esym.st_shndx != elf.SHN_UNDEF) continue; |
| 599 | | 605 | if (elf_file.symbol(self.resolveSymbol(esym_index, elf_file)) != null) continue; |
| 600 | const global = elf_file.symbol(index); | | |
| 601 | if (global.file(elf_file)) |_| { | | |
| 602 | if (global.elfSym(elf_file).st_shndx != elf.SHN_UNDEF) continue; | | |
| 603 | } | | |
| 604 | | 606 | |
| 605 | const is_import = blk: { | 607 | const is_import = blk: { |
| 606 | if (!elf_file.isEffectivelyDynLib()) break :blk false; | 608 | if (!elf_file.isEffectivelyDynLib()) break :blk false; |
| ... | @@ -609,12 +611,15 @@ pub fn claimUnresolved(self: *Object, elf_file: *Elf) void { | ... | @@ -609,12 +611,15 @@ pub fn claimUnresolved(self: *Object, elf_file: *Elf) void { |
| 609 | break :blk true; | 611 | break :blk true; |
| 610 | }; | 612 | }; |
| 611 | | 613 | |
| 612 | global.value = 0; | 614 | sym.value = 0; |
| 613 | global.ref = .{ .index = 0, .file = 0 }; | 615 | sym.ref = .{ .index = 0, .file = 0 }; |
| 614 | global.esym_index = esym_index; | 616 | sym.esym_index = esym_index; |
| 615 | global.file_index = self.index; | 617 | sym.file_index = self.index; |
| 616 | global.version_index = if (is_import) elf.VER_NDX_LOCAL else elf_file.default_sym_version; | 618 | sym.version_index = if (is_import) elf.VER_NDX_LOCAL else elf_file.default_sym_version; |
| 617 | global.flags.import = is_import; | 619 | sym.flags.import = is_import; |
| | 620 | |
| | 621 | const idx = self.symbols_resolver.items[i]; |
| | 622 | elf_file.resolver.values.items[idx - 1] = .{ .index = esym_index, .file = self.index }; |
| 618 | } | 623 | } |
| 619 | } | 624 | } |
| 620 | | 625 | |
| ... | @@ -1141,20 +1146,6 @@ pub fn writeSymtab(self: Object, elf_file: *Elf) void { | ... | @@ -1141,20 +1146,6 @@ pub fn writeSymtab(self: Object, elf_file: *Elf) void { |
| 1141 | } | 1146 | } |
| 1142 | } | 1147 | } |
| 1143 | | 1148 | |
| 1144 | pub fn locals(self: Object) []const Symbol.Index { | | |
| 1145 | if (self.symbols.items.len == 0) return &[0]Symbol.Index{}; | | |
| 1146 | assert(self.symbols.items.len >= self.symtab.items.len); | | |
| 1147 | const end = self.first_global orelse self.symtab.items.len; | | |
| 1148 | return self.symbols.items[0..end]; | | |
| 1149 | } | | |
| 1150 | | | |
| 1151 | pub fn globals(self: Object) []const Symbol.Index { | | |
| 1152 | if (self.symbols.items.len == 0) return &[0]Symbol.Index{}; | | |
| 1153 | assert(self.symbols.items.len >= self.symtab.items.len); | | |
| 1154 | const start = self.first_global orelse self.symtab.items.len; | | |
| 1155 | return self.symbols.items[start..self.symtab.items.len]; | | |
| 1156 | } | | |
| 1157 | | | |
| 1158 | /// Returns atom's code and optionally uncompresses data if required (for compressed sections). | 1149 | /// Returns atom's code and optionally uncompresses data if required (for compressed sections). |
| 1159 | /// Caller owns the memory. | 1150 | /// Caller owns the memory. |
| 1160 | pub fn codeDecompressAlloc(self: *Object, elf_file: *Elf, atom_index: Atom.Index) ![]u8 { | 1151 | pub fn codeDecompressAlloc(self: *Object, elf_file: *Elf, atom_index: Atom.Index) ![]u8 { |
| ... | @@ -1187,6 +1178,77 @@ pub fn codeDecompressAlloc(self: *Object, elf_file: *Elf, atom_index: Atom.Index | ... | @@ -1187,6 +1178,77 @@ pub fn codeDecompressAlloc(self: *Object, elf_file: *Elf, atom_index: Atom.Index |
| 1187 | return data; | 1178 | return data; |
| 1188 | } | 1179 | } |
| 1189 | | 1180 | |
| | 1181 | pub fn locals(self: *Object) []Symbol { |
| | 1182 | if (self.symbols.items.len == 0) return &[0]Symbol{}; |
| | 1183 | assert(self.symbols.items.len >= self.symtab.items.len); |
| | 1184 | const end = self.first_global orelse self.symtab.items.len; |
| | 1185 | return self.symbols.items[0..end]; |
| | 1186 | } |
| | 1187 | |
| | 1188 | pub fn globals(self: *Object) []Symbol { |
| | 1189 | if (self.symbols.items.len == 0) return &[0]Symbol{}; |
| | 1190 | assert(self.symbols.items.len >= self.symtab.items.len); |
| | 1191 | const start = self.first_global orelse self.symtab.items.len; |
| | 1192 | return self.symbols.items[start..self.symtab.items.len]; |
| | 1193 | } |
| | 1194 | |
| | 1195 | pub fn resolveSymbol(self: Object, index: Symbol.Index, elf_file: *Elf) Elf.Ref { |
| | 1196 | const start = self.first_global orelse self.symtab.items.len; |
| | 1197 | const end = self.symtab.items.len; |
| | 1198 | if (index < start or index >= end) return .{ .index = index, .file = self.index }; |
| | 1199 | const resolv = self.symbols_resolver.items[index - start]; |
| | 1200 | return elf_file.resolver.get(resolv).?; |
| | 1201 | } |
| | 1202 | |
| | 1203 | pub fn addSymbol(self: *Object, allocator: Allocator) !Symbol.Index { |
| | 1204 | try self.symbols.ensureUnusedCapacity(allocator, 1); |
| | 1205 | const index: Symbol.Index = @intCast(self.symbols.items.len); |
| | 1206 | self.symbols.appendAssumeCapacity(.{ .file_index = self.index }); |
| | 1207 | return index; |
| | 1208 | } |
| | 1209 | |
| | 1210 | pub fn addSymbolExtra(self: *Object, allocator: Allocator, extra: Symbol.Extra) !u32 { |
| | 1211 | const fields = @typeInfo(Symbol.Extra).Struct.fields; |
| | 1212 | try self.symbols_extra.ensureUnusedCapacity(allocator, fields.len); |
| | 1213 | return self.addSymbolExtraAssumeCapacity(extra); |
| | 1214 | } |
| | 1215 | |
| | 1216 | pub fn addSymbolExtraAssumeCapacity(self: *Object, extra: Symbol.Extra) u32 { |
| | 1217 | const index = @as(u32, @intCast(self.symbols_extra.items.len)); |
| | 1218 | const fields = @typeInfo(Symbol.Extra).Struct.fields; |
| | 1219 | inline for (fields) |field| { |
| | 1220 | self.symbols_extra.appendAssumeCapacity(switch (field.type) { |
| | 1221 | u32 => @field(extra, field.name), |
| | 1222 | else => @compileError("bad field type"), |
| | 1223 | }); |
| | 1224 | } |
| | 1225 | return index; |
| | 1226 | } |
| | 1227 | |
| | 1228 | pub fn symbolExtra(self: *Object, index: u32) Symbol.Extra { |
| | 1229 | const fields = @typeInfo(Symbol.Extra).Struct.fields; |
| | 1230 | var i: usize = index; |
| | 1231 | var result: Symbol.Extra = undefined; |
| | 1232 | inline for (fields) |field| { |
| | 1233 | @field(result, field.name) = switch (field.type) { |
| | 1234 | u32 => self.symbols_extra.items[i], |
| | 1235 | else => @compileError("bad field type"), |
| | 1236 | }; |
| | 1237 | i += 1; |
| | 1238 | } |
| | 1239 | return result; |
| | 1240 | } |
| | 1241 | |
| | 1242 | pub fn setSymbolExtra(self: *Object, index: u32, extra: Symbol.Extra) void { |
| | 1243 | const fields = @typeInfo(Symbol.Extra).Struct.fields; |
| | 1244 | inline for (fields, 0..) |field, i| { |
| | 1245 | self.symbols_extra.items[index + i] = switch (field.type) { |
| | 1246 | u32 => @field(extra, field.name), |
| | 1247 | else => @compileError("bad field type"), |
| | 1248 | }; |
| | 1249 | } |
| | 1250 | } |
| | 1251 | |
| 1190 | pub fn asFile(self: *Object) File { | 1252 | pub fn asFile(self: *Object) File { |
| 1191 | return .{ .object = self }; | 1253 | return .{ .object = self }; |
| 1192 | } | 1254 | } |