| ... | @@ -12,10 +12,8 @@ inputs: std.ArrayList(struct { | ... | @@ -12,10 +12,8 @@ inputs: std.ArrayList(struct { |
| 12 | }), | 12 | }), |
| 13 | input_sections: std.ArrayList(struct { | 13 | input_sections: std.ArrayList(struct { |
| 14 | ii: Node.InputIndex, | 14 | ii: Node.InputIndex, |
| 15 | ni: MappedFile.Node.Index, | 15 | si: Symbol.Index, |
| 16 | addr: u64, | 16 | file_location: MappedFile.Node.FileLocation, |
| 17 | offset: u64, | | |
| 18 | size: u64, | | |
| 19 | }), | 17 | }), |
| 20 | input_section_pending_index: u32, | 18 | input_section_pending_index: u32, |
| 21 | globals: std.AutoArrayHashMapUnmanaged(u32, Symbol.Index), | 19 | globals: std.AutoArrayHashMapUnmanaged(u32, Symbol.Index), |
| ... | @@ -59,7 +57,7 @@ pub const Node = union(enum) { | ... | @@ -59,7 +57,7 @@ pub const Node = union(enum) { |
| 59 | return elf.inputs.items[@intFromEnum(ii)].si; | 57 | return elf.inputs.items[@intFromEnum(ii)].si; |
| 60 | } | 58 | } |
| 61 | | 59 | |
| 62 | pub fn nextSymbol(ii: InputIndex, elf: *const Elf) Symbol.Index { | 60 | pub fn endSymbol(ii: InputIndex, elf: *const Elf) Symbol.Index { |
| 63 | const next_ii = @intFromEnum(ii) + 1; | 61 | const next_ii = @intFromEnum(ii) + 1; |
| 64 | return if (next_ii < elf.inputs.items.len) | 62 | return if (next_ii < elf.inputs.items.len) |
| 65 | @as(InputIndex, @enumFromInt(next_ii)).symbol(elf) | 63 | @as(InputIndex, @enumFromInt(next_ii)).symbol(elf) |
| ... | @@ -75,17 +73,12 @@ pub const Node = union(enum) { | ... | @@ -75,17 +73,12 @@ pub const Node = union(enum) { |
| 75 | return elf.input_sections.items[@intFromEnum(isi)].ii; | 73 | return elf.input_sections.items[@intFromEnum(isi)].ii; |
| 76 | } | 74 | } |
| 77 | | 75 | |
| 78 | pub fn node(isi: InputSectionIndex, elf: *const Elf) MappedFile.Node.Index { | 76 | pub fn symbol(isi: InputSectionIndex, elf: *const Elf) Symbol.Index { |
| 79 | return elf.input_sections.items[@intFromEnum(isi)].ni; | 77 | return elf.input_sections.items[@intFromEnum(isi)].si; |
| 80 | } | 78 | } |
| 81 | | 79 | |
| 82 | pub fn addr(isi: InputSectionIndex, elf: *Elf) *u64 { | 80 | pub fn fileLocation(isi: InputSectionIndex, elf: *const Elf) MappedFile.Node.FileLocation { |
| 83 | return &elf.input_sections.items[@intFromEnum(isi)].addr; | 81 | return elf.input_sections.items[@intFromEnum(isi)].file_location; |
| 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 | } | 82 | } |
| 90 | }; | 83 | }; |
| 91 | | 84 | |
| ... | @@ -302,9 +295,12 @@ pub const Symbol = struct { | ... | @@ -302,9 +295,12 @@ pub const Symbol = struct { |
| 302 | } | 295 | } |
| 303 | | 296 | |
| 304 | pub fn applyLocationRelocs(si: Symbol.Index, elf: *Elf) void { | 297 | pub fn applyLocationRelocs(si: Symbol.Index, elf: *Elf) void { |
| 305 | for (elf.relocs.items[@intFromEnum(si.get(elf).loc_relocs)..]) |*reloc| { | 298 | switch (si.get(elf).loc_relocs) { |
| 306 | if (reloc.loc != si) break; | 299 | .none => {}, |
| 307 | reloc.apply(elf); | 300 | else => |loc_relocs| for (elf.relocs.items[@intFromEnum(loc_relocs)..]) |*reloc| { |
| | 301 | if (reloc.loc != si) break; |
| | 302 | reloc.apply(elf); |
| | 303 | }, |
| 308 | } | 304 | } |
| 309 | } | 305 | } |
| 310 | | 306 | |
| ... | @@ -390,7 +386,7 @@ pub const Reloc = extern struct { | ... | @@ -390,7 +386,7 @@ pub const Reloc = extern struct { |
| 390 | target_value, | 386 | target_value, |
| 391 | target_endian, | 387 | target_endian, |
| 392 | ), | 388 | ), |
| 393 | .PC32 => std.mem.writeInt( | 389 | .PC32, .PLT32 => std.mem.writeInt( |
| 394 | i32, | 390 | i32, |
| 395 | loc_slice[0..4], | 391 | loc_slice[0..4], |
| 396 | @intCast(@as(i64, @bitCast(target_value -% loc_value))), | 392 | @intCast(@as(i64, @bitCast(target_value -% loc_value))), |
| ... | @@ -402,6 +398,12 @@ pub const Reloc = extern struct { | ... | @@ -402,6 +398,12 @@ pub const Reloc = extern struct { |
| 402 | @intCast(target_value), | 398 | @intCast(target_value), |
| 403 | target_endian, | 399 | target_endian, |
| 404 | ), | 400 | ), |
| | 401 | .@"32S" => std.mem.writeInt( |
| | 402 | i32, |
| | 403 | loc_slice[0..4], |
| | 404 | @intCast(@as(i64, @bitCast(target_value))), |
| | 405 | target_endian, |
| | 406 | ), |
| 405 | .TPOFF32 => { | 407 | .TPOFF32 => { |
| 406 | const phdr = @field(elf.phdrSlice(), @tagName(class)); | 408 | const phdr = @field(elf.phdrSlice(), @tagName(class)); |
| 407 | const ph = &phdr[elf.getNode(elf.known.tls).segment]; | 409 | const ph = &phdr[elf.getNode(elf.known.tls).segment]; |
| ... | @@ -632,12 +634,7 @@ fn initHeaders( | ... | @@ -632,12 +634,7 @@ fn initHeaders( |
| 632 | switch (class) { | 634 | switch (class) { |
| 633 | .NONE, _ => unreachable, | 635 | .NONE, _ => unreachable, |
| 634 | inline else => |ct_class| { | 636 | inline else => |ct_class| { |
| 635 | const ElfN = switch (ct_class) { | 637 | const ElfN = ct_class.ElfN(); |
| 636 | .NONE, _ => comptime unreachable, | | |
| 637 | .@"32" => std.elf.Elf32, | | |
| 638 | .@"64" => std.elf.Elf64, | | |
| 639 | }; | | |
| 640 | | | |
| 641 | assert(Node.Known.ehdr == try elf.mf.addOnlyChildNode(gpa, Node.Known.rodata, .{ | 638 | assert(Node.Known.ehdr == try elf.mf.addOnlyChildNode(gpa, Node.Known.rodata, .{ |
| 642 | .size = @sizeOf(ElfN.Ehdr), | 639 | .size = @sizeOf(ElfN.Ehdr), |
| 643 | .alignment = addr_align, | 640 | .alignment = addr_align, |
| ... | @@ -717,11 +714,7 @@ fn initHeaders( | ... | @@ -717,11 +714,7 @@ fn initHeaders( |
| 717 | switch (class) { | 714 | switch (class) { |
| 718 | .NONE, _ => unreachable, | 715 | .NONE, _ => unreachable, |
| 719 | inline else => |ct_class| { | 716 | inline else => |ct_class| { |
| 720 | const ElfN = switch (ct_class) { | 717 | const ElfN = ct_class.ElfN(); |
| 721 | .NONE, _ => comptime unreachable, | | |
| 722 | .@"32" => std.elf.Elf32, | | |
| 723 | .@"64" => std.elf.Elf64, | | |
| 724 | }; | | |
| 725 | const target_endian = elf.targetEndian(); | 718 | const target_endian = elf.targetEndian(); |
| 726 | | 719 | |
| 727 | const phdr: []ElfN.Phdr = @ptrCast(@alignCast(Node.Known.phdr.slice(&elf.mf))); | 720 | const phdr: []ElfN.Phdr = @ptrCast(@alignCast(Node.Known.phdr.slice(&elf.mf))); |
| ... | @@ -1293,23 +1286,32 @@ pub fn loadInput(elf: *Elf, input: link.Input) !void { | ... | @@ -1293,23 +1286,32 @@ pub fn loadInput(elf: *Elf, input: link.Input) !void { |
| 1293 | switch (elf.identClass()) { | 1286 | switch (elf.identClass()) { |
| 1294 | .NONE, _ => unreachable, | 1287 | .NONE, _ => unreachable, |
| 1295 | inline else => |class| { | 1288 | inline else => |class| { |
| 1296 | const ehdr = try r.peekStruct( | 1289 | const ElfN = class.ElfN(); |
| 1297 | @typeInfo(@FieldType(EhdrPtr, @tagName(class))).pointer.child, | 1290 | const ehdr = try r.peekStruct(ElfN.Ehdr, target_endian); |
| 1298 | target_endian, | | |
| 1299 | ); | | |
| 1300 | if (ehdr.type != .REL) | 1291 | if (ehdr.type != .REL) |
| 1301 | return diags.failParse(object.path, "unsupported object type", .{}); | 1292 | return diags.failParse(object.path, "unsupported object type", .{}); |
| 1302 | if (ehdr.machine != elf.ehdrField(.machine)) | 1293 | if (ehdr.machine != elf.ehdrField(.machine)) |
| 1303 | return diags.failParse(object.path, "wrong machine", .{}); | 1294 | return diags.failParse(object.path, "wrong machine", .{}); |
| 1304 | if (ehdr.shoff == 0 or ehdr.shnum <= 1) return; | 1295 | if (ehdr.shoff == 0 or ehdr.shnum <= 1) return; |
| 1305 | if (ehdr.shstrndx == std.elf.SHN_UNDEF or ehdr.shstrndx >= ehdr.shnum) | 1296 | if (ehdr.shentsize < @sizeOf(ElfN.Shdr)) |
| 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", .{}); | 1297 | return diags.failParse(object.path, "unsupported shentsize", .{}); |
| | 1298 | const sections = try gpa.alloc(struct { |
| | 1299 | shdr: ElfN.Shdr, |
| | 1300 | si: Symbol.Index, |
| | 1301 | }, ehdr.shnum); |
| | 1302 | defer gpa.free(sections); |
| | 1303 | try fr.seekTo(ehdr.shoff); |
| | 1304 | for (sections) |*section| { |
| | 1305 | section.* = .{ |
| | 1306 | .shdr = try r.peekStruct(ElfN.Shdr, target_endian), |
| | 1307 | .si = .null, |
| | 1308 | }; |
| | 1309 | try fr.seekBy(ehdr.shentsize); |
| | 1310 | } |
| 1310 | const shstrtab = shstrtab: { | 1311 | const shstrtab = shstrtab: { |
| 1311 | try fr.seekTo(ehdr.shoff + ehdr.shentsize * ehdr.shstrndx); | 1312 | if (ehdr.shstrndx == std.elf.SHN_UNDEF or ehdr.shstrndx >= ehdr.shnum) |
| 1312 | const shdr = try r.peekStruct(Shdr, target_endian); | 1313 | return diags.failParse(object.path, "missing section names", .{}); |
| | 1314 | const shdr = &sections[ehdr.shstrndx].shdr; |
| 1313 | if (shdr.type != std.elf.SHT_STRTAB) | 1315 | if (shdr.type != std.elf.SHT_STRTAB) |
| 1314 | return diags.failParse(object.path, "invalid shstrtab type", .{}); | 1316 | return diags.failParse(object.path, "invalid shstrtab type", .{}); |
| 1315 | const shstrtab = try gpa.alloc(u8, @intCast(shdr.size)); | 1317 | const shstrtab = try gpa.alloc(u8, @intCast(shdr.size)); |
| ... | @@ -1319,141 +1321,186 @@ pub fn loadInput(elf: *Elf, input: link.Input) !void { | ... | @@ -1319,141 +1321,186 @@ pub fn loadInput(elf: *Elf, input: link.Input) !void { |
| 1319 | break :shstrtab shstrtab; | 1321 | break :shstrtab shstrtab; |
| 1320 | }; | 1322 | }; |
| 1321 | defer gpa.free(shstrtab); | 1323 | defer gpa.free(shstrtab); |
| 1322 | const Sym = @typeInfo(@FieldType(SymPtr, @tagName(class))).pointer.child; | 1324 | try elf.nodes.ensureUnusedCapacity(gpa, ehdr.shnum - 1); |
| 1323 | try fr.seekTo(ehdr.shoff + ehdr.shentsize); | 1325 | try elf.symtab.ensureUnusedCapacity(gpa, ehdr.shnum - 1); |
| 1324 | var symtab_shdr: Shdr = .{ | 1326 | try elf.input_sections.ensureUnusedCapacity(gpa, ehdr.shnum - 1); |
| 1325 | .name = 0, | 1327 | for (sections[1..]) |*section| switch (section.shdr.type) { |
| 1326 | .type = 0, | 1328 | else => {}, |
| 1327 | .flags = .{ .shf = .{} }, | 1329 | std.elf.SHT_PROGBITS, std.elf.SHT_NOBITS => { |
| 1328 | .addr = 0, | 1330 | if (section.shdr.name >= shstrtab.len) continue; |
| 1329 | .offset = 0, | 1331 | const name = std.mem.sliceTo(shstrtab[section.shdr.name..], 0); |
| 1330 | .size = 0, | 1332 | const parent_si = namedSection(name) orelse continue; |
| 1331 | .link = 0, | 1333 | const ni = try elf.mf.addLastChildNode(gpa, parent_si.node(elf), .{ |
| 1332 | .info = 0, | 1334 | .size = section.shdr.size, |
| 1333 | .addralign = 0, | 1335 | .alignment = .fromByteUnits(std.math.ceilPowerOfTwoAssert( |
| 1334 | .entsize = 0, | 1336 | usize, |
| 1335 | }; | 1337 | @intCast(@max(section.shdr.addralign, 1)), |
| 1336 | const sections = try gpa.alloc(struct { | 1338 | )), |
| 1337 | shndx: u32, | 1339 | .moved = true, |
| 1338 | ni: MappedFile.Node.Index, | 1340 | }); |
| 1339 | }, ehdr.shnum); | 1341 | elf.nodes.appendAssumeCapacity(.{ |
| 1340 | defer gpa.free(sections); | 1342 | .input_section = @enumFromInt(elf.input_sections.items.len), |
| 1341 | @memset(sections, .{ .shndx = std.elf.SHN_UNDEF, .ni = .none }); | 1343 | }); |
| 1342 | for (sections[1..ehdr.shnum]) |*section| { | 1344 | section.si = try elf.initSymbolAssumeCapacity(.{ |
| 1343 | const shdr = try r.peekStruct(Shdr, target_endian); | 1345 | .type = .SECTION, |
| 1344 | try r.discardAll(ehdr.shentsize); | 1346 | .shndx = elf.targetLoad(&@field(elf.symPtr(parent_si), @tagName(class)).shndx), |
| 1345 | switch (shdr.type) { | 1347 | }); |
| 1346 | else => continue, | 1348 | section.si.get(elf).ni = ni; |
| 1347 | std.elf.SHT_PROGBITS => {}, | 1349 | elf.input_sections.addOneAssumeCapacity().* = .{ |
| 1348 | std.elf.SHT_SYMTAB => { | 1350 | .ii = ii, |
| 1349 | if (symtab_shdr.entsize > 0) | 1351 | .si = section.si, |
| 1350 | return diags.failParse(object.path, "too many symtabs", .{}); | 1352 | .file_location = .{ |
| 1351 | if (shdr.entsize < @sizeOf(Sym)) | 1353 | .offset = section.shdr.offset, |
| 1352 | return diags.failParse(object.path, "unsupported entsize", .{}); | 1354 | .size = section.shdr.size, |
| 1353 | symtab_shdr = shdr; | 1355 | }, |
| 1354 | continue; | 1356 | }; |
| 1355 | }, | 1357 | elf.synth_prog_node.increaseEstimatedTotalItems(1); |
| 1356 | std.elf.SHT_NOBITS => {}, | 1358 | }, |
| 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 | }; | 1359 | }; |
| 1396 | defer gpa.free(strtab); | 1360 | var symmap: std.ArrayList(Symbol.Index) = .empty; |
| 1397 | try elf.symtab.ensureUnusedCapacity(gpa, symtab_shdr.info); | 1361 | defer symmap.deinit(gpa); |
| 1398 | try elf.globals.ensureUnusedCapacity(gpa, symtab_shdr.info); | 1362 | for (sections[1..], 1..) |*symtab, symtab_shndx| switch (symtab.shdr.type) { |
| 1399 | try fr.seekTo(symtab_shdr.offset + symtab_shdr.entsize); | 1363 | else => {}, |
| 1400 | for (1..try std.math.divExact( | 1364 | std.elf.SHT_SYMTAB => { |
| 1401 | usize, | 1365 | if (symtab.shdr.entsize < @sizeOf(ElfN.Sym)) |
| 1402 | @intCast(symtab_shdr.size), | 1366 | return diags.failParse(object.path, "unsupported symtab entsize", .{}); |
| 1403 | @intCast(symtab_shdr.entsize), | 1367 | const strtab = strtab: { |
| 1404 | )) |_| { | 1368 | if (symtab.shdr.link == std.elf.SHN_UNDEF or symtab.shdr.link >= ehdr.shnum) |
| 1405 | const input_sym = try r.peekStruct(Sym, target_endian); | 1369 | return diags.failParse(object.path, "missing symbol names", .{}); |
| 1406 | try r.discardAll64(symtab_shdr.entsize); | 1370 | const shdr = &sections[symtab.shdr.link].shdr; |
| 1407 | switch (input_sym.info.type) { | 1371 | if (shdr.type != std.elf.SHT_STRTAB) |
| 1408 | else => continue, | 1372 | return diags.failParse(object.path, "invalid strtab type", .{}); |
| 1409 | .OBJECT, .FUNC => {}, | 1373 | const strtab = try gpa.alloc(u8, @intCast(shdr.size)); |
| 1410 | } | 1374 | errdefer gpa.free(strtab); |
| 1411 | if (input_sym.name >= strtab.len or input_sym.shndx >= sections.len) continue; | 1375 | try fr.seekTo(shdr.offset); |
| 1412 | const name = std.mem.sliceTo(strtab[input_sym.name..], 0); | 1376 | try r.readSliceAll(strtab); |
| 1413 | const si = try elf.initSymbolAssumeCapacity(.{ | 1377 | break :strtab strtab; |
| 1414 | .name = name, | 1378 | }; |
| 1415 | .value = input_sym.value, | 1379 | defer gpa.free(strtab); |
| 1416 | .size = input_sym.size, | 1380 | const symnum = try std.math.divExact( |
| 1417 | .type = input_sym.info.type, | 1381 | u32, |
| 1418 | .bind = input_sym.info.bind, | 1382 | @intCast(symtab.shdr.size), |
| 1419 | .visibility = input_sym.other.visibility, | 1383 | @intCast(symtab.shdr.entsize), |
| 1420 | .shndx = @intCast(sections[input_sym.shndx].shndx), | 1384 | ); |
| 1421 | }); | 1385 | symmap.clearRetainingCapacity(); |
| 1422 | { | 1386 | try symmap.resize(gpa, symnum); |
| 1423 | const sym = si.get(elf); | 1387 | try elf.symtab.ensureUnusedCapacity(gpa, symnum); |
| 1424 | sym.ni = sections[input_sym.shndx].ni; | 1388 | try elf.globals.ensureUnusedCapacity(gpa, symnum); |
| 1425 | assert(sym.loc_relocs == .none); | 1389 | try fr.seekTo(symtab.shdr.offset + symtab.shdr.entsize); |
| 1426 | sym.loc_relocs = @enumFromInt(elf.relocs.items.len); | 1390 | symmap.items[0] = .null; |
| 1427 | } | 1391 | for (symmap.items[1..]) |*si| { |
| 1428 | switch (input_sym.info.bind) { | 1392 | si.* = .null; |
| 1429 | else => {}, | 1393 | const input_sym = try r.peekStruct(ElfN.Sym, target_endian); |
| 1430 | .GLOBAL => { | 1394 | try fr.seekBy(@intCast(symtab.shdr.entsize)); |
| 1431 | const gop = elf.globals.getOrPutAssumeCapacity(elf.targetLoad( | 1395 | if (input_sym.name >= strtab.len or |
| 1432 | &@field(elf.symPtr(si), @tagName(class)).name, | 1396 | input_sym.shndx == std.elf.SHN_UNDEF or |
| 1433 | )); | 1397 | input_sym.shndx >= ehdr.shnum) continue; |
| 1434 | if (gop.found_existing) switch (elf.targetLoad( | 1398 | switch (input_sym.info.type) { |
| 1435 | switch (elf.symPtr(gop.value_ptr.*)) { | 1399 | else => continue, |
| 1436 | inline else => |sym| &sym.info, | 1400 | .SECTION => { |
| | 1401 | const section = &sections[input_sym.shndx]; |
| | 1402 | if (input_sym.value == section.shdr.addr) si.* = section.si; |
| | 1403 | continue; |
| | 1404 | }, |
| | 1405 | .OBJECT, .FUNC => {}, |
| | 1406 | } |
| | 1407 | const name = std.mem.sliceTo(strtab[input_sym.name..], 0); |
| | 1408 | const parent_si = sections[input_sym.shndx].si; |
| | 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 | }, |
| | 1442 | .WEAK => { |
| | 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.*; |
| 1437 | }, | 1447 | }, |
| 1438 | ).bind) { | 1448 | } |
| 1439 | else => unreachable, | 1449 | } |
| 1440 | .GLOBAL => return diags.failParse( | 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( |
| 1441 | object.path, | 1462 | object.path, |
| 1442 | "multiple definitions of '{s}'", | 1463 | "unsupported rel entsize", |
| 1443 | .{name}, | 1464 | .{}, |
| 1444 | ), | 1465 | ); |
| 1445 | .WEAK => {}, | 1466 | const loc_sec = &sections[rels.shdr.info]; |
| 1446 | }; | 1467 | if (loc_sec.si == .null) continue; |
| 1447 | gop.value_ptr.* = si; | 1468 | const relnum = try std.math.divExact( |
| 1448 | }, | 1469 | u32, |
| 1449 | .WEAK => { | 1470 | @intCast(rels.shdr.size), |
| 1450 | const gop = elf.globals.getOrPutAssumeCapacity(elf.targetLoad( | 1471 | @intCast(rels.shdr.entsize), |
| 1451 | &@field(elf.symPtr(si), @tagName(class)).name, | 1472 | ); |
| 1452 | )); | 1473 | try elf.relocs.ensureUnusedCapacity(gpa, relnum); |
| 1453 | if (!gop.found_existing) gop.value_ptr.* = si; | 1474 | try fr.seekTo(rels.shdr.offset); |
| 1454 | }, | 1475 | for (0..relnum) |_| { |
| 1455 | } | 1476 | const rel = try r.peekStruct(Rel, target_endian); |
| 1456 | } | 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 | }, |
| | 1503 | }; |
| 1457 | }, | 1504 | }, |
| 1458 | } | 1505 | } |
| 1459 | }, | 1506 | }, |
| ... | @@ -1512,11 +1559,10 @@ pub fn getVAddr(elf: *Elf, reloc_info: link.File.RelocInfo, target_si: Symbol.In | ... | @@ -1512,11 +1559,10 @@ pub fn getVAddr(elf: *Elf, reloc_info: link.File.RelocInfo, target_si: Symbol.In |
| 1512 | reloc_info.addend, | 1559 | reloc_info.addend, |
| 1513 | switch (elf.ehdrField(.machine)) { | 1560 | switch (elf.ehdrField(.machine)) { |
| 1514 | else => unreachable, | 1561 | else => unreachable, |
| 1515 | .X86_64 => .{ .X86_64 = switch (elf.identClass()) { | 1562 | .AARCH64 => .{ .AARCH64 = .ABS64 }, |
| 1516 | .NONE, _ => unreachable, | 1563 | .PPC64 => .{ .PPC64 = .ADDR64 }, |
| 1517 | .@"32" => .@"32", | 1564 | .RISCV => .{ .RISCV = .@"64" }, |
| 1518 | .@"64" => .@"64", | 1565 | .X86_64 => .{ .X86_64 = .@"64" }, |
| 1519 | } }, | | |
| 1520 | }, | 1566 | }, |
| 1521 | ); | 1567 | ); |
| 1522 | return switch (elf.symPtr(target_si)) { | 1568 | return switch (elf.symPtr(target_si)) { |
| ... | @@ -1912,11 +1958,11 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool { | ... | @@ -1912,11 +1958,11 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool { |
| 1912 | if (elf.input_section_pending_index < elf.input_sections.items.len) { | 1958 | if (elf.input_section_pending_index < elf.input_sections.items.len) { |
| 1913 | const isi: Node.InputSectionIndex = @enumFromInt(elf.input_section_pending_index); | 1959 | const isi: Node.InputSectionIndex = @enumFromInt(elf.input_section_pending_index); |
| 1914 | elf.input_section_pending_index += 1; | 1960 | elf.input_section_pending_index += 1; |
| 1915 | const sub_prog_node = elf.idleProgNode(tid, elf.input_prog_node, elf.getNode(isi.node(elf))); | 1961 | const sub_prog_node = elf.idleProgNode(tid, elf.input_prog_node, elf.getNode(isi.symbol(elf).node(elf))); |
| 1916 | defer sub_prog_node.end(); | 1962 | defer sub_prog_node.end(); |
| 1917 | elf.flushInputSection(isi) catch |err| switch (err) { | 1963 | 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}", .{ | 1964 | 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), | 1965 | elf.sectionName(elf.getNode(isi.symbol(elf).node(elf).parent(&elf.mf)).section), |
| 1920 | isi.input(elf).path(elf).fmtEscapeString(), | 1966 | isi.input(elf).path(elf).fmtEscapeString(), |
| 1921 | e, | 1967 | e, |
| 1922 | }), | 1968 | }), |
| ... | @@ -1954,7 +2000,7 @@ fn idleProgNode( | ... | @@ -1954,7 +2000,7 @@ fn idleProgNode( |
| 1954 | .section => |si| elf.sectionName(si), | 2000 | .section => |si| elf.sectionName(si), |
| 1955 | .input_section => |isi| std.fmt.bufPrint(&name, "{f} {s}", .{ | 2001 | .input_section => |isi| std.fmt.bufPrint(&name, "{f} {s}", .{ |
| 1956 | isi.input(elf).path(elf), | 2002 | isi.input(elf).path(elf), |
| 1957 | elf.sectionName(elf.getNode(isi.node(elf).parent(&elf.mf)).section), | 2003 | elf.sectionName(elf.getNode(isi.symbol(elf).node(elf).parent(&elf.mf)).section), |
| 1958 | }) catch &name, | 2004 | }) catch &name, |
| 1959 | .nav => |nmi| { | 2005 | .nav => |nmi| { |
| 1960 | const ip = &elf.base.comp.zcu.?.intern_pool; | 2006 | const ip = &elf.base.comp.zcu.?.intern_pool; |
| ... | @@ -2078,8 +2124,8 @@ fn flushLazy(elf: *Elf, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void { | ... | @@ -2078,8 +2124,8 @@ fn flushLazy(elf: *Elf, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void { |
| 2078 | } | 2124 | } |
| 2079 | | 2125 | |
| 2080 | fn flushInputSection(elf: *Elf, isi: Node.InputSectionIndex) !void { | 2126 | fn flushInputSection(elf: *Elf, isi: Node.InputSectionIndex) !void { |
| 2081 | const offset, const size = isi.fileLocation(elf); | 2127 | const file_loc = isi.fileLocation(elf); |
| 2082 | if (size == 0) return; | 2128 | if (file_loc.size == 0) return; |
| 2083 | const comp = elf.base.comp; | 2129 | const comp = elf.base.comp; |
| 2084 | const gpa = comp.gpa; | 2130 | const gpa = comp.gpa; |
| 2085 | const io = comp.io; | 2131 | const io = comp.io; |
| ... | @@ -2087,11 +2133,11 @@ fn flushInputSection(elf: *Elf, isi: Node.InputSectionIndex) !void { | ... | @@ -2087,11 +2133,11 @@ fn flushInputSection(elf: *Elf, isi: Node.InputSectionIndex) !void { |
| 2087 | const file = try path.root_dir.handle.adaptToNewApi().openFile(io, path.sub_path, .{}); | 2133 | const file = try path.root_dir.handle.adaptToNewApi().openFile(io, path.sub_path, .{}); |
| 2088 | defer file.close(io); | 2134 | defer file.close(io); |
| 2089 | var fr = file.reader(io, &.{}); | 2135 | var fr = file.reader(io, &.{}); |
| 2090 | try fr.seekTo(offset); | 2136 | try fr.seekTo(file_loc.offset); |
| 2091 | var nw: MappedFile.Node.Writer = undefined; | 2137 | var nw: MappedFile.Node.Writer = undefined; |
| 2092 | isi.node(elf).writer(&elf.mf, gpa, &nw); | 2138 | isi.symbol(elf).node(elf).writer(&elf.mf, gpa, &nw); |
| 2093 | defer nw.deinit(); | 2139 | defer nw.deinit(); |
| 2094 | if (try nw.interface.sendFileAll(&fr, .limited(@intCast(size))) != size) return error.EndOfStream; | 2140 | if (try nw.interface.sendFileAll(&fr, .limited(@intCast(file_loc.size))) != file_loc.size) return error.EndOfStream; |
| 2095 | } | 2141 | } |
| 2096 | | 2142 | |
| 2097 | fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void { | 2143 | fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void { |
| ... | @@ -2132,13 +2178,13 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void { | ... | @@ -2132,13 +2178,13 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void { |
| 2132 | }, | 2178 | }, |
| 2133 | }, | 2179 | }, |
| 2134 | .input_section => |isi| { | 2180 | .input_section => |isi| { |
| 2135 | const addr = isi.addr(elf); | 2181 | const old_addr = switch (elf.symPtr(isi.symbol(elf))) { |
| 2136 | const old_addr = addr.*; | 2182 | inline else => |sym| elf.targetLoad(&sym.value), |
| | 2183 | }; |
| 2137 | const new_addr = elf.computeNodeVAddr(ni); | 2184 | const new_addr = elf.computeNodeVAddr(ni); |
| 2138 | addr.* = new_addr; | | |
| 2139 | const ii = isi.input(elf); | 2185 | const ii = isi.input(elf); |
| 2140 | var si = ii.symbol(elf); | 2186 | var si = ii.symbol(elf); |
| 2141 | const end_si = ii.nextSymbol(elf); | 2187 | const end_si = ii.endSymbol(elf); |
| 2142 | while (cond: { | 2188 | while (cond: { |
| 2143 | si = si.next(); | 2189 | si = si.next(); |
| 2144 | break :cond si != end_si; | 2190 | break :cond si != end_si; |