| ... | ... | @@ -6,6 +6,18 @@ phdrs: std.ArrayList(MappedFile.Node.Index), |
| 6 | 6 | symtab: std.ArrayList(Symbol), |
| 7 | 7 | shstrtab: StringTable, |
| 8 | 8 | strtab: StringTable, |
| 9 | inputs: std.ArrayList(struct { |
| 10 | path: std.Build.Cache.Path, |
| 11 | si: Symbol.Index, |
| 12 | }), |
| 13 | input_sections: std.ArrayList(struct { |
| 14 | ii: Node.InputIndex, |
| 15 | ni: MappedFile.Node.Index, |
| 16 | addr: u64, |
| 17 | offset: u64, |
| 18 | size: u64, |
| 19 | }), |
| 20 | input_section_pending_index: u32, |
| 9 | 21 | globals: std.AutoArrayHashMapUnmanaged(u32, Symbol.Index), |
| 10 | 22 | navs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, Symbol.Index), |
| 11 | 23 | uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, Symbol.Index), |
| ... | ... | @@ -20,6 +32,9 @@ pending_uavs: std.AutoArrayHashMapUnmanaged(Node.UavMapIndex, struct { |
| 20 | 32 | relocs: std.ArrayList(Reloc), |
| 21 | 33 | /// This is hiding actual bugs with global symbols! Reconsider once they are implemented correctly. |
| 22 | 34 | entry_hack: Symbol.Index, |
| 35 | const_prog_node: std.Progress.Node, |
| 36 | synth_prog_node: std.Progress.Node, |
| 37 | input_prog_node: std.Progress.Node, |
| 23 | 38 | |
| 24 | 39 | pub const Node = union(enum) { |
| 25 | 40 | file, |
| ... | ... | @@ -27,11 +42,53 @@ pub const Node = union(enum) { |
| 27 | 42 | shdr, |
| 28 | 43 | segment: u32, |
| 29 | 44 | section: Symbol.Index, |
| 45 | input_section: InputSectionIndex, |
| 30 | 46 | nav: NavMapIndex, |
| 31 | 47 | uav: UavMapIndex, |
| 32 | 48 | lazy_code: LazyMapRef.Index(.code), |
| 33 | 49 | lazy_const_data: LazyMapRef.Index(.const_data), |
| 34 | 50 | |
| 51 | pub const InputIndex = enum(u32) { |
| 52 | _, |
| 53 | |
| 54 | pub fn path(ii: InputIndex, elf: *const Elf) std.Build.Cache.Path { |
| 55 | return elf.inputs.items[@intFromEnum(ii)].path; |
| 56 | } |
| 57 | |
| 58 | pub fn symbol(ii: InputIndex, elf: *const Elf) Symbol.Index { |
| 59 | return elf.inputs.items[@intFromEnum(ii)].si; |
| 60 | } |
| 61 | |
| 62 | pub fn nextSymbol(ii: InputIndex, elf: *const Elf) Symbol.Index { |
| 63 | const next_ii = @intFromEnum(ii) + 1; |
| 64 | return if (next_ii < elf.inputs.items.len) |
| 65 | @as(InputIndex, @enumFromInt(next_ii)).symbol(elf) |
| 66 | else |
| 67 | @enumFromInt(elf.symtab.items.len); |
| 68 | } |
| 69 | }; |
| 70 | |
| 71 | pub const InputSectionIndex = enum(u32) { |
| 72 | _, |
| 73 | |
| 74 | pub fn input(isi: InputSectionIndex, elf: *const Elf) InputIndex { |
| 75 | return elf.input_sections.items[@intFromEnum(isi)].ii; |
| 76 | } |
| 77 | |
| 78 | pub fn node(isi: InputSectionIndex, elf: *const Elf) MappedFile.Node.Index { |
| 79 | return elf.input_sections.items[@intFromEnum(isi)].ni; |
| 80 | } |
| 81 | |
| 82 | pub fn addr(isi: InputSectionIndex, elf: *Elf) *u64 { |
| 83 | return &elf.input_sections.items[@intFromEnum(isi)].addr; |
| 84 | } |
| 85 | |
| 86 | pub fn fileLocation(isi: InputSectionIndex, elf: *const Elf) struct { u64, u64 } { |
| 87 | const input_section = &elf.input_sections.items[@intFromEnum(isi)]; |
| 88 | return .{ input_section.offset, input_section.size }; |
| 89 | } |
| 90 | }; |
| 91 | |
| 35 | 92 | pub const NavMapIndex = enum(u32) { |
| 36 | 93 | _, |
| 37 | 94 | |
| ... | ... | @@ -189,9 +246,14 @@ pub const Symbol = struct { |
| 189 | 246 | return ni; |
| 190 | 247 | } |
| 191 | 248 | |
| 249 | pub fn next(si: Symbol.Index) Symbol.Index { |
| 250 | return @enumFromInt(@intFromEnum(si) + 1); |
| 251 | } |
| 252 | |
| 192 | 253 | pub const InitOptions = struct { |
| 193 | 254 | name: []const u8 = "", |
| 194 | | size: std.elf.Word = 0, |
| 255 | value: u64 = 0, |
| 256 | size: u64 = 0, |
| 195 | 257 | type: std.elf.STT, |
| 196 | 258 | bind: std.elf.STB = .LOCAL, |
| 197 | 259 | visibility: std.elf.STV = .DEFAULT, |
| ... | ... | @@ -211,8 +273,8 @@ pub const Symbol = struct { |
| 211 | 273 | switch (elf.symPtr(si)) { |
| 212 | 274 | inline else => |sym| sym.* = .{ |
| 213 | 275 | .name = name_entry, |
| 214 | | .value = 0, |
| 215 | | .size = opts.size, |
| 276 | .value = @intCast(opts.value), |
| 277 | .size = @intCast(opts.size), |
| 216 | 278 | .info = .{ |
| 217 | 279 | .type = opts.type, |
| 218 | 280 | .bind = opts.bind, |
| ... | ... | @@ -225,8 +287,7 @@ pub const Symbol = struct { |
| 225 | 287 | } |
| 226 | 288 | } |
| 227 | 289 | |
| 228 | | pub fn flushMoved(si: Symbol.Index, elf: *Elf) void { |
| 229 | | const value = elf.computeNodeVAddr(si.node(elf)); |
| 290 | pub fn flushMoved(si: Symbol.Index, elf: *Elf, value: u64) void { |
| 230 | 291 | switch (elf.symPtr(si)) { |
| 231 | 292 | inline else => |sym, class| { |
| 232 | 293 | elf.targetStore(&sym.value, @intCast(value)); |
| ... | ... | @@ -443,11 +504,11 @@ fn create( |
| 443 | 504 | }; |
| 444 | 505 | |
| 445 | 506 | const elf = try arena.create(Elf); |
| 446 | | const file = try path.root_dir.handle.createFile(path.sub_path, .{ |
| 507 | const file = try path.root_dir.handle.adaptToNewApi().createFile(comp.io, path.sub_path, .{ |
| 447 | 508 | .read = true, |
| 448 | 509 | .mode = link.File.determineMode(comp.config.output_mode, comp.config.link_mode), |
| 449 | 510 | }); |
| 450 | | errdefer file.close(); |
| 511 | errdefer file.close(comp.io); |
| 451 | 512 | elf.* = .{ |
| 452 | 513 | .base = .{ |
| 453 | 514 | .tag = .elf2, |
| ... | ... | @@ -455,7 +516,7 @@ fn create( |
| 455 | 516 | .comp = comp, |
| 456 | 517 | .emit = path, |
| 457 | 518 | |
| 458 | | .file = file, |
| 519 | .file = .adaptFromNewApi(file), |
| 459 | 520 | .gc_sections = false, |
| 460 | 521 | .print_gc_sections = false, |
| 461 | 522 | .build_id = .none, |
| ... | ... | @@ -477,6 +538,9 @@ fn create( |
| 477 | 538 | .map = .empty, |
| 478 | 539 | .size = 1, |
| 479 | 540 | }, |
| 541 | .inputs = .empty, |
| 542 | .input_sections = .empty, |
| 543 | .input_section_pending_index = 0, |
| 480 | 544 | .globals = .empty, |
| 481 | 545 | .navs = .empty, |
| 482 | 546 | .uavs = .empty, |
| ... | ... | @@ -487,6 +551,9 @@ fn create( |
| 487 | 551 | .pending_uavs = .empty, |
| 488 | 552 | .relocs = .empty, |
| 489 | 553 | .entry_hack = .null, |
| 554 | .const_prog_node = .none, |
| 555 | .synth_prog_node = .none, |
| 556 | .input_prog_node = .none, |
| 490 | 557 | }; |
| 491 | 558 | errdefer elf.deinit(); |
| 492 | 559 | |
| ... | ... | @@ -502,6 +569,8 @@ pub fn deinit(elf: *Elf) void { |
| 502 | 569 | elf.symtab.deinit(gpa); |
| 503 | 570 | elf.shstrtab.map.deinit(gpa); |
| 504 | 571 | elf.strtab.map.deinit(gpa); |
| 572 | elf.inputs.deinit(gpa); |
| 573 | elf.input_sections.deinit(gpa); |
| 505 | 574 | elf.globals.deinit(gpa); |
| 506 | 575 | elf.navs.deinit(gpa); |
| 507 | 576 | elf.uavs.deinit(gpa); |
| ... | ... | @@ -796,16 +865,18 @@ fn initHeaders( |
| 796 | 865 | .addralign = elf.mf.flags.block_size, |
| 797 | 866 | .entsize = 1, |
| 798 | 867 | }) == .shstrtab); |
| 868 | try elf.renameSection(.symtab, ".symtab"); |
| 869 | try elf.renameSection(.shstrtab, ".shstrtab"); |
| 870 | Symbol.Index.shstrtab.node(elf).slice(&elf.mf)[0] = 0; |
| 871 | |
| 799 | 872 | assert(try elf.addSection(Node.Known.rodata, .{ |
| 873 | .name = ".strtab", |
| 800 | 874 | .type = std.elf.SHT_STRTAB, |
| 801 | 875 | .addralign = elf.mf.flags.block_size, |
| 876 | .size = 1, |
| 802 | 877 | .entsize = 1, |
| 803 | 878 | }) == .strtab); |
| 804 | | try elf.renameSection(.symtab, ".symtab"); |
| 805 | | try elf.renameSection(.shstrtab, ".shstrtab"); |
| 806 | | try elf.renameSection(.strtab, ".strtab"); |
| 807 | 879 | try elf.linkSections(.symtab, .strtab); |
| 808 | | Symbol.Index.shstrtab.node(elf).slice(&elf.mf)[0] = 0; |
| 809 | 880 | Symbol.Index.strtab.node(elf).slice(&elf.mf)[0] = 0; |
| 810 | 881 | |
| 811 | 882 | assert(try elf.addSection(Node.Known.rodata, .{ |
| ... | ... | @@ -860,6 +931,32 @@ fn initHeaders( |
| 860 | 931 | assert(elf.nodes.len == expected_nodes_len); |
| 861 | 932 | } |
| 862 | 933 | |
| 934 | pub fn startProgress(elf: *Elf, prog_node: std.Progress.Node) void { |
| 935 | prog_node.increaseEstimatedTotalItems(4); |
| 936 | elf.const_prog_node = prog_node.start("Constants", elf.pending_uavs.count()); |
| 937 | elf.synth_prog_node = prog_node.start("Synthetics", count: { |
| 938 | var count: usize = 0; |
| 939 | for (&elf.lazy.values) |*lazy| count += lazy.map.count() - lazy.pending_index; |
| 940 | break :count count; |
| 941 | }); |
| 942 | elf.mf.update_prog_node = prog_node.start("Relocations", elf.mf.updates.items.len); |
| 943 | elf.input_prog_node = prog_node.start( |
| 944 | "Inputs", |
| 945 | elf.input_sections.items.len - elf.input_section_pending_index, |
| 946 | ); |
| 947 | } |
| 948 | |
| 949 | pub fn endProgress(elf: *Elf) void { |
| 950 | elf.input_prog_node.end(); |
| 951 | elf.input_prog_node = .none; |
| 952 | elf.mf.update_prog_node.end(); |
| 953 | elf.mf.update_prog_node = .none; |
| 954 | elf.synth_prog_node.end(); |
| 955 | elf.synth_prog_node = .none; |
| 956 | elf.const_prog_node.end(); |
| 957 | elf.const_prog_node = .none; |
| 958 | } |
| 959 | |
| 863 | 960 | fn getNode(elf: *const Elf, ni: MappedFile.Node.Index) Node { |
| 864 | 961 | return elf.nodes.get(@intFromEnum(ni)); |
| 865 | 962 | } |
| ... | ... | @@ -871,6 +968,7 @@ fn computeNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 { |
| 871 | 968 | inline else => |ph| elf.targetLoad(&ph[phndx].vaddr), |
| 872 | 969 | }, |
| 873 | 970 | .section => |si| si, |
| 971 | .input_section => unreachable, |
| 874 | 972 | inline .nav, .uav, .lazy_code, .lazy_const_data => |mi| mi.symbol(elf), |
| 875 | 973 | }; |
| 876 | 974 | break :parent_vaddr switch (elf.symPtr(parent_si)) { |
| ... | ... | @@ -1072,21 +1170,24 @@ fn navType( |
| 1072 | 1170 | }, |
| 1073 | 1171 | }; |
| 1074 | 1172 | } |
| 1173 | fn namedSection(name: []const u8) ?Symbol.Index { |
| 1174 | if (std.mem.eql(u8, name, ".rodata") or |
| 1175 | std.mem.startsWith(u8, name, ".rodata.")) return .rodata; |
| 1176 | if (std.mem.eql(u8, name, ".text") or |
| 1177 | std.mem.startsWith(u8, name, ".text.")) return .text; |
| 1178 | if (std.mem.eql(u8, name, ".data") or |
| 1179 | std.mem.startsWith(u8, name, ".data.")) return .data; |
| 1180 | if (std.mem.eql(u8, name, ".tdata") or |
| 1181 | std.mem.startsWith(u8, name, ".tdata.")) return .tdata; |
| 1182 | return null; |
| 1183 | } |
| 1075 | 1184 | fn navSection( |
| 1076 | 1185 | elf: *Elf, |
| 1077 | 1186 | ip: *const InternPool, |
| 1078 | 1187 | nav_fr: @FieldType(@FieldType(InternPool.Nav, "status"), "fully_resolved"), |
| 1079 | 1188 | ) Symbol.Index { |
| 1080 | | if (nav_fr.@"linksection".toSlice(ip)) |@"linksection"| { |
| 1081 | | if (std.mem.eql(u8, @"linksection", ".rodata") or |
| 1082 | | std.mem.startsWith(u8, @"linksection", ".rodata.")) return .rodata; |
| 1083 | | if (std.mem.eql(u8, @"linksection", ".text") or |
| 1084 | | std.mem.startsWith(u8, @"linksection", ".text.")) return .text; |
| 1085 | | if (std.mem.eql(u8, @"linksection", ".data") or |
| 1086 | | std.mem.startsWith(u8, @"linksection", ".data.")) return .data; |
| 1087 | | if (std.mem.eql(u8, @"linksection", ".tdata") or |
| 1088 | | std.mem.startsWith(u8, @"linksection", ".tdata.")) return .tdata; |
| 1089 | | } |
| 1189 | if (nav_fr.@"linksection".toSlice(ip)) |@"linksection"| |
| 1190 | if (namedSection(@"linksection")) |si| return si; |
| 1090 | 1191 | return switch (navType( |
| 1091 | 1192 | ip, |
| 1092 | 1193 | .{ .fully_resolved = nav_fr }, |
| ... | ... | @@ -1156,11 +1257,236 @@ pub fn lazySymbol(elf: *Elf, lazy: link.File.LazySymbol) !Symbol.Index { |
| 1156 | 1257 | .const_data => .OBJECT, |
| 1157 | 1258 | }, |
| 1158 | 1259 | }); |
| 1159 | | elf.base.comp.link_synth_prog_node.increaseEstimatedTotalItems(1); |
| 1260 | elf.synth_prog_node.increaseEstimatedTotalItems(1); |
| 1160 | 1261 | } |
| 1161 | 1262 | return lazy_gop.value_ptr.*; |
| 1162 | 1263 | } |
| 1163 | 1264 | |
| 1265 | pub fn loadInput(elf: *Elf, input: link.Input) !void { |
| 1266 | const comp = elf.base.comp; |
| 1267 | const gpa = comp.gpa; |
| 1268 | const diags = &comp.link_diags; |
| 1269 | switch (input) { |
| 1270 | .object => |object| { |
| 1271 | const ii: Node.InputIndex = @enumFromInt(elf.inputs.items.len); |
| 1272 | log.debug("loadInput(.{{ .object = {f} }}) = {d}", .{ object.path, ii }); |
| 1273 | { |
| 1274 | try elf.symtab.ensureUnusedCapacity(gpa, 1); |
| 1275 | try elf.inputs.ensureUnusedCapacity(gpa, 1); |
| 1276 | const si = try elf.initSymbolAssumeCapacity(.{ |
| 1277 | .name = std.fs.path.stem(object.path.sub_path), |
| 1278 | .type = .FILE, |
| 1279 | .shndx = std.elf.SHN_ABS, |
| 1280 | }); |
| 1281 | elf.inputs.addOneAssumeCapacity().* = .{ |
| 1282 | .path = object.path, |
| 1283 | .si = si, |
| 1284 | }; |
| 1285 | } |
| 1286 | var buf: [4096]u8 = undefined; |
| 1287 | var fr = object.file.reader(comp.io, &buf); |
| 1288 | const r = &fr.interface; |
| 1289 | const ident = try r.peek(std.elf.EI.NIDENT); |
| 1290 | if (!std.mem.eql(u8, elf.mf.contents[0..std.elf.EI.NIDENT], ident)) |
| 1291 | return diags.failParse(object.path, "wrong ident", .{}); |
| 1292 | const target_endian = elf.targetEndian(); |
| 1293 | switch (elf.identClass()) { |
| 1294 | .NONE, _ => unreachable, |
| 1295 | inline else => |class| { |
| 1296 | const ehdr = try r.peekStruct( |
| 1297 | @typeInfo(@FieldType(EhdrPtr, @tagName(class))).pointer.child, |
| 1298 | target_endian, |
| 1299 | ); |
| 1300 | if (ehdr.type != .REL) |
| 1301 | return diags.failParse(object.path, "unsupported object type", .{}); |
| 1302 | if (ehdr.machine != elf.ehdrField(.machine)) |
| 1303 | return diags.failParse(object.path, "wrong machine", .{}); |
| 1304 | if (ehdr.shoff == 0 or ehdr.shnum <= 1) return; |
| 1305 | if (ehdr.shstrndx == std.elf.SHN_UNDEF or ehdr.shstrndx >= ehdr.shnum) |
| 1306 | return diags.failParse(object.path, "missing section names", .{}); |
| 1307 | const Shdr = @typeInfo(@FieldType(ShdrSlice, @tagName(class))).pointer.child; |
| 1308 | if (ehdr.shentsize < @sizeOf(Shdr)) |
| 1309 | return diags.failParse(object.path, "unsupported shentsize", .{}); |
| 1310 | const shstrtab = shstrtab: { |
| 1311 | try fr.seekTo(ehdr.shoff + ehdr.shentsize * ehdr.shstrndx); |
| 1312 | const shdr = try r.peekStruct(Shdr, target_endian); |
| 1313 | if (shdr.type != std.elf.SHT_STRTAB) |
| 1314 | return diags.failParse(object.path, "invalid shstrtab type", .{}); |
| 1315 | const shstrtab = try gpa.alloc(u8, @intCast(shdr.size)); |
| 1316 | errdefer gpa.free(shstrtab); |
| 1317 | try fr.seekTo(shdr.offset); |
| 1318 | try r.readSliceAll(shstrtab); |
| 1319 | break :shstrtab shstrtab; |
| 1320 | }; |
| 1321 | defer gpa.free(shstrtab); |
| 1322 | const Sym = @typeInfo(@FieldType(SymPtr, @tagName(class))).pointer.child; |
| 1323 | try fr.seekTo(ehdr.shoff + ehdr.shentsize); |
| 1324 | var symtab_shdr: Shdr = .{ |
| 1325 | .name = 0, |
| 1326 | .type = 0, |
| 1327 | .flags = .{ .shf = .{} }, |
| 1328 | .addr = 0, |
| 1329 | .offset = 0, |
| 1330 | .size = 0, |
| 1331 | .link = 0, |
| 1332 | .info = 0, |
| 1333 | .addralign = 0, |
| 1334 | .entsize = 0, |
| 1335 | }; |
| 1336 | const sections = try gpa.alloc(struct { |
| 1337 | shndx: u32, |
| 1338 | ni: MappedFile.Node.Index, |
| 1339 | }, ehdr.shnum); |
| 1340 | defer gpa.free(sections); |
| 1341 | @memset(sections, .{ .shndx = std.elf.SHN_UNDEF, .ni = .none }); |
| 1342 | for (sections[1..ehdr.shnum]) |*section| { |
| 1343 | const shdr = try r.peekStruct(Shdr, target_endian); |
| 1344 | try r.discardAll(ehdr.shentsize); |
| 1345 | switch (shdr.type) { |
| 1346 | else => continue, |
| 1347 | std.elf.SHT_PROGBITS => {}, |
| 1348 | std.elf.SHT_SYMTAB => { |
| 1349 | if (symtab_shdr.entsize > 0) |
| 1350 | return diags.failParse(object.path, "too many symtabs", .{}); |
| 1351 | if (shdr.entsize < @sizeOf(Sym)) |
| 1352 | return diags.failParse(object.path, "unsupported entsize", .{}); |
| 1353 | symtab_shdr = shdr; |
| 1354 | continue; |
| 1355 | }, |
| 1356 | std.elf.SHT_NOBITS => {}, |
| 1357 | } |
| 1358 | if (shdr.name >= shstrtab.len) continue; |
| 1359 | const name = std.mem.sliceTo(shstrtab[shdr.name..], 0); |
| 1360 | const si = namedSection(name) orelse continue; |
| 1361 | section.shndx = elf.targetLoad(&@field(elf.symPtr(si), @tagName(class)).shndx); |
| 1362 | try elf.nodes.ensureUnusedCapacity(gpa, 1); |
| 1363 | try elf.input_sections.ensureUnusedCapacity(gpa, 1); |
| 1364 | section.ni = try elf.mf.addLastChildNode(gpa, si.node(elf), .{ |
| 1365 | .size = shdr.size, |
| 1366 | .alignment = .fromByteUnits(std.math.ceilPowerOfTwoAssert( |
| 1367 | usize, |
| 1368 | @intCast(@max(shdr.addralign, 1)), |
| 1369 | )), |
| 1370 | .moved = true, |
| 1371 | }); |
| 1372 | elf.nodes.appendAssumeCapacity(.{ |
| 1373 | .input_section = @enumFromInt(elf.input_sections.items.len), |
| 1374 | }); |
| 1375 | elf.input_sections.addOneAssumeCapacity().* = .{ |
| 1376 | .ii = ii, |
| 1377 | .ni = section.ni, |
| 1378 | .addr = shdr.addr, |
| 1379 | .offset = shdr.offset, |
| 1380 | .size = shdr.size, |
| 1381 | }; |
| 1382 | elf.synth_prog_node.increaseEstimatedTotalItems(1); |
| 1383 | } |
| 1384 | if (symtab_shdr.info <= 1) return; |
| 1385 | const strtab = strtab: { |
| 1386 | try fr.seekTo(ehdr.shoff + ehdr.shentsize * symtab_shdr.link); |
| 1387 | const shdr = try r.peekStruct(Shdr, target_endian); |
| 1388 | if (shdr.type != std.elf.SHT_STRTAB) |
| 1389 | return diags.failParse(object.path, "invalid strtab type", .{}); |
| 1390 | const strtab = try gpa.alloc(u8, @intCast(shdr.size)); |
| 1391 | errdefer gpa.free(strtab); |
| 1392 | try fr.seekTo(shdr.offset); |
| 1393 | try r.readSliceAll(strtab); |
| 1394 | break :strtab strtab; |
| 1395 | }; |
| 1396 | defer gpa.free(strtab); |
| 1397 | try elf.symtab.ensureUnusedCapacity(gpa, symtab_shdr.info); |
| 1398 | try elf.globals.ensureUnusedCapacity(gpa, symtab_shdr.info); |
| 1399 | try fr.seekTo(symtab_shdr.offset + symtab_shdr.entsize); |
| 1400 | for (1..try std.math.divExact( |
| 1401 | usize, |
| 1402 | @intCast(symtab_shdr.size), |
| 1403 | @intCast(symtab_shdr.entsize), |
| 1404 | )) |_| { |
| 1405 | const input_sym = try r.peekStruct(Sym, target_endian); |
| 1406 | try r.discardAll64(symtab_shdr.entsize); |
| 1407 | switch (input_sym.info.type) { |
| 1408 | else => continue, |
| 1409 | .OBJECT, .FUNC => {}, |
| 1410 | } |
| 1411 | if (input_sym.name >= strtab.len or input_sym.shndx >= sections.len) continue; |
| 1412 | const name = std.mem.sliceTo(strtab[input_sym.name..], 0); |
| 1413 | const si = try elf.initSymbolAssumeCapacity(.{ |
| 1414 | .name = name, |
| 1415 | .value = input_sym.value, |
| 1416 | .size = input_sym.size, |
| 1417 | .type = input_sym.info.type, |
| 1418 | .bind = input_sym.info.bind, |
| 1419 | .visibility = input_sym.other.visibility, |
| 1420 | .shndx = @intCast(sections[input_sym.shndx].shndx), |
| 1421 | }); |
| 1422 | { |
| 1423 | const sym = si.get(elf); |
| 1424 | sym.ni = sections[input_sym.shndx].ni; |
| 1425 | assert(sym.loc_relocs == .none); |
| 1426 | sym.loc_relocs = @enumFromInt(elf.relocs.items.len); |
| 1427 | } |
| 1428 | switch (input_sym.info.bind) { |
| 1429 | else => {}, |
| 1430 | .GLOBAL => { |
| 1431 | const gop = elf.globals.getOrPutAssumeCapacity(elf.targetLoad( |
| 1432 | &@field(elf.symPtr(si), @tagName(class)).name, |
| 1433 | )); |
| 1434 | if (gop.found_existing) switch (elf.targetLoad( |
| 1435 | switch (elf.symPtr(gop.value_ptr.*)) { |
| 1436 | inline else => |sym| &sym.info, |
| 1437 | }, |
| 1438 | ).bind) { |
| 1439 | else => unreachable, |
| 1440 | .GLOBAL => return diags.failParse( |
| 1441 | object.path, |
| 1442 | "multiple definitions of '{s}'", |
| 1443 | .{name}, |
| 1444 | ), |
| 1445 | .WEAK => {}, |
| 1446 | }; |
| 1447 | gop.value_ptr.* = si; |
| 1448 | }, |
| 1449 | .WEAK => { |
| 1450 | const gop = elf.globals.getOrPutAssumeCapacity(elf.targetLoad( |
| 1451 | &@field(elf.symPtr(si), @tagName(class)).name, |
| 1452 | )); |
| 1453 | if (!gop.found_existing) gop.value_ptr.* = si; |
| 1454 | }, |
| 1455 | } |
| 1456 | } |
| 1457 | }, |
| 1458 | } |
| 1459 | }, |
| 1460 | else => {}, |
| 1461 | } |
| 1462 | } |
| 1463 | |
| 1464 | pub fn prelink(elf: *Elf, prog_node: std.Progress.Node) !void { |
| 1465 | _ = prog_node; |
| 1466 | elf.prelinkInner() catch |err| switch (err) { |
| 1467 | error.OutOfMemory => return error.OutOfMemory, |
| 1468 | else => |e| return elf.base.comp.link_diags.fail("prelink failed: {t}", .{e}), |
| 1469 | }; |
| 1470 | } |
| 1471 | fn prelinkInner(elf: *Elf) !void { |
| 1472 | const gpa = elf.base.comp.gpa; |
| 1473 | try elf.symtab.ensureUnusedCapacity(gpa, 1); |
| 1474 | try elf.inputs.ensureUnusedCapacity(gpa, 1); |
| 1475 | const zcu_name = try std.fmt.allocPrint(gpa, "{s}_zcu", .{ |
| 1476 | std.fs.path.stem(elf.base.emit.sub_path), |
| 1477 | }); |
| 1478 | defer gpa.free(zcu_name); |
| 1479 | const si = try elf.initSymbolAssumeCapacity(.{ |
| 1480 | .name = zcu_name, |
| 1481 | .type = .FILE, |
| 1482 | .shndx = std.elf.SHN_ABS, |
| 1483 | }); |
| 1484 | elf.inputs.addOneAssumeCapacity().* = .{ |
| 1485 | .path = elf.base.emit, |
| 1486 | .si = si, |
| 1487 | }; |
| 1488 | } |
| 1489 | |
| 1164 | 1490 | pub fn getNavVAddr( |
| 1165 | 1491 | elf: *Elf, |
| 1166 | 1492 | pt: Zcu.PerThread, |
| ... | ... | @@ -1228,12 +1554,7 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { |
| 1228 | 1554 | const si = elf.addSymbolAssumeCapacity(); |
| 1229 | 1555 | elf.nodes.appendAssumeCapacity(.{ .section = si }); |
| 1230 | 1556 | si.get(elf).ni = ni; |
| 1231 | | try si.init(elf, .{ |
| 1232 | | .name = opts.name, |
| 1233 | | .size = opts.size, |
| 1234 | | .type = .SECTION, |
| 1235 | | .shndx = shndx, |
| 1236 | | }); |
| 1557 | try si.init(elf, .{ .size = opts.size, .type = .SECTION, .shndx = shndx }); |
| 1237 | 1558 | switch (elf.shdrSlice()) { |
| 1238 | 1559 | inline else => |shdr| { |
| 1239 | 1560 | const sh = &shdr[shndx]; |
| ... | ... | @@ -1256,15 +1577,12 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { |
| 1256 | 1577 | } |
| 1257 | 1578 | |
| 1258 | 1579 | fn renameSection(elf: *Elf, si: Symbol.Index, name: []const u8) !void { |
| 1259 | | const strtab_entry = try elf.string(.strtab, name); |
| 1260 | 1580 | const shstrtab_entry = try elf.string(.shstrtab, name); |
| 1261 | 1581 | switch (elf.shdrSlice()) { |
| 1262 | | inline else => |shdr, class| { |
| 1263 | | const sym = @field(elf.symPtr(si), @tagName(class)); |
| 1264 | | elf.targetStore(&sym.name, strtab_entry); |
| 1265 | | const sh = &shdr[elf.targetLoad(&sym.shndx)]; |
| 1266 | | elf.targetStore(&sh.name, shstrtab_entry); |
| 1267 | | }, |
| 1582 | inline else => |shdr, class| elf.targetStore( |
| 1583 | &shdr[elf.targetLoad(&@field(elf.symPtr(si), @tagName(class)).shndx)].name, |
| 1584 | shstrtab_entry, |
| 1585 | ), |
| 1268 | 1586 | } |
| 1269 | 1587 | } |
| 1270 | 1588 | |
| ... | ... | @@ -1323,11 +1641,6 @@ pub fn addReloc( |
| 1323 | 1641 | target.target_relocs = ri; |
| 1324 | 1642 | } |
| 1325 | 1643 | |
| 1326 | | pub fn prelink(elf: *Elf, prog_node: std.Progress.Node) void { |
| 1327 | | _ = elf; |
| 1328 | | _ = prog_node; |
| 1329 | | } |
| 1330 | | |
| 1331 | 1644 | pub fn updateNav(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !void { |
| 1332 | 1645 | elf.updateNavInner(pt, nav_index) catch |err| switch (err) { |
| 1333 | 1646 | error.OutOfMemory, |
| ... | ... | @@ -1430,7 +1743,7 @@ pub fn lowerUav( |
| 1430 | 1743 | .alignment = uav_align, |
| 1431 | 1744 | .src_loc = src_loc, |
| 1432 | 1745 | }; |
| 1433 | | elf.base.comp.link_const_prog_node.increaseEstimatedTotalItems(1); |
| 1746 | elf.const_prog_node.increaseEstimatedTotalItems(1); |
| 1434 | 1747 | } |
| 1435 | 1748 | } |
| 1436 | 1749 | return .{ .sym_index = @intFromEnum(si) }; |
| ... | ... | @@ -1534,7 +1847,7 @@ pub fn updateErrorData(elf: *Elf, pt: Zcu.PerThread) !void { |
| 1534 | 1847 | }) catch |err| switch (err) { |
| 1535 | 1848 | error.OutOfMemory => return error.OutOfMemory, |
| 1536 | 1849 | error.CodegenFail => return error.LinkFailure, |
| 1537 | | else => |e| return elf.base.comp.link_diags.fail("updateErrorData failed {t}", .{e}), |
| 1850 | else => |e| return elf.base.comp.link_diags.fail("updateErrorData failed: {t}", .{e}), |
| 1538 | 1851 | }; |
| 1539 | 1852 | } |
| 1540 | 1853 | |
| ... | ... | @@ -1553,20 +1866,16 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool { |
| 1553 | 1866 | const comp = elf.base.comp; |
| 1554 | 1867 | task: { |
| 1555 | 1868 | while (elf.pending_uavs.pop()) |pending_uav| { |
| 1556 | | const sub_prog_node = elf.idleProgNode( |
| 1557 | | tid, |
| 1558 | | comp.link_const_prog_node, |
| 1559 | | .{ .uav = pending_uav.key }, |
| 1560 | | ); |
| 1869 | const sub_prog_node = elf.idleProgNode(tid, elf.const_prog_node, .{ .uav = pending_uav.key }); |
| 1561 | 1870 | defer sub_prog_node.end(); |
| 1562 | 1871 | elf.flushUav( |
| 1563 | | .{ .zcu = elf.base.comp.zcu.?, .tid = tid }, |
| 1872 | .{ .zcu = comp.zcu.?, .tid = tid }, |
| 1564 | 1873 | pending_uav.key, |
| 1565 | 1874 | pending_uav.value.alignment, |
| 1566 | 1875 | pending_uav.value.src_loc, |
| 1567 | 1876 | ) catch |err| switch (err) { |
| 1568 | 1877 | error.OutOfMemory => return error.OutOfMemory, |
| 1569 | | else => |e| return elf.base.comp.link_diags.fail( |
| 1878 | else => |e| return comp.link_diags.fail( |
| 1570 | 1879 | "linker failed to lower constant: {t}", |
| 1571 | 1880 | .{e}, |
| 1572 | 1881 | ), |
| ... | ... | @@ -1575,7 +1884,7 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool { |
| 1575 | 1884 | } |
| 1576 | 1885 | var lazy_it = elf.lazy.iterator(); |
| 1577 | 1886 | while (lazy_it.next()) |lazy| if (lazy.value.pending_index < lazy.value.map.count()) { |
| 1578 | | const pt: Zcu.PerThread = .{ .zcu = elf.base.comp.zcu.?, .tid = tid }; |
| 1887 | const pt: Zcu.PerThread = .{ .zcu = comp.zcu.?, .tid = tid }; |
| 1579 | 1888 | const lmr: Node.LazyMapRef = .{ .kind = lazy.key, .index = lazy.value.pending_index }; |
| 1580 | 1889 | lazy.value.pending_index += 1; |
| 1581 | 1890 | const kind = switch (lmr.kind) { |
| ... | ... | @@ -1583,7 +1892,7 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool { |
| 1583 | 1892 | .const_data => "data", |
| 1584 | 1893 | }; |
| 1585 | 1894 | var name: [std.Progress.Node.max_name_len]u8 = undefined; |
| 1586 | | const sub_prog_node = comp.link_synth_prog_node.start( |
| 1895 | const sub_prog_node = elf.synth_prog_node.start( |
| 1587 | 1896 | std.fmt.bufPrint(&name, "lazy {s} for {f}", .{ |
| 1588 | 1897 | kind, |
| 1589 | 1898 | Type.fromInterned(lmr.lazySymbol(elf).ty).fmt(pt), |
| ... | ... | @@ -1593,13 +1902,27 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool { |
| 1593 | 1902 | defer sub_prog_node.end(); |
| 1594 | 1903 | elf.flushLazy(pt, lmr) catch |err| switch (err) { |
| 1595 | 1904 | error.OutOfMemory => return error.OutOfMemory, |
| 1596 | | else => |e| return elf.base.comp.link_diags.fail( |
| 1905 | else => |e| return comp.link_diags.fail( |
| 1597 | 1906 | "linker failed to lower lazy {s}: {t}", |
| 1598 | 1907 | .{ kind, e }, |
| 1599 | 1908 | ), |
| 1600 | 1909 | }; |
| 1601 | 1910 | break :task; |
| 1602 | 1911 | }; |
| 1912 | if (elf.input_section_pending_index < elf.input_sections.items.len) { |
| 1913 | const isi: Node.InputSectionIndex = @enumFromInt(elf.input_section_pending_index); |
| 1914 | elf.input_section_pending_index += 1; |
| 1915 | const sub_prog_node = elf.idleProgNode(tid, elf.input_prog_node, elf.getNode(isi.node(elf))); |
| 1916 | defer sub_prog_node.end(); |
| 1917 | elf.flushInputSection(isi) catch |err| switch (err) { |
| 1918 | else => |e| return comp.link_diags.fail("linker failed to read input section '{s}' from \"{f}\": {t}", .{ |
| 1919 | elf.sectionName(elf.getNode(isi.node(elf).parent(&elf.mf)).section), |
| 1920 | isi.input(elf).path(elf).fmtEscapeString(), |
| 1921 | e, |
| 1922 | }), |
| 1923 | }; |
| 1924 | break :task; |
| 1925 | } |
| 1603 | 1926 | while (elf.mf.updates.pop()) |ni| { |
| 1604 | 1927 | const clean_moved = ni.cleanMoved(&elf.mf); |
| 1605 | 1928 | const clean_resized = ni.cleanResized(&elf.mf); |
| ... | ... | @@ -1614,6 +1937,7 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool { |
| 1614 | 1937 | } |
| 1615 | 1938 | if (elf.pending_uavs.count() > 0) return true; |
| 1616 | 1939 | for (&elf.lazy.values) |lazy| if (lazy.map.count() > lazy.pending_index) return true; |
| 1940 | if (elf.input_sections.items.len > elf.input_section_pending_index) return true; |
| 1617 | 1941 | if (elf.mf.updates.items.len > 0) return true; |
| 1618 | 1942 | return false; |
| 1619 | 1943 | } |
| ... | ... | @@ -1628,6 +1952,10 @@ fn idleProgNode( |
| 1628 | 1952 | return prog_node.start(name: switch (node) { |
| 1629 | 1953 | else => |tag| @tagName(tag), |
| 1630 | 1954 | .section => |si| elf.sectionName(si), |
| 1955 | .input_section => |isi| std.fmt.bufPrint(&name, "{f} {s}", .{ |
| 1956 | isi.input(elf).path(elf), |
| 1957 | elf.sectionName(elf.getNode(isi.node(elf).parent(&elf.mf)).section), |
| 1958 | }) catch &name, |
| 1631 | 1959 | .nav => |nmi| { |
| 1632 | 1960 | const ip = &elf.base.comp.zcu.?.intern_pool; |
| 1633 | 1961 | break :name ip.getNav(nmi.navIndex(elf)).fqn.toSlice(ip); |
| ... | ... | @@ -1749,6 +2077,23 @@ fn flushLazy(elf: *Elf, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void { |
| 1749 | 2077 | si.applyLocationRelocs(elf); |
| 1750 | 2078 | } |
| 1751 | 2079 | |
| 2080 | fn flushInputSection(elf: *Elf, isi: Node.InputSectionIndex) !void { |
| 2081 | const offset, const size = isi.fileLocation(elf); |
| 2082 | if (size == 0) return; |
| 2083 | const comp = elf.base.comp; |
| 2084 | const gpa = comp.gpa; |
| 2085 | const io = comp.io; |
| 2086 | const path = isi.input(elf).path(elf); |
| 2087 | const file = try path.root_dir.handle.adaptToNewApi().openFile(io, path.sub_path, .{}); |
| 2088 | defer file.close(io); |
| 2089 | var fr = file.reader(io, &.{}); |
| 2090 | try fr.seekTo(offset); |
| 2091 | var nw: MappedFile.Node.Writer = undefined; |
| 2092 | isi.node(elf).writer(&elf.mf, gpa, &nw); |
| 2093 | defer nw.deinit(); |
| 2094 | if (try nw.interface.sendFileAll(&fr, .limited(@intCast(size))) != size) return error.EndOfStream; |
| 2095 | } |
| 2096 | |
| 1752 | 2097 | fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void { |
| 1753 | 2098 | switch (elf.getNode(ni)) { |
| 1754 | 2099 | .file => unreachable, |
| ... | ... | @@ -1786,7 +2131,28 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void { |
| 1786 | 2131 | } |
| 1787 | 2132 | }, |
| 1788 | 2133 | }, |
| 1789 | | inline .nav, .uav, .lazy_code, .lazy_const_data => |mi| mi.symbol(elf).flushMoved(elf), |
| 2134 | .input_section => |isi| { |
| 2135 | const addr = isi.addr(elf); |
| 2136 | const old_addr = addr.*; |
| 2137 | const new_addr = elf.computeNodeVAddr(ni); |
| 2138 | addr.* = new_addr; |
| 2139 | const ii = isi.input(elf); |
| 2140 | var si = ii.symbol(elf); |
| 2141 | const end_si = ii.nextSymbol(elf); |
| 2142 | while (cond: { |
| 2143 | si = si.next(); |
| 2144 | break :cond si != end_si; |
| 2145 | }) { |
| 2146 | if (si.get(elf).ni != ni) continue; |
| 2147 | si.flushMoved(elf, switch (elf.symPtr(si)) { |
| 2148 | inline else => |sym| elf.targetLoad(&sym.value), |
| 2149 | } - old_addr + new_addr); |
| 2150 | } |
| 2151 | }, |
| 2152 | inline .nav, .uav, .lazy_code, .lazy_const_data => |mi| mi.symbol(elf).flushMoved( |
| 2153 | elf, |
| 2154 | elf.computeNodeVAddr(ni), |
| 2155 | ), |
| 1790 | 2156 | } |
| 1791 | 2157 | try ni.childrenMoved(elf.base.comp.gpa, &elf.mf); |
| 1792 | 2158 | } |
| ... | ... | @@ -1860,6 +2226,7 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void { |
| 1860 | 2226 | } |
| 1861 | 2227 | }, |
| 1862 | 2228 | }, |
| 2229 | .input_section => {}, |
| 1863 | 2230 | .nav, .uav, .lazy_code, .lazy_const_data => {}, |
| 1864 | 2231 | } |
| 1865 | 2232 | } |
| ... | ... | @@ -1983,6 +2350,10 @@ pub fn printNode( |
| 1983 | 2350 | switch (node) { |
| 1984 | 2351 | else => {}, |
| 1985 | 2352 | .section => |si| try w.print("({s})", .{elf.sectionName(si)}), |
| 2353 | .input_section => |isi| try w.print("({f}, {s})", .{ |
| 2354 | isi.input(elf).path(elf), |
| 2355 | elf.sectionName(elf.getNode(isi.node(elf).parent(&elf.mf)).section), |
| 2356 | }), |
| 1986 | 2357 | .nav => |nmi| { |
| 1987 | 2358 | const zcu = elf.base.comp.zcu.?; |
| 1988 | 2359 | const ip = &zcu.intern_pool; |
| ... | ... | @@ -2027,25 +2398,28 @@ pub fn printNode( |
| 2027 | 2398 | leaf = false; |
| 2028 | 2399 | try elf.printNode(tid, w, child_ni, indent + 1); |
| 2029 | 2400 | } |
| 2030 | | if (leaf) { |
| 2031 | | const file_loc = ni.fileLocation(&elf.mf, false); |
| 2032 | | if (file_loc.size == 0) return; |
| 2033 | | var address = file_loc.offset; |
| 2034 | | const line_len = 0x10; |
| 2035 | | var line_it = std.mem.window( |
| 2036 | | u8, |
| 2037 | | elf.mf.contents[@intCast(file_loc.offset)..][0..@intCast(file_loc.size)], |
| 2038 | | line_len, |
| 2039 | | line_len, |
| 2040 | | ); |
| 2041 | | while (line_it.next()) |line_bytes| : (address += line_len) { |
| 2042 | | try w.splatByteAll(' ', indent + 1); |
| 2043 | | try w.print("{x:0>8} ", .{address}); |
| 2044 | | for (line_bytes) |byte| try w.print("{x:0>2} ", .{byte}); |
| 2045 | | try w.splatByteAll(' ', 3 * (line_len - line_bytes.len) + 1); |
| 2046 | | for (line_bytes) |byte| try w.writeByte(if (std.ascii.isPrint(byte)) byte else '.'); |
| 2047 | | try w.writeByte('\n'); |
| 2048 | | } |
| 2401 | if (!leaf) return; |
| 2402 | const file_loc = ni.fileLocation(&elf.mf, false); |
| 2403 | var address = file_loc.offset; |
| 2404 | if (file_loc.size == 0) { |
| 2405 | try w.splatByteAll(' ', indent + 1); |
| 2406 | try w.print("{x:0>8}\n", .{address}); |
| 2407 | return; |
| 2408 | } |
| 2409 | const line_len = 0x10; |
| 2410 | var line_it = std.mem.window( |
| 2411 | u8, |
| 2412 | elf.mf.contents[@intCast(file_loc.offset)..][0..@intCast(file_loc.size)], |
| 2413 | line_len, |
| 2414 | line_len, |
| 2415 | ); |
| 2416 | while (line_it.next()) |line_bytes| : (address += line_len) { |
| 2417 | try w.splatByteAll(' ', indent + 1); |
| 2418 | try w.print("{x:0>8} ", .{address}); |
| 2419 | for (line_bytes) |byte| try w.print("{x:0>2} ", .{byte}); |
| 2420 | try w.splatByteAll(' ', 3 * (line_len - line_bytes.len) + 1); |
| 2421 | for (line_bytes) |byte| try w.writeByte(if (std.ascii.isPrint(byte)) byte else '.'); |
| 2422 | try w.writeByte('\n'); |
| 2049 | 2423 | } |
| 2050 | 2424 | } |
| 2051 | 2425 | |