| ... | ... | @@ -9,7 +9,9 @@ shdrs: std.ArrayListUnmanaged(elf.Elf64_Shdr) = .{}, |
| 9 | 9 | symtab: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{}, |
| 10 | 10 | strtab: std.ArrayListUnmanaged(u8) = .{}, |
| 11 | 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 | 15 | relocs: std.ArrayListUnmanaged(elf.Elf64_Rela) = .{}, |
| 14 | 16 | |
| 15 | 17 | atoms: std.ArrayListUnmanaged(Atom) = .{}, |
| ... | ... | @@ -51,6 +53,8 @@ pub fn deinit(self: *Object, allocator: Allocator) void { |
| 51 | 53 | self.symtab.deinit(allocator); |
| 52 | 54 | self.strtab.deinit(allocator); |
| 53 | 55 | self.symbols.deinit(allocator); |
| 56 | self.symbols_extra.deinit(allocator); |
| 57 | self.symbols_resolver.deinit(allocator); |
| 54 | 58 | self.atoms.deinit(allocator); |
| 55 | 59 | self.atoms_indexes.deinit(allocator); |
| 56 | 60 | self.atoms_extra.deinit(allocator); |
| ... | ... | @@ -80,7 +84,7 @@ pub fn parse(self: *Object, elf_file: *Elf) !void { |
| 80 | 84 | try self.atoms.append(gpa, .{ .extra_index = try self.addAtomExtra(gpa, .{}) }); |
| 81 | 85 | |
| 82 | 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 | 89 | for (self.shdrs.items, 0..) |shdr, i| { |
| 86 | 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 | 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 | 382 | const first_global = self.first_global orelse self.symtab.items.len; |
| 383 | const nglobals = self.symtab.items.len - first_global; |
| 379 | 384 | |
| 380 | 385 | try self.symbols.ensureTotalCapacityPrecise(allocator, self.symtab.items.len); |
| 381 | | |
| 382 | | for (self.symtab.items[0..first_global], 0..) |sym, i| { |
| 383 | | const index = try elf_file.addSymbol(); |
| 384 | | self.symbols.appendAssumeCapacity(index); |
| 385 | | const sym_ptr = elf_file.symbol(index); |
| 386 | try self.symbols_extra.ensureTotalCapacityPrecise(allocator, self.symtab.items.len * @sizeOf(Symbol.Extra)); |
| 387 | try self.symbols_resolver.ensureTotalCapacityPrecise(allocator, nglobals); |
| 388 | self.symbols_resolver.resize(allocator, nglobals) catch unreachable; |
| 389 | @memset(self.symbols_resolver.items, 0); |
| 390 | |
| 391 | for (self.symtab.items, 0..) |sym, i| { |
| 392 | const index = self.addSymbolAssumeCapacity(); |
| 393 | const sym_ptr = &self.symbols.items[index]; |
| 386 | 394 | sym_ptr.value = @intCast(sym.st_value); |
| 387 | 395 | sym_ptr.name_offset = sym.st_name; |
| 388 | | sym_ptr.esym_index = @as(u32, @intCast(i)); |
| 389 | | sym_ptr.file_index = self.index; |
| 390 | | sym_ptr.extra_index = try elf_file.addSymbolExtra(.{}); |
| 391 | | if (sym.st_shndx != elf.SHN_ABS) { |
| 396 | sym_ptr.esym_index = @intCast(i); |
| 397 | sym_ptr.extra_index = self.addSymbolExtraAssumeCapacity(.{ |
| 398 | .weak = sym.st_bind() == elf.STB_WEAK, |
| 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 | 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 | 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 | 548 | |
| 545 | 549 | for (self.cies.items) |cie| { |
| 546 | 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 | 552 | if (sym.flags.import) { |
| 549 | 553 | if (sym.type(elf_file) != elf.STT_FUNC) |
| 550 | 554 | // TODO convert into an error |
| ... | ... | @@ -559,48 +563,46 @@ pub fn scanRelocs(self: *Object, elf_file: *Elf, undefs: anytype) !void { |
| 559 | 563 | } |
| 560 | 564 | |
| 561 | 565 | pub fn resolveSymbols(self: *Object, elf_file: *Elf) void { |
| 562 | | const first_global = self.first_global orelse return; |
| 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; |
| 566 | const gpa = elf_file.base.comp.gpa; |
| 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 | 571 | if (esym.st_shndx != elf.SHN_ABS and esym.st_shndx != elf.SHN_COMMON) { |
| 570 | 572 | const atom_index = self.atoms_indexes.items[esym.st_shndx]; |
| 571 | 573 | const atom_ptr = self.atom(atom_index) orelse continue; |
| 572 | 574 | if (!atom_ptr.alive) continue; |
| 573 | 575 | } |
| 574 | 576 | |
| 575 | | const global = elf_file.symbol(index); |
| 576 | | if (self.asFile().symbolRank(esym, !self.alive) < global.symbolRank(elf_file)) { |
| 577 | | switch (esym.st_shndx) { |
| 578 | | elf.SHN_ABS, elf.SHN_COMMON => {}, |
| 579 | | else => global.ref = .{ |
| 580 | | .index = self.atoms_indexes.items[esym.st_shndx], |
| 581 | | .file = self.index, |
| 582 | | }, |
| 583 | | } |
| 584 | | global.value = @intCast(esym.st_value); |
| 585 | | global.esym_index = esym_index; |
| 586 | | global.file_index = self.index; |
| 587 | | global.version_index = elf_file.default_sym_version; |
| 588 | | if (esym.st_bind() == elf.STB_WEAK) global.flags.weak = true; |
| 577 | const resolv = &self.symbols_resolver.items[i - first_global]; |
| 578 | const gop = try elf_file.resolver.getOrPut(gpa, .{ |
| 579 | .index = @intCast(i), |
| 580 | .file = self.index, |
| 581 | }, elf_file); |
| 582 | if (!gop.found_existing) { |
| 583 | gop.ref.* = .{ .index = 0, .file = 0 }; |
| 584 | } |
| 585 | resolv.* = gop.index; |
| 586 | |
| 587 | if (esym.st_shndx == elf.SHN_UNDEF) continue; |
| 588 | if (elf_file.symbol(gop.ref) == null) { |
| 589 | gop.ref.* = .{ .index = @intCast(i), .file = self.index }; |
| 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 | 599 | pub fn claimUnresolved(self: *Object, elf_file: *Elf) void { |
| 594 | 600 | const first_global = self.first_global orelse return; |
| 595 | | for (self.globals(), 0..) |index, i| { |
| 601 | for (self.globals(), 0..) |*sym, i| { |
| 596 | 602 | const esym_index = @as(u32, @intCast(first_global + i)); |
| 597 | 603 | const esym = self.symtab.items[esym_index]; |
| 598 | 604 | if (esym.st_shndx != elf.SHN_UNDEF) continue; |
| 599 | | |
| 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 | | } |
| 605 | if (elf_file.symbol(self.resolveSymbol(esym_index, elf_file)) != null) continue; |
| 604 | 606 | |
| 605 | 607 | const is_import = blk: { |
| 606 | 608 | if (!elf_file.isEffectivelyDynLib()) break :blk false; |
| ... | ... | @@ -609,12 +611,15 @@ pub fn claimUnresolved(self: *Object, elf_file: *Elf) void { |
| 609 | 611 | break :blk true; |
| 610 | 612 | }; |
| 611 | 613 | |
| 612 | | global.value = 0; |
| 613 | | global.ref = .{ .index = 0, .file = 0 }; |
| 614 | | global.esym_index = esym_index; |
| 615 | | global.file_index = self.index; |
| 616 | | global.version_index = if (is_import) elf.VER_NDX_LOCAL else elf_file.default_sym_version; |
| 617 | | global.flags.import = is_import; |
| 614 | sym.value = 0; |
| 615 | sym.ref = .{ .index = 0, .file = 0 }; |
| 616 | sym.esym_index = esym_index; |
| 617 | sym.file_index = self.index; |
| 618 | sym.version_index = if (is_import) elf.VER_NDX_LOCAL else elf_file.default_sym_version; |
| 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 | 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 | 1149 | /// Returns atom's code and optionally uncompresses data if required (for compressed sections). |
| 1159 | 1150 | /// Caller owns the memory. |
| 1160 | 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 | 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 | 1252 | pub fn asFile(self: *Object) File { |
| 1191 | 1253 | return .{ .object = self }; |
| 1192 | 1254 | } |