| ... | @@ -8,12 +8,13 @@ shstrtab: StringTable, | ... | @@ -8,12 +8,13 @@ shstrtab: StringTable, |
| 8 | strtab: StringTable, | 8 | strtab: StringTable, |
| 9 | inputs: std.ArrayList(struct { | 9 | inputs: std.ArrayList(struct { |
| 10 | path: std.Build.Cache.Path, | 10 | path: std.Build.Cache.Path, |
| | 11 | member: ?[]const u8, |
| 11 | si: Symbol.Index, | 12 | si: Symbol.Index, |
| 12 | }), | 13 | }), |
| 13 | input_sections: std.ArrayList(struct { | 14 | input_sections: std.ArrayList(struct { |
| 14 | ii: Node.InputIndex, | 15 | ii: Node.InputIndex, |
| 15 | si: Symbol.Index, | | |
| 16 | file_location: MappedFile.Node.FileLocation, | 16 | file_location: MappedFile.Node.FileLocation, |
| | 17 | si: Symbol.Index, |
| 17 | }), | 18 | }), |
| 18 | input_section_pending_index: u32, | 19 | input_section_pending_index: u32, |
| 19 | globals: std.AutoArrayHashMapUnmanaged(u32, Symbol.Index), | 20 | globals: std.AutoArrayHashMapUnmanaged(u32, Symbol.Index), |
| ... | @@ -53,6 +54,10 @@ pub const Node = union(enum) { | ... | @@ -53,6 +54,10 @@ pub const Node = union(enum) { |
| 53 | return elf.inputs.items[@intFromEnum(ii)].path; | 54 | return elf.inputs.items[@intFromEnum(ii)].path; |
| 54 | } | 55 | } |
| 55 | | 56 | |
| | 57 | pub fn member(ii: InputIndex, elf: *const Elf) ?[]const u8 { |
| | 58 | return elf.inputs.items[@intFromEnum(ii)].member; |
| | 59 | } |
| | 60 | |
| 56 | pub fn symbol(ii: InputIndex, elf: *const Elf) Symbol.Index { | 61 | pub fn symbol(ii: InputIndex, elf: *const Elf) Symbol.Index { |
| 57 | return elf.inputs.items[@intFromEnum(ii)].si; | 62 | return elf.inputs.items[@intFromEnum(ii)].si; |
| 58 | } | 63 | } |
| ... | @@ -73,13 +78,13 @@ pub const Node = union(enum) { | ... | @@ -73,13 +78,13 @@ pub const Node = union(enum) { |
| 73 | return elf.input_sections.items[@intFromEnum(isi)].ii; | 78 | return elf.input_sections.items[@intFromEnum(isi)].ii; |
| 74 | } | 79 | } |
| 75 | | 80 | |
| 76 | pub fn symbol(isi: InputSectionIndex, elf: *const Elf) Symbol.Index { | | |
| 77 | return elf.input_sections.items[@intFromEnum(isi)].si; | | |
| 78 | } | | |
| 79 | | | |
| 80 | pub fn fileLocation(isi: InputSectionIndex, elf: *const Elf) MappedFile.Node.FileLocation { | 81 | pub fn fileLocation(isi: InputSectionIndex, elf: *const Elf) MappedFile.Node.FileLocation { |
| 81 | return elf.input_sections.items[@intFromEnum(isi)].file_location; | 82 | return elf.input_sections.items[@intFromEnum(isi)].file_location; |
| 82 | } | 83 | } |
| | 84 | |
| | 85 | pub fn symbol(isi: InputSectionIndex, elf: *const Elf) Symbol.Index { |
| | 86 | return elf.input_sections.items[@intFromEnum(isi)].si; |
| | 87 | } |
| 83 | }; | 88 | }; |
| 84 | | 89 | |
| 85 | pub const NavMapIndex = enum(u32) { | 90 | pub const NavMapIndex = enum(u32) { |
| ... | @@ -571,6 +576,7 @@ pub fn deinit(elf: *Elf) void { | ... | @@ -571,6 +576,7 @@ pub fn deinit(elf: *Elf) void { |
| 571 | elf.symtab.deinit(gpa); | 576 | elf.symtab.deinit(gpa); |
| 572 | elf.shstrtab.map.deinit(gpa); | 577 | elf.shstrtab.map.deinit(gpa); |
| 573 | elf.strtab.map.deinit(gpa); | 578 | elf.strtab.map.deinit(gpa); |
| | 579 | for (elf.inputs.items) |input| if (input.member) |m| gpa.free(m); |
| 574 | elf.inputs.deinit(gpa); | 580 | elf.inputs.deinit(gpa); |
| 575 | elf.input_sections.deinit(gpa); | 581 | elf.input_sections.deinit(gpa); |
| 576 | elf.globals.deinit(gpa); | 582 | elf.globals.deinit(gpa); |
| ... | @@ -1255,256 +1261,370 @@ pub fn lazySymbol(elf: *Elf, lazy: link.File.LazySymbol) !Symbol.Index { | ... | @@ -1255,256 +1261,370 @@ pub fn lazySymbol(elf: *Elf, lazy: link.File.LazySymbol) !Symbol.Index { |
| 1255 | return lazy_gop.value_ptr.*; | 1261 | return lazy_gop.value_ptr.*; |
| 1256 | } | 1262 | } |
| 1257 | | 1263 | |
| 1258 | pub fn loadInput(elf: *Elf, input: link.Input) !void { | 1264 | pub fn loadInput(elf: *Elf, input: link.Input) (std.fs.File.Reader.SizeError || |
| | 1265 | std.Io.File.Reader.Error || MappedFile.Error || error{ EndOfStream, LinkFailure })!void { |
| | 1266 | const io = elf.base.comp.io; |
| | 1267 | var buf: [4096]u8 = undefined; |
| | 1268 | switch (input) { |
| | 1269 | else => {}, |
| | 1270 | .object => |object| { |
| | 1271 | var fsr: FileSliceReader = .init(object.file.reader(io, &.{})); |
| | 1272 | fsr.reset(try fsr.file.getSize(), &buf); |
| | 1273 | elf.loadObject(object.path, null, &fsr) catch |err| switch (err) { |
| | 1274 | error.ReadFailed => return fsr.file.err.?, |
| | 1275 | else => |e| return e, |
| | 1276 | }; |
| | 1277 | }, |
| | 1278 | .archive => |archive| { |
| | 1279 | var fsr: FileSliceReader = .init(archive.file.reader(io, &buf)); |
| | 1280 | elf.loadArchive(archive.path, &fsr) catch |err| switch (err) { |
| | 1281 | error.ReadFailed => return fsr.file.err.?, |
| | 1282 | else => |e| return e, |
| | 1283 | }; |
| | 1284 | }, |
| | 1285 | } |
| | 1286 | } |
| | 1287 | const FileSliceReader = struct { |
| | 1288 | file: std.Io.File.Reader, |
| | 1289 | file_location: MappedFile.Node.FileLocation, |
| | 1290 | reader: std.Io.Reader.Limited, |
| | 1291 | |
| | 1292 | pub fn init(file: std.Io.File.Reader) FileSliceReader { |
| | 1293 | return .{ .file = file, .file_location = undefined, .reader = undefined }; |
| | 1294 | } |
| | 1295 | |
| | 1296 | pub fn reset(fsr: *FileSliceReader, size: u64, buffer: []u8) void { |
| | 1297 | fsr.file_location = .{ |
| | 1298 | .offset = fsr.file.logicalPos(), |
| | 1299 | .size = size, |
| | 1300 | }; |
| | 1301 | fsr.reader = .init(&fsr.file.interface, .limited(@intCast(size)), buffer); |
| | 1302 | } |
| | 1303 | |
| | 1304 | pub fn pos(fsr: *const FileSliceReader) u64 { |
| | 1305 | return fsr.file.logicalPos() - fsr.file_location.offset; |
| | 1306 | } |
| | 1307 | |
| | 1308 | pub fn logicalPos(fsr: *const FileSliceReader) u64 { |
| | 1309 | return fsr.pos() - fsr.reader.interface.bufferedLen(); |
| | 1310 | } |
| | 1311 | |
| | 1312 | pub fn seekTo(fsr: *FileSliceReader, offset: u64) std.Io.File.Reader.SeekError!void { |
| | 1313 | if (offset > fsr.file_location.size) return error.EndOfStream; |
| | 1314 | const logical_pos = fsr.logicalPos(); |
| | 1315 | if (offset < logical_pos or offset >= fsr.pos()) { |
| | 1316 | fsr.reader.interface.tossBuffered(); |
| | 1317 | try fsr.file.seekTo(fsr.file_location.offset + offset); |
| | 1318 | fsr.reader.remaining = .limited(@intCast(fsr.file_location.size - offset)); |
| | 1319 | } else fsr.reader.interface.toss(@intCast(offset - logical_pos)); |
| | 1320 | } |
| | 1321 | }; |
| | 1322 | fn loadArchive(elf: *Elf, path: std.Build.Cache.Path, fsr: *FileSliceReader) !void { |
| 1259 | const comp = elf.base.comp; | 1323 | const comp = elf.base.comp; |
| 1260 | const gpa = comp.gpa; | 1324 | const gpa = comp.gpa; |
| 1261 | const diags = &comp.link_diags; | 1325 | const diags = &comp.link_diags; |
| 1262 | switch (input) { | 1326 | const r = &fsr.file.interface; |
| 1263 | .object => |object| { | 1327 | |
| 1264 | const ii: Node.InputIndex = @enumFromInt(elf.inputs.items.len); | 1328 | log.debug("loadArchive({f})", .{path.fmtEscapeString()}); |
| 1265 | log.debug("loadInput(.{{ .object = {f} }}) = {d}", .{ object.path, ii }); | 1329 | if (!std.mem.eql(u8, try r.take(std.elf.ARMAG.len), std.elf.ARMAG)) |
| 1266 | { | 1330 | return diags.failParse(path, "bad magic", .{}); |
| 1267 | try elf.symtab.ensureUnusedCapacity(gpa, 1); | 1331 | var strtab: std.Io.Writer.Allocating = .init(gpa); |
| 1268 | try elf.inputs.ensureUnusedCapacity(gpa, 1); | 1332 | defer strtab.deinit(); |
| 1269 | const si = try elf.initSymbolAssumeCapacity(.{ | 1333 | while (r.takeStruct(std.elf.ar_hdr, native_endian)) |header| { |
| 1270 | .name = std.fs.path.stem(object.path.sub_path), | 1334 | if (!std.mem.eql(u8, &header.ar_fmag, std.elf.ARFMAG)) |
| 1271 | .type = .FILE, | 1335 | return diags.failParse(path, "bad file magic", .{}); |
| 1272 | .shndx = std.elf.SHN_ABS, | 1336 | const size = header.size() catch |
| 1273 | }); | 1337 | return diags.failParse(path, "bad member size", .{}); |
| 1274 | elf.inputs.addOneAssumeCapacity().* = .{ | 1338 | if (std.mem.eql(u8, &header.ar_name, std.elf.STRNAME)) { |
| 1275 | .path = object.path, | 1339 | strtab.clearRetainingCapacity(); |
| 1276 | .si = si, | 1340 | try strtab.ensureTotalCapacityPrecise(size); |
| | 1341 | r.streamExact(&strtab.writer, size) catch |err| switch (err) { |
| | 1342 | error.WriteFailed => return error.OutOfMemory, |
| | 1343 | else => |e| return e, |
| | 1344 | }; |
| | 1345 | continue; |
| | 1346 | } |
| | 1347 | load_object: { |
| | 1348 | const member = header.name() orelse member: { |
| | 1349 | const strtab_offset = header.nameOffset() catch |err| switch (err) { |
| | 1350 | error.Overflow => break :member error.Overflow, |
| | 1351 | error.InvalidCharacter => break :load_object, |
| | 1352 | } orelse break :load_object; |
| | 1353 | const strtab_written = strtab.written(); |
| | 1354 | if (strtab_offset > strtab_written.len) break :member error.Overflow; |
| | 1355 | const member = std.mem.sliceTo(strtab_written[strtab_offset..], '\n'); |
| | 1356 | break :member if (std.mem.endsWith(u8, member, "/")) |
| | 1357 | member[0 .. member.len - "/".len] |
| | 1358 | else |
| | 1359 | member; |
| | 1360 | } catch |err| switch (err) { |
| | 1361 | error.Overflow => return diags.failParse(path, "bad member name offset", .{}), |
| | 1362 | }; |
| | 1363 | if (!std.mem.endsWith(u8, member, ".o")) break :load_object; |
| | 1364 | var buf: [4096]u8 = undefined; |
| | 1365 | fsr.reset(size, &buf); |
| | 1366 | try elf.loadObject(path, member, fsr); |
| | 1367 | try fsr.seekTo(size); |
| | 1368 | continue; |
| | 1369 | } |
| | 1370 | try r.discardAll(size); |
| | 1371 | } else |err| switch (err) { |
| | 1372 | error.EndOfStream => if (!fsr.file.atEnd()) return error.EndOfStream, |
| | 1373 | else => |e| return e, |
| | 1374 | } |
| | 1375 | } |
| | 1376 | fn fmtMemberString(member: ?[]const u8) std.fmt.Alt(?[]const u8, memberStringEscape) { |
| | 1377 | return .{ .data = member }; |
| | 1378 | } |
| | 1379 | fn memberStringEscape(member: ?[]const u8, w: *std.Io.Writer) std.Io.Writer.Error!void { |
| | 1380 | try w.print("({f})", .{std.zig.fmtString(member orelse return)}); |
| | 1381 | } |
| | 1382 | fn loadObject(elf: *Elf, path: std.Build.Cache.Path, member: ?[]const u8, fsr: *FileSliceReader) !void { |
| | 1383 | const comp = elf.base.comp; |
| | 1384 | const gpa = comp.gpa; |
| | 1385 | const diags = &comp.link_diags; |
| | 1386 | const r = &fsr.reader.interface; |
| | 1387 | |
| | 1388 | const ii: Node.InputIndex = @enumFromInt(elf.inputs.items.len); |
| | 1389 | log.debug("loadObject({f}{f})", .{ path.fmtEscapeString(), fmtMemberString(member) }); |
| | 1390 | const ident = try r.peek(std.elf.EI.NIDENT); |
| | 1391 | if (!std.mem.eql(u8, ident, elf.mf.contents[0..std.elf.EI.NIDENT])) |
| | 1392 | return diags.failParse(path, "bad ident", .{}); |
| | 1393 | try elf.symtab.ensureUnusedCapacity(gpa, 1); |
| | 1394 | try elf.inputs.ensureUnusedCapacity(gpa, 1); |
| | 1395 | elf.inputs.addOneAssumeCapacity().* = .{ |
| | 1396 | .path = path, |
| | 1397 | .member = if (member) |m| try gpa.dupe(u8, m) else null, |
| | 1398 | .si = try elf.initSymbolAssumeCapacity(.{ |
| | 1399 | .name = std.fs.path.stem(member orelse path.sub_path), |
| | 1400 | .type = .FILE, |
| | 1401 | .shndx = std.elf.SHN_ABS, |
| | 1402 | }), |
| | 1403 | }; |
| | 1404 | const target_endian = elf.targetEndian(); |
| | 1405 | switch (elf.identClass()) { |
| | 1406 | .NONE, _ => unreachable, |
| | 1407 | inline else => |class| { |
| | 1408 | const ElfN = class.ElfN(); |
| | 1409 | const ehdr = try r.peekStruct(ElfN.Ehdr, target_endian); |
| | 1410 | if (ehdr.type != .REL) return diags.failParse(path, "unsupported object type", .{}); |
| | 1411 | if (ehdr.machine != elf.ehdrField(.machine)) |
| | 1412 | return diags.failParse(path, "bad machine", .{}); |
| | 1413 | if (ehdr.shoff == 0 or ehdr.shnum <= 1) return; |
| | 1414 | if (ehdr.shentsize < @sizeOf(ElfN.Shdr)) |
| | 1415 | return diags.failParse(path, "unsupported shentsize", .{}); |
| | 1416 | const sections = try gpa.alloc(struct { shdr: ElfN.Shdr, si: Symbol.Index }, ehdr.shnum); |
| | 1417 | defer gpa.free(sections); |
| | 1418 | try fsr.seekTo(ehdr.shoff); |
| | 1419 | for (sections) |*section| { |
| | 1420 | section.* = .{ |
| | 1421 | .shdr = try r.peekStruct(ElfN.Shdr, target_endian), |
| | 1422 | .si = .null, |
| 1277 | }; | 1423 | }; |
| | 1424 | try r.discardAll(ehdr.shentsize); |
| | 1425 | switch (section.shdr.type) { |
| | 1426 | std.elf.SHT_NULL, std.elf.SHT_NOBITS => {}, |
| | 1427 | else => if (section.shdr.offset + section.shdr.size > fsr.file_location.size) |
| | 1428 | return diags.failParse(path, "bad section offset/size", .{}), |
| | 1429 | } |
| 1278 | } | 1430 | } |
| 1279 | var buf: [4096]u8 = undefined; | 1431 | const shstrtab = shstrtab: { |
| 1280 | var fr = object.file.reader(comp.io, &buf); | 1432 | if (ehdr.shstrndx == std.elf.SHN_UNDEF or ehdr.shstrndx >= ehdr.shnum) |
| 1281 | const r = &fr.interface; | 1433 | return diags.failParse(path, "missing section names", .{}); |
| 1282 | const ident = try r.peek(std.elf.EI.NIDENT); | 1434 | const shdr = &sections[ehdr.shstrndx].shdr; |
| 1283 | if (!std.mem.eql(u8, elf.mf.contents[0..std.elf.EI.NIDENT], ident)) | 1435 | if (shdr.type != std.elf.SHT_STRTAB) |
| 1284 | return diags.failParse(object.path, "wrong ident", .{}); | 1436 | return diags.failParse(path, "invalid shstrtab type", .{}); |
| 1285 | const target_endian = elf.targetEndian(); | 1437 | const shstrtab = try gpa.alloc(u8, @intCast(shdr.size)); |
| 1286 | switch (elf.identClass()) { | 1438 | errdefer gpa.free(shstrtab); |
| 1287 | .NONE, _ => unreachable, | 1439 | try fsr.seekTo(shdr.offset); |
| 1288 | inline else => |class| { | 1440 | try r.readSliceAll(shstrtab); |
| 1289 | const ElfN = class.ElfN(); | 1441 | break :shstrtab shstrtab; |
| 1290 | const ehdr = try r.peekStruct(ElfN.Ehdr, target_endian); | 1442 | }; |
| 1291 | if (ehdr.type != .REL) | 1443 | defer gpa.free(shstrtab); |
| 1292 | return diags.failParse(object.path, "unsupported object type", .{}); | 1444 | try elf.nodes.ensureUnusedCapacity(gpa, ehdr.shnum - 1); |
| 1293 | if (ehdr.machine != elf.ehdrField(.machine)) | 1445 | try elf.symtab.ensureUnusedCapacity(gpa, ehdr.shnum - 1); |
| 1294 | return diags.failParse(object.path, "wrong machine", .{}); | 1446 | try elf.input_sections.ensureUnusedCapacity(gpa, ehdr.shnum - 1); |
| 1295 | if (ehdr.shoff == 0 or ehdr.shnum <= 1) return; | 1447 | for (sections[1..]) |*section| switch (section.shdr.type) { |
| 1296 | if (ehdr.shentsize < @sizeOf(ElfN.Shdr)) | 1448 | else => {}, |
| 1297 | return diags.failParse(object.path, "unsupported shentsize", .{}); | 1449 | std.elf.SHT_PROGBITS, std.elf.SHT_NOBITS => { |
| 1298 | const sections = try gpa.alloc(struct { | 1450 | if (section.shdr.name >= shstrtab.len) continue; |
| 1299 | shdr: ElfN.Shdr, | 1451 | const name = std.mem.sliceTo(shstrtab[section.shdr.name..], 0); |
| 1300 | si: Symbol.Index, | 1452 | const parent_si = namedSection(name) orelse continue; |
| 1301 | }, ehdr.shnum); | 1453 | const ni = try elf.mf.addLastChildNode(gpa, parent_si.node(elf), .{ |
| 1302 | defer gpa.free(sections); | 1454 | .size = section.shdr.size, |
| 1303 | try fr.seekTo(ehdr.shoff); | 1455 | .alignment = .fromByteUnits(std.math.ceilPowerOfTwoAssert( |
| 1304 | for (sections) |*section| { | 1456 | usize, |
| 1305 | section.* = .{ | 1457 | @intCast(@max(section.shdr.addralign, 1)), |
| 1306 | .shdr = try r.peekStruct(ElfN.Shdr, target_endian), | 1458 | )), |
| 1307 | .si = .null, | 1459 | .moved = true, |
| 1308 | }; | 1460 | }); |
| 1309 | try fr.seekBy(ehdr.shentsize); | 1461 | elf.nodes.appendAssumeCapacity(.{ |
| 1310 | } | 1462 | .input_section = @enumFromInt(elf.input_sections.items.len), |
| 1311 | const shstrtab = shstrtab: { | 1463 | }); |
| 1312 | if (ehdr.shstrndx == std.elf.SHN_UNDEF or ehdr.shstrndx >= ehdr.shnum) | 1464 | section.si = try elf.initSymbolAssumeCapacity(.{ |
| 1313 | return diags.failParse(object.path, "missing section names", .{}); | 1465 | .type = .SECTION, |
| 1314 | const shdr = &sections[ehdr.shstrndx].shdr; | 1466 | .shndx = elf.targetLoad(&@field(elf.symPtr(parent_si), @tagName(class)).shndx), |
| 1315 | if (shdr.type != std.elf.SHT_STRTAB) | 1467 | }); |
| 1316 | return diags.failParse(object.path, "invalid shstrtab type", .{}); | 1468 | section.si.get(elf).ni = ni; |
| 1317 | const shstrtab = try gpa.alloc(u8, @intCast(shdr.size)); | 1469 | elf.input_sections.addOneAssumeCapacity().* = .{ |
| 1318 | errdefer gpa.free(shstrtab); | 1470 | .ii = ii, |
| 1319 | try fr.seekTo(shdr.offset); | 1471 | .si = section.si, |
| 1320 | try r.readSliceAll(shstrtab); | 1472 | .file_location = .{ |
| 1321 | break :shstrtab shstrtab; | 1473 | .offset = fsr.file_location.offset + section.shdr.offset, |
| 1322 | }; | 1474 | .size = section.shdr.size, |
| 1323 | defer gpa.free(shstrtab); | | |
| 1324 | try elf.nodes.ensureUnusedCapacity(gpa, ehdr.shnum - 1); | | |
| 1325 | try elf.symtab.ensureUnusedCapacity(gpa, ehdr.shnum - 1); | | |
| 1326 | try elf.input_sections.ensureUnusedCapacity(gpa, ehdr.shnum - 1); | | |
| 1327 | for (sections[1..]) |*section| switch (section.shdr.type) { | | |
| 1328 | else => {}, | | |
| 1329 | std.elf.SHT_PROGBITS, std.elf.SHT_NOBITS => { | | |
| 1330 | if (section.shdr.name >= shstrtab.len) continue; | | |
| 1331 | const name = std.mem.sliceTo(shstrtab[section.shdr.name..], 0); | | |
| 1332 | const parent_si = namedSection(name) orelse continue; | | |
| 1333 | const ni = try elf.mf.addLastChildNode(gpa, parent_si.node(elf), .{ | | |
| 1334 | .size = section.shdr.size, | | |
| 1335 | .alignment = .fromByteUnits(std.math.ceilPowerOfTwoAssert( | | |
| 1336 | usize, | | |
| 1337 | @intCast(@max(section.shdr.addralign, 1)), | | |
| 1338 | )), | | |
| 1339 | .moved = true, | | |
| 1340 | }); | | |
| 1341 | elf.nodes.appendAssumeCapacity(.{ | | |
| 1342 | .input_section = @enumFromInt(elf.input_sections.items.len), | | |
| 1343 | }); | | |
| 1344 | section.si = try elf.initSymbolAssumeCapacity(.{ | | |
| 1345 | .type = .SECTION, | | |
| 1346 | .shndx = elf.targetLoad(&@field(elf.symPtr(parent_si), @tagName(class)).shndx), | | |
| 1347 | }); | | |
| 1348 | section.si.get(elf).ni = ni; | | |
| 1349 | elf.input_sections.addOneAssumeCapacity().* = .{ | | |
| 1350 | .ii = ii, | | |
| 1351 | .si = section.si, | | |
| 1352 | .file_location = .{ | | |
| 1353 | .offset = section.shdr.offset, | | |
| 1354 | .size = section.shdr.size, | | |
| 1355 | }, | | |
| 1356 | }; | | |
| 1357 | elf.synth_prog_node.increaseEstimatedTotalItems(1); | | |
| 1358 | }, | 1475 | }, |
| 1359 | }; | 1476 | }; |
| 1360 | var symmap: std.ArrayList(Symbol.Index) = .empty; | 1477 | elf.synth_prog_node.increaseEstimatedTotalItems(1); |
| 1361 | defer symmap.deinit(gpa); | 1478 | }, |
| 1362 | for (sections[1..], 1..) |*symtab, symtab_shndx| switch (symtab.shdr.type) { | 1479 | }; |
| | 1480 | var symmap: std.ArrayList(Symbol.Index) = .empty; |
| | 1481 | defer symmap.deinit(gpa); |
| | 1482 | for (sections[1..], 1..) |*symtab, symtab_shndx| switch (symtab.shdr.type) { |
| | 1483 | else => {}, |
| | 1484 | std.elf.SHT_SYMTAB => { |
| | 1485 | if (symtab.shdr.entsize < @sizeOf(ElfN.Sym)) |
| | 1486 | return diags.failParse(path, "unsupported symtab entsize", .{}); |
| | 1487 | const strtab = strtab: { |
| | 1488 | if (symtab.shdr.link == std.elf.SHN_UNDEF or symtab.shdr.link >= ehdr.shnum) |
| | 1489 | return diags.failParse(path, "missing symbol names", .{}); |
| | 1490 | const shdr = &sections[symtab.shdr.link].shdr; |
| | 1491 | if (shdr.type != std.elf.SHT_STRTAB) |
| | 1492 | return diags.failParse(path, "invalid strtab type", .{}); |
| | 1493 | const strtab = try gpa.alloc(u8, @intCast(shdr.size)); |
| | 1494 | errdefer gpa.free(strtab); |
| | 1495 | try fsr.seekTo(shdr.offset); |
| | 1496 | try r.readSliceAll(strtab); |
| | 1497 | break :strtab strtab; |
| | 1498 | }; |
| | 1499 | defer gpa.free(strtab); |
| | 1500 | const symnum = std.math.divExact( |
| | 1501 | u32, |
| | 1502 | @intCast(symtab.shdr.size), |
| | 1503 | @intCast(symtab.shdr.entsize), |
| | 1504 | ) catch return diags.failParse( |
| | 1505 | path, |
| | 1506 | "symtab section size (0x{x}) is not a multiple of entsize (0x{x})", |
| | 1507 | .{ symtab.shdr.size, symtab.shdr.entsize }, |
| | 1508 | ); |
| | 1509 | symmap.clearRetainingCapacity(); |
| | 1510 | try symmap.resize(gpa, symnum); |
| | 1511 | try elf.symtab.ensureUnusedCapacity(gpa, symnum); |
| | 1512 | try elf.globals.ensureUnusedCapacity(gpa, symnum); |
| | 1513 | try fsr.seekTo(symtab.shdr.offset + symtab.shdr.entsize); |
| | 1514 | symmap.items[0] = .null; |
| | 1515 | for (symmap.items[1..]) |*si| { |
| | 1516 | si.* = .null; |
| | 1517 | const input_sym = try r.peekStruct(ElfN.Sym, target_endian); |
| | 1518 | try r.discardAll64(symtab.shdr.entsize); |
| | 1519 | if (input_sym.name >= strtab.len or input_sym.shndx == std.elf.SHN_UNDEF or |
| | 1520 | input_sym.shndx >= ehdr.shnum) continue; |
| | 1521 | switch (input_sym.info.type) { |
| | 1522 | else => continue, |
| | 1523 | .SECTION => { |
| | 1524 | const section = &sections[input_sym.shndx]; |
| | 1525 | if (input_sym.value == section.shdr.addr) si.* = section.si; |
| | 1526 | continue; |
| | 1527 | }, |
| | 1528 | .OBJECT, .FUNC => {}, |
| | 1529 | } |
| | 1530 | const name = std.mem.sliceTo(strtab[input_sym.name..], 0); |
| | 1531 | const parent_si = sections[input_sym.shndx].si; |
| | 1532 | si.* = try elf.initSymbolAssumeCapacity(.{ |
| | 1533 | .name = name, |
| | 1534 | .value = input_sym.value, |
| | 1535 | .size = input_sym.size, |
| | 1536 | .type = input_sym.info.type, |
| | 1537 | .bind = input_sym.info.bind, |
| | 1538 | .visibility = input_sym.other.visibility, |
| | 1539 | .shndx = elf.targetLoad(switch (elf.symPtr(parent_si)) { |
| | 1540 | inline else => |parent_sym| &parent_sym.shndx, |
| | 1541 | }), |
| | 1542 | }); |
| | 1543 | si.get(elf).ni = parent_si.get(elf).ni; |
| | 1544 | switch (input_sym.info.bind) { |
| | 1545 | else => {}, |
| | 1546 | .GLOBAL => { |
| | 1547 | const gop = elf.globals.getOrPutAssumeCapacity(elf.targetLoad( |
| | 1548 | &@field(elf.symPtr(si.*), @tagName(class)).name, |
| | 1549 | )); |
| | 1550 | if (gop.found_existing) switch (elf.targetLoad( |
| | 1551 | switch (elf.symPtr(gop.value_ptr.*)) { |
| | 1552 | inline else => |sym| &sym.info, |
| | 1553 | }, |
| | 1554 | ).bind) { |
| | 1555 | else => unreachable, |
| | 1556 | .GLOBAL => return diags.failParse( |
| | 1557 | path, |
| | 1558 | "multiple definitions of '{s}'", |
| | 1559 | .{name}, |
| | 1560 | ), |
| | 1561 | .WEAK => {}, |
| | 1562 | }; |
| | 1563 | gop.value_ptr.* = si.*; |
| | 1564 | }, |
| | 1565 | .WEAK => { |
| | 1566 | const gop = elf.globals.getOrPutAssumeCapacity(elf.targetLoad( |
| | 1567 | &@field(elf.symPtr(si.*), @tagName(class)).name, |
| | 1568 | )); |
| | 1569 | if (!gop.found_existing) gop.value_ptr.* = si.*; |
| | 1570 | }, |
| | 1571 | } |
| | 1572 | } |
| | 1573 | for (sections[1..]) |*rels| switch (rels.shdr.type) { |
| 1363 | else => {}, | 1574 | else => {}, |
| 1364 | std.elf.SHT_SYMTAB => { | 1575 | inline std.elf.SHT_REL, std.elf.SHT_RELA => |sht| { |
| 1365 | if (symtab.shdr.entsize < @sizeOf(ElfN.Sym)) | 1576 | if (rels.shdr.link != symtab_shndx or rels.shdr.info == std.elf.SHN_UNDEF or |
| 1366 | return diags.failParse(object.path, "unsupported symtab entsize", .{}); | 1577 | rels.shdr.info >= ehdr.shnum) continue; |
| 1367 | const strtab = strtab: { | 1578 | const Rel = switch (sht) { |
| 1368 | if (symtab.shdr.link == std.elf.SHN_UNDEF or symtab.shdr.link >= ehdr.shnum) | 1579 | else => comptime unreachable, |
| 1369 | return diags.failParse(object.path, "missing symbol names", .{}); | 1580 | std.elf.SHT_REL => ElfN.Rel, |
| 1370 | const shdr = &sections[symtab.shdr.link].shdr; | 1581 | std.elf.SHT_RELA => ElfN.Rela, |
| 1371 | if (shdr.type != std.elf.SHT_STRTAB) | | |
| 1372 | return diags.failParse(object.path, "invalid strtab type", .{}); | | |
| 1373 | const strtab = try gpa.alloc(u8, @intCast(shdr.size)); | | |
| 1374 | errdefer gpa.free(strtab); | | |
| 1375 | try fr.seekTo(shdr.offset); | | |
| 1376 | try r.readSliceAll(strtab); | | |
| 1377 | break :strtab strtab; | | |
| 1378 | }; | 1582 | }; |
| 1379 | defer gpa.free(strtab); | 1583 | if (rels.shdr.entsize < @sizeOf(Rel)) |
| 1380 | const symnum = try std.math.divExact( | 1584 | return diags.failParse(path, "unsupported rel entsize", .{}); |
| | 1585 | const loc_sec = &sections[rels.shdr.info]; |
| | 1586 | if (loc_sec.si == .null) continue; |
| | 1587 | const relnum = std.math.divExact( |
| 1381 | u32, | 1588 | u32, |
| 1382 | @intCast(symtab.shdr.size), | 1589 | @intCast(rels.shdr.size), |
| 1383 | @intCast(symtab.shdr.entsize), | 1590 | @intCast(rels.shdr.entsize), |
| | 1591 | ) catch return diags.failParse( |
| | 1592 | path, |
| | 1593 | "relocation section size (0x{x}) is not a multiple of entsize (0x{x})", |
| | 1594 | .{ rels.shdr.size, rels.shdr.entsize }, |
| 1384 | ); | 1595 | ); |
| 1385 | symmap.clearRetainingCapacity(); | 1596 | try elf.relocs.ensureUnusedCapacity(gpa, relnum); |
| 1386 | try symmap.resize(gpa, symnum); | 1597 | try fsr.seekTo(rels.shdr.offset); |
| 1387 | try elf.symtab.ensureUnusedCapacity(gpa, symnum); | 1598 | for (0..relnum) |_| { |
| 1388 | try elf.globals.ensureUnusedCapacity(gpa, symnum); | 1599 | const rel = try r.peekStruct(Rel, target_endian); |
| 1389 | try fr.seekTo(symtab.shdr.offset + symtab.shdr.entsize); | 1600 | try r.discardAll64(rels.shdr.entsize); |
| 1390 | symmap.items[0] = .null; | 1601 | if (rel.info.sym >= symnum) continue; |
| 1391 | for (symmap.items[1..]) |*si| { | 1602 | const target_si = symmap.items[rel.info.sym]; |
| 1392 | si.* = .null; | 1603 | if (target_si == .null) continue; |
| 1393 | const input_sym = try r.peekStruct(ElfN.Sym, target_endian); | 1604 | elf.addRelocAssumeCapacity( |
| 1394 | try fr.seekBy(@intCast(symtab.shdr.entsize)); | 1605 | loc_sec.si, |
| 1395 | if (input_sym.name >= strtab.len or | 1606 | rel.offset - loc_sec.shdr.addr, |
| 1396 | input_sym.shndx == std.elf.SHN_UNDEF or | 1607 | target_si, |
| 1397 | input_sym.shndx >= ehdr.shnum) continue; | 1608 | rel.addend, |
| 1398 | switch (input_sym.info.type) { | 1609 | switch (elf.ehdrField(.machine)) { |
| 1399 | else => continue, | 1610 | else => unreachable, |
| 1400 | .SECTION => { | 1611 | inline .AARCH64, |
| 1401 | const section = &sections[input_sym.shndx]; | 1612 | .PPC64, |
| 1402 | if (input_sym.value == section.shdr.addr) si.* = section.si; | 1613 | .RISCV, |
| 1403 | continue; | 1614 | .X86_64, |
| 1404 | }, | 1615 | => |machine| @unionInit( |
| 1405 | .OBJECT, .FUNC => {}, | 1616 | Reloc.Type, |
| 1406 | } | 1617 | @tagName(machine), |
| 1407 | const name = std.mem.sliceTo(strtab[input_sym.name..], 0); | 1618 | @enumFromInt(rel.info.type), |
| 1408 | const parent_si = sections[input_sym.shndx].si; | 1619 | ), |
| 1409 | si.* = try elf.initSymbolAssumeCapacity(.{ | | |
| 1410 | .name = name, | | |
| 1411 | .value = input_sym.value, | | |
| 1412 | .size = input_sym.size, | | |
| 1413 | .type = input_sym.info.type, | | |
| 1414 | .bind = input_sym.info.bind, | | |
| 1415 | .visibility = input_sym.other.visibility, | | |
| 1416 | .shndx = elf.targetLoad(switch (elf.symPtr(parent_si)) { | | |
| 1417 | inline else => |parent_sym| &parent_sym.shndx, | | |
| 1418 | }), | | |
| 1419 | }); | | |
| 1420 | si.get(elf).ni = parent_si.get(elf).ni; | | |
| 1421 | switch (input_sym.info.bind) { | | |
| 1422 | else => {}, | | |
| 1423 | .GLOBAL => { | | |
| 1424 | const gop = elf.globals.getOrPutAssumeCapacity(elf.targetLoad( | | |
| 1425 | &@field(elf.symPtr(si.*), @tagName(class)).name, | | |
| 1426 | )); | | |
| 1427 | if (gop.found_existing) switch (elf.targetLoad( | | |
| 1428 | switch (elf.symPtr(gop.value_ptr.*)) { | | |
| 1429 | inline else => |sym| &sym.info, | | |
| 1430 | }, | | |
| 1431 | ).bind) { | | |
| 1432 | else => unreachable, | | |
| 1433 | .GLOBAL => return diags.failParse( | | |
| 1434 | object.path, | | |
| 1435 | "multiple definitions of '{s}'", | | |
| 1436 | .{name}, | | |
| 1437 | ), | | |
| 1438 | .WEAK => {}, | | |
| 1439 | }; | | |
| 1440 | gop.value_ptr.* = si.*; | | |
| 1441 | }, | 1620 | }, |
| 1442 | .WEAK => { | 1621 | ); |
| 1443 | const gop = elf.globals.getOrPutAssumeCapacity(elf.targetLoad( | | |
| 1444 | &@field(elf.symPtr(si.*), @tagName(class)).name, | | |
| 1445 | )); | | |
| 1446 | if (!gop.found_existing) gop.value_ptr.* = si.*; | | |
| 1447 | }, | | |
| 1448 | } | | |
| 1449 | } | 1622 | } |
| 1450 | for (sections[1..]) |*rels| switch (rels.shdr.type) { | | |
| 1451 | else => {}, | | |
| 1452 | inline std.elf.SHT_REL, std.elf.SHT_RELA => |sht| { | | |
| 1453 | if (rels.shdr.link != symtab_shndx or | | |
| 1454 | rels.shdr.info == std.elf.SHN_UNDEF or | | |
| 1455 | rels.shdr.info >= ehdr.shnum) continue; | | |
| 1456 | const Rel = switch (sht) { | | |
| 1457 | else => comptime unreachable, | | |
| 1458 | std.elf.SHT_REL => ElfN.Rel, | | |
| 1459 | std.elf.SHT_RELA => ElfN.Rela, | | |
| 1460 | }; | | |
| 1461 | if (rels.shdr.entsize < @sizeOf(Rel)) return diags.failParse( | | |
| 1462 | object.path, | | |
| 1463 | "unsupported rel entsize", | | |
| 1464 | .{}, | | |
| 1465 | ); | | |
| 1466 | const loc_sec = &sections[rels.shdr.info]; | | |
| 1467 | if (loc_sec.si == .null) continue; | | |
| 1468 | const relnum = try std.math.divExact( | | |
| 1469 | u32, | | |
| 1470 | @intCast(rels.shdr.size), | | |
| 1471 | @intCast(rels.shdr.entsize), | | |
| 1472 | ); | | |
| 1473 | try elf.relocs.ensureUnusedCapacity(gpa, relnum); | | |
| 1474 | try fr.seekTo(rels.shdr.offset); | | |
| 1475 | for (0..relnum) |_| { | | |
| 1476 | const rel = try r.peekStruct(Rel, target_endian); | | |
| 1477 | try fr.seekBy(@intCast(rels.shdr.entsize)); | | |
| 1478 | if (rel.info.sym >= symnum) continue; | | |
| 1479 | const target_si = symmap.items[rel.info.sym]; | | |
| 1480 | if (target_si == .null) continue; | | |
| 1481 | elf.addReloc( | | |
| 1482 | loc_sec.si, | | |
| 1483 | rel.offset - loc_sec.shdr.addr, | | |
| 1484 | target_si, | | |
| 1485 | rel.addend, | | |
| 1486 | switch (elf.ehdrField(.machine)) { | | |
| 1487 | else => unreachable, | | |
| 1488 | inline .AARCH64, | | |
| 1489 | .PPC64, | | |
| 1490 | .RISCV, | | |
| 1491 | .X86_64, | | |
| 1492 | => |machine| @unionInit( | | |
| 1493 | Reloc.Type, | | |
| 1494 | @tagName(machine), | | |
| 1495 | @enumFromInt(rel.info.type), | | |
| 1496 | ), | | |
| 1497 | }, | | |
| 1498 | ) catch unreachable; | | |
| 1499 | } | | |
| 1500 | }, | | |
| 1501 | }; | | |
| 1502 | }, | 1623 | }, |
| 1503 | }; | 1624 | }; |
| 1504 | }, | 1625 | }, |
| 1505 | } | 1626 | }; |
| 1506 | }, | 1627 | }, |
| 1507 | else => {}, | | |
| 1508 | } | 1628 | } |
| 1509 | } | 1629 | } |
| 1510 | | 1630 | |
| ... | @@ -1530,6 +1650,7 @@ fn prelinkInner(elf: *Elf) !void { | ... | @@ -1530,6 +1650,7 @@ fn prelinkInner(elf: *Elf) !void { |
| 1530 | }); | 1650 | }); |
| 1531 | elf.inputs.addOneAssumeCapacity().* = .{ | 1651 | elf.inputs.addOneAssumeCapacity().* = .{ |
| 1532 | .path = elf.base.emit, | 1652 | .path = elf.base.emit, |
| | 1653 | .member = null, |
| 1533 | .si = si, | 1654 | .si = si, |
| 1534 | }; | 1655 | }; |
| 1535 | } | 1656 | } |
| ... | @@ -1667,10 +1788,20 @@ pub fn addReloc( | ... | @@ -1667,10 +1788,20 @@ pub fn addReloc( |
| 1667 | addend: i64, | 1788 | addend: i64, |
| 1668 | @"type": Reloc.Type, | 1789 | @"type": Reloc.Type, |
| 1669 | ) !void { | 1790 | ) !void { |
| 1670 | const gpa = elf.base.comp.gpa; | 1791 | try elf.relocs.ensureUnusedCapacity(elf.base.comp.gpa, 1); |
| | 1792 | elf.addRelocAssumeCapacity(loc_si, offset, target_si, addend, @"type"); |
| | 1793 | } |
| | 1794 | pub fn addRelocAssumeCapacity( |
| | 1795 | elf: *Elf, |
| | 1796 | loc_si: Symbol.Index, |
| | 1797 | offset: u64, |
| | 1798 | target_si: Symbol.Index, |
| | 1799 | addend: i64, |
| | 1800 | @"type": Reloc.Type, |
| | 1801 | ) void { |
| 1671 | const target = target_si.get(elf); | 1802 | const target = target_si.get(elf); |
| 1672 | const ri: Reloc.Index = @enumFromInt(elf.relocs.items.len); | 1803 | const ri: Reloc.Index = @enumFromInt(elf.relocs.items.len); |
| 1673 | (try elf.relocs.addOne(gpa)).* = .{ | 1804 | elf.relocs.addOneAssumeCapacity().* = .{ |
| 1674 | .type = @"type", | 1805 | .type = @"type", |
| 1675 | .prev = .none, | 1806 | .prev = .none, |
| 1676 | .next = target.target_relocs, | 1807 | .next = target.target_relocs, |
| ... | @@ -1961,11 +2092,20 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool { | ... | @@ -1961,11 +2092,20 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool { |
| 1961 | const sub_prog_node = elf.idleProgNode(tid, elf.input_prog_node, elf.getNode(isi.symbol(elf).node(elf))); | 2092 | const sub_prog_node = elf.idleProgNode(tid, elf.input_prog_node, elf.getNode(isi.symbol(elf).node(elf))); |
| 1962 | defer sub_prog_node.end(); | 2093 | defer sub_prog_node.end(); |
| 1963 | elf.flushInputSection(isi) catch |err| switch (err) { | 2094 | elf.flushInputSection(isi) catch |err| switch (err) { |
| 1964 | else => |e| return comp.link_diags.fail("linker failed to read input section '{s}' from \"{f}\": {t}", .{ | 2095 | else => |e| { |
| 1965 | elf.sectionName(elf.getNode(isi.symbol(elf).node(elf).parent(&elf.mf)).section), | 2096 | const ii = isi.input(elf); |
| 1966 | isi.input(elf).path(elf).fmtEscapeString(), | 2097 | return comp.link_diags.fail( |
| 1967 | e, | 2098 | "linker failed to read input section '{s}' from \"{f}{f}\": {t}", |
| 1968 | }), | 2099 | .{ |
| | 2100 | elf.sectionName( |
| | 2101 | elf.getNode(isi.symbol(elf).node(elf).parent(&elf.mf)).section, |
| | 2102 | ), |
| | 2103 | ii.path(elf).fmtEscapeString(), |
| | 2104 | fmtMemberString(ii.member(elf)), |
| | 2105 | e, |
| | 2106 | }, |
| | 2107 | ); |
| | 2108 | }, |
| 1969 | }; | 2109 | }; |
| 1970 | break :task; | 2110 | break :task; |
| 1971 | } | 2111 | } |
| ... | @@ -1998,10 +2138,14 @@ fn idleProgNode( | ... | @@ -1998,10 +2138,14 @@ fn idleProgNode( |
| 1998 | return prog_node.start(name: switch (node) { | 2138 | return prog_node.start(name: switch (node) { |
| 1999 | else => |tag| @tagName(tag), | 2139 | else => |tag| @tagName(tag), |
| 2000 | .section => |si| elf.sectionName(si), | 2140 | .section => |si| elf.sectionName(si), |
| 2001 | .input_section => |isi| std.fmt.bufPrint(&name, "{f} {s}", .{ | 2141 | .input_section => |isi| { |
| 2002 | isi.input(elf).path(elf), | 2142 | const ii = isi.input(elf); |
| 2003 | elf.sectionName(elf.getNode(isi.symbol(elf).node(elf).parent(&elf.mf)).section), | 2143 | break :name std.fmt.bufPrint(&name, "{f}{f} {s}", .{ |
| 2004 | }) catch &name, | 2144 | ii.path(elf).fmtEscapeString(), |
| | 2145 | fmtMemberString(ii.member(elf)), |
| | 2146 | elf.sectionName(elf.getNode(isi.symbol(elf).node(elf).parent(&elf.mf)).section), |
| | 2147 | }) catch &name; |
| | 2148 | }, |
| 2005 | .nav => |nmi| { | 2149 | .nav => |nmi| { |
| 2006 | const ip = &elf.base.comp.zcu.?.intern_pool; | 2150 | const ip = &elf.base.comp.zcu.?.intern_pool; |
| 2007 | break :name ip.getNav(nmi.navIndex(elf)).fqn.toSlice(ip); | 2151 | break :name ip.getNav(nmi.navIndex(elf)).fqn.toSlice(ip); |
| ... | @@ -2128,16 +2272,17 @@ fn flushInputSection(elf: *Elf, isi: Node.InputSectionIndex) !void { | ... | @@ -2128,16 +2272,17 @@ fn flushInputSection(elf: *Elf, isi: Node.InputSectionIndex) !void { |
| 2128 | if (file_loc.size == 0) return; | 2272 | if (file_loc.size == 0) return; |
| 2129 | const comp = elf.base.comp; | 2273 | const comp = elf.base.comp; |
| 2130 | const gpa = comp.gpa; | 2274 | const gpa = comp.gpa; |
| 2131 | const io = comp.io; | 2275 | const ii = isi.input(elf); |
| 2132 | const path = isi.input(elf).path(elf); | 2276 | const path = ii.path(elf); |
| 2133 | const file = try path.root_dir.handle.adaptToNewApi().openFile(io, path.sub_path, .{}); | 2277 | const file = try path.root_dir.handle.adaptToNewApi().openFile(comp.io, path.sub_path, .{}); |
| 2134 | defer file.close(io); | 2278 | defer file.close(comp.io); |
| 2135 | var fr = file.reader(io, &.{}); | 2279 | var fr = file.reader(comp.io, &.{}); |
| 2136 | try fr.seekTo(file_loc.offset); | 2280 | try fr.seekTo(file_loc.offset); |
| 2137 | var nw: MappedFile.Node.Writer = undefined; | 2281 | var nw: MappedFile.Node.Writer = undefined; |
| 2138 | isi.symbol(elf).node(elf).writer(&elf.mf, gpa, &nw); | 2282 | isi.symbol(elf).node(elf).writer(&elf.mf, gpa, &nw); |
| 2139 | defer nw.deinit(); | 2283 | defer nw.deinit(); |
| 2140 | if (try nw.interface.sendFileAll(&fr, .limited(@intCast(file_loc.size))) != file_loc.size) return error.EndOfStream; | 2284 | if (try nw.interface.sendFileAll(&fr, .limited(@intCast(file_loc.size))) != file_loc.size) |
| | 2285 | return error.EndOfStream; |
| 2141 | } | 2286 | } |
| 2142 | | 2287 | |
| 2143 | fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void { | 2288 | fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void { |
| ... | @@ -2396,10 +2541,14 @@ pub fn printNode( | ... | @@ -2396,10 +2541,14 @@ pub fn printNode( |
| 2396 | switch (node) { | 2541 | switch (node) { |
| 2397 | else => {}, | 2542 | else => {}, |
| 2398 | .section => |si| try w.print("({s})", .{elf.sectionName(si)}), | 2543 | .section => |si| try w.print("({s})", .{elf.sectionName(si)}), |
| 2399 | .input_section => |isi| try w.print("({f}, {s})", .{ | 2544 | .input_section => |isi| { |
| 2400 | isi.input(elf).path(elf), | 2545 | const ii = isi.input(elf); |
| 2401 | elf.sectionName(elf.getNode(isi.node(elf).parent(&elf.mf)).section), | 2546 | try w.print("({f}{f}, {s})", .{ |
| 2402 | }), | 2547 | ii.path(elf).fmtEscapeString(), |
| | 2548 | fmtMemberString(ii.member(elf)), |
| | 2549 | elf.sectionName(elf.getNode(isi.symbol(elf).node(elf).parent(&elf.mf)).section), |
| | 2550 | }); |
| | 2551 | }, |
| 2403 | .nav => |nmi| { | 2552 | .nav => |nmi| { |
| 2404 | const zcu = elf.base.comp.zcu.?; | 2553 | const zcu = elf.base.comp.zcu.?; |
| 2405 | const ip = &zcu.intern_pool; | 2554 | const ip = &zcu.intern_pool; |