authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2025-10-29 18:01:10-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2025-10-29 18:06:17-04:00
log7542c3260f93e92fd8da7e5329bc80fd601964e9
tree1df5785b192e3098ca2823fc068c55757d2a7f78
parent6f0476e41d2f9b040a9883b288171c6a50c29ed5

Elf2: load relocations from input objects


5 files changed, 289 insertions(+), 199 deletions(-)

lib/std/elf.zig+46
......@@ -943,11 +943,30 @@ pub const Elf32 = struct {
943943 unused: u5 = 0,
944944 };
945945 };
946 pub const Rel = extern struct {
947 offset: Elf32.Addr,
948 info: Info,
949 addend: u0 = 0,
950
951 pub const Info = packed struct(u32) {
952 type: u8,
953 sym: u24,
954 };
955 };
956 pub const Rela = extern struct {
957 offset: Elf32.Addr,
958 info: Info,
959 addend: i32,
960
961 pub const Info = Elf32.Rel.Info;
962 };
946963 comptime {
947964 assert(@sizeOf(Elf32.Ehdr) == 52);
948965 assert(@sizeOf(Elf32.Phdr) == 32);
949966 assert(@sizeOf(Elf32.Shdr) == 40);
950967 assert(@sizeOf(Elf32.Sym) == 16);
968 assert(@sizeOf(Elf32.Rel) == 8);
969 assert(@sizeOf(Elf32.Rela) == 12);
951970 }
952971};
953972pub const Elf64 = struct {
......@@ -1008,11 +1027,30 @@ pub const Elf64 = struct {
10081027 pub const Info = Elf32.Sym.Info;
10091028 pub const Other = Elf32.Sym.Other;
10101029 };
1030 pub const Rel = extern struct {
1031 offset: Elf64.Addr,
1032 info: Info,
1033 addend: u0 = 0,
1034
1035 pub const Info = packed struct(u64) {
1036 type: u32,
1037 sym: u32,
1038 };
1039 };
1040 pub const Rela = extern struct {
1041 offset: Elf64.Addr,
1042 info: Info,
1043 addend: i64,
1044
1045 pub const Info = Elf64.Rel.Info;
1046 };
10111047 comptime {
10121048 assert(@sizeOf(Elf64.Ehdr) == 64);
10131049 assert(@sizeOf(Elf64.Phdr) == 56);
10141050 assert(@sizeOf(Elf64.Shdr) == 64);
10151051 assert(@sizeOf(Elf64.Sym) == 24);
1052 assert(@sizeOf(Elf64.Rel) == 16);
1053 assert(@sizeOf(Elf64.Rela) == 24);
10161054 }
10171055};
10181056pub const ElfN = switch (@sizeOf(usize)) {
......@@ -1428,6 +1466,14 @@ pub const CLASS = enum(u8) {
14281466 _,
14291467
14301468 pub const NUM = @typeInfo(CLASS).@"enum".fields.len;
1469
1470 pub fn ElfN(comptime class: CLASS) type {
1471 return switch (class) {
1472 .NONE, _ => comptime unreachable,
1473 .@"32" => Elf32,
1474 .@"64" => Elf64,
1475 };
1476 }
14311477};
14321478
14331479/// Deprecated, use `@intFromEnum(std.elf.DATA.NONE)`
src/Compilation.zig+1-1
......@@ -1989,7 +1989,7 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,
19891989 break :s if (is_exe_or_dyn_lib and build_options.have_llvm) .dyn_lib else .zcu;
19901990 },
19911991 }
1992 if (options.config.use_new_linker) break :s .zcu;
1992 if (options.config.use_new_linker) break :s .obj;
19931993 }
19941994 if (need_llvm and !build_options.have_llvm) break :s .none; // impossible to build without llvm
19951995 if (is_exe_or_dyn_lib) break :s .lib;
src/codegen/x86_64/Emit.zig+5-7
......@@ -217,9 +217,7 @@ pub fn emitMir(emit: *Emit) Error!void {
217217 }, emit.lower.target), reloc_info),
218218 .mov => try emit.encodeInst(try .new(.none, .mov, &.{
219219 lowered_inst.ops[0],
220 .{ .mem = .initSib(lowered_inst.ops[reloc.op_index].mem.sib.ptr_size, .{
221 .base = .{ .reg = .ds },
222 }) },
220 .{ .mem = .initSib(lowered_inst.ops[reloc.op_index].mem.sib.ptr_size, .{}) },
223221 }, emit.lower.target), reloc_info),
224222 else => unreachable,
225223 } else if (reloc.target.is_extern) switch (lowered_inst.encoding.mnemonic) {
......@@ -720,7 +718,7 @@ pub fn emitMir(emit: *Emit) Error!void {
720718
721719 for (emit.table_relocs.items) |table_reloc| try atom.addReloc(gpa, .{
722720 .r_offset = table_reloc.source_offset,
723 .r_info = @as(u64, emit.atom_index) << 32 | @intFromEnum(std.elf.R_X86_64.@"32"),
721 .r_info = @as(u64, emit.atom_index) << 32 | @intFromEnum(std.elf.R_X86_64.@"32S"),
724722 .r_addend = @as(i64, table_offset) + table_reloc.target_offset,
725723 }, zo);
726724 for (emit.lower.mir.table) |entry| {
......@@ -738,7 +736,7 @@ pub fn emitMir(emit: *Emit) Error!void {
738736 table_reloc.source_offset,
739737 @enumFromInt(emit.atom_index),
740738 @as(i64, table_offset) + table_reloc.target_offset,
741 .{ .X86_64 = .@"32" },
739 .{ .X86_64 = .@"32S" },
742740 );
743741 for (emit.lower.mir.table) |entry| {
744742 try elf.addReloc(
......@@ -824,7 +822,7 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI
824822 const zo = elf_file.zigObjectPtr().?;
825823 const atom = zo.symbol(emit.atom_index).atom(elf_file).?;
826824 const r_type: std.elf.R_X86_64 = if (!emit.pic)
827 .@"32"
825 .@"32S"
828826 else if (reloc.target.is_extern and !reloc.target.force_pcrel_direct)
829827 .GOTPCREL
830828 else
......@@ -855,7 +853,7 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI
855853 end_offset - 4,
856854 @enumFromInt(reloc.target.index),
857855 reloc.off,
858 .{ .X86_64 = .@"32" },
856 .{ .X86_64 = .@"32S" },
859857 ) else if (emit.bin_file.cast(.coff2)) |coff| try coff.addReloc(
860858 @enumFromInt(emit.atom_index),
861859 end_offset - 4,
src/link/Elf2.zig+234-188
......@@ -12,10 +12,8 @@ inputs: std.ArrayList(struct {
1212}),
1313input_sections: std.ArrayList(struct {
1414 ii: Node.InputIndex,
15 ni: MappedFile.Node.Index,
16 addr: u64,
17 offset: u64,
18 size: u64,
15 si: Symbol.Index,
16 file_location: MappedFile.Node.FileLocation,
1917}),
2018input_section_pending_index: u32,
2119globals: std.AutoArrayHashMapUnmanaged(u32, Symbol.Index),
......@@ -59,7 +57,7 @@ pub const Node = union(enum) {
5957 return elf.inputs.items[@intFromEnum(ii)].si;
6058 }
6159
62 pub fn nextSymbol(ii: InputIndex, elf: *const Elf) Symbol.Index {
60 pub fn endSymbol(ii: InputIndex, elf: *const Elf) Symbol.Index {
6361 const next_ii = @intFromEnum(ii) + 1;
6462 return if (next_ii < elf.inputs.items.len)
6563 @as(InputIndex, @enumFromInt(next_ii)).symbol(elf)
......@@ -75,17 +73,12 @@ pub const Node = union(enum) {
7573 return elf.input_sections.items[@intFromEnum(isi)].ii;
7674 }
7775
78 pub fn node(isi: InputSectionIndex, elf: *const Elf) MappedFile.Node.Index {
79 return elf.input_sections.items[@intFromEnum(isi)].ni;
76 pub fn symbol(isi: InputSectionIndex, elf: *const Elf) Symbol.Index {
77 return elf.input_sections.items[@intFromEnum(isi)].si;
8078 }
8179
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 };
80 pub fn fileLocation(isi: InputSectionIndex, elf: *const Elf) MappedFile.Node.FileLocation {
81 return elf.input_sections.items[@intFromEnum(isi)].file_location;
8982 }
9083 };
9184
......@@ -302,9 +295,12 @@ pub const Symbol = struct {
302295 }
303296
304297 pub fn applyLocationRelocs(si: Symbol.Index, elf: *Elf) void {
305 for (elf.relocs.items[@intFromEnum(si.get(elf).loc_relocs)..]) |*reloc| {
306 if (reloc.loc != si) break;
307 reloc.apply(elf);
298 switch (si.get(elf).loc_relocs) {
299 .none => {},
300 else => |loc_relocs| for (elf.relocs.items[@intFromEnum(loc_relocs)..]) |*reloc| {
301 if (reloc.loc != si) break;
302 reloc.apply(elf);
303 },
308304 }
309305 }
310306
......@@ -390,7 +386,7 @@ pub const Reloc = extern struct {
390386 target_value,
391387 target_endian,
392388 ),
393 .PC32 => std.mem.writeInt(
389 .PC32, .PLT32 => std.mem.writeInt(
394390 i32,
395391 loc_slice[0..4],
396392 @intCast(@as(i64, @bitCast(target_value -% loc_value))),
......@@ -402,6 +398,12 @@ pub const Reloc = extern struct {
402398 @intCast(target_value),
403399 target_endian,
404400 ),
401 .@"32S" => std.mem.writeInt(
402 i32,
403 loc_slice[0..4],
404 @intCast(@as(i64, @bitCast(target_value))),
405 target_endian,
406 ),
405407 .TPOFF32 => {
406408 const phdr = @field(elf.phdrSlice(), @tagName(class));
407409 const ph = &phdr[elf.getNode(elf.known.tls).segment];
......@@ -632,12 +634,7 @@ fn initHeaders(
632634 switch (class) {
633635 .NONE, _ => unreachable,
634636 inline else => |ct_class| {
635 const ElfN = switch (ct_class) {
636 .NONE, _ => comptime unreachable,
637 .@"32" => std.elf.Elf32,
638 .@"64" => std.elf.Elf64,
639 };
640
637 const ElfN = ct_class.ElfN();
641638 assert(Node.Known.ehdr == try elf.mf.addOnlyChildNode(gpa, Node.Known.rodata, .{
642639 .size = @sizeOf(ElfN.Ehdr),
643640 .alignment = addr_align,
......@@ -717,11 +714,7 @@ fn initHeaders(
717714 switch (class) {
718715 .NONE, _ => unreachable,
719716 inline else => |ct_class| {
720 const ElfN = switch (ct_class) {
721 .NONE, _ => comptime unreachable,
722 .@"32" => std.elf.Elf32,
723 .@"64" => std.elf.Elf64,
724 };
717 const ElfN = ct_class.ElfN();
725718 const target_endian = elf.targetEndian();
726719
727720 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 {
12931286 switch (elf.identClass()) {
12941287 .NONE, _ => unreachable,
12951288 inline else => |class| {
1296 const ehdr = try r.peekStruct(
1297 @typeInfo(@FieldType(EhdrPtr, @tagName(class))).pointer.child,
1298 target_endian,
1299 );
1289 const ElfN = class.ElfN();
1290 const ehdr = try r.peekStruct(ElfN.Ehdr, target_endian);
13001291 if (ehdr.type != .REL)
13011292 return diags.failParse(object.path, "unsupported object type", .{});
13021293 if (ehdr.machine != elf.ehdrField(.machine))
13031294 return diags.failParse(object.path, "wrong machine", .{});
13041295 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))
1296 if (ehdr.shentsize < @sizeOf(ElfN.Shdr))
13091297 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 }
13101311 const shstrtab = shstrtab: {
1311 try fr.seekTo(ehdr.shoff + ehdr.shentsize * ehdr.shstrndx);
1312 const shdr = try r.peekStruct(Shdr, target_endian);
1312 if (ehdr.shstrndx == std.elf.SHN_UNDEF or ehdr.shstrndx >= ehdr.shnum)
1313 return diags.failParse(object.path, "missing section names", .{});
1314 const shdr = &sections[ehdr.shstrndx].shdr;
13131315 if (shdr.type != std.elf.SHT_STRTAB)
13141316 return diags.failParse(object.path, "invalid shstrtab type", .{});
13151317 const shstrtab = try gpa.alloc(u8, @intCast(shdr.size));
......@@ -1319,141 +1321,186 @@ pub fn loadInput(elf: *Elf, input: link.Input) !void {
13191321 break :shstrtab shstrtab;
13201322 };
13211323 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;
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 },
13951359 };
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,
1360 var symmap: std.ArrayList(Symbol.Index) = .empty;
1361 defer symmap.deinit(gpa);
1362 for (sections[1..], 1..) |*symtab, symtab_shndx| switch (symtab.shdr.type) {
1363 else => {},
1364 std.elf.SHT_SYMTAB => {
1365 if (symtab.shdr.entsize < @sizeOf(ElfN.Sym))
1366 return diags.failParse(object.path, "unsupported symtab entsize", .{});
1367 const strtab = strtab: {
1368 if (symtab.shdr.link == std.elf.SHN_UNDEF or symtab.shdr.link >= ehdr.shnum)
1369 return diags.failParse(object.path, "missing symbol names", .{});
1370 const shdr = &sections[symtab.shdr.link].shdr;
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 };
1379 defer gpa.free(strtab);
1380 const symnum = try std.math.divExact(
1381 u32,
1382 @intCast(symtab.shdr.size),
1383 @intCast(symtab.shdr.entsize),
1384 );
1385 symmap.clearRetainingCapacity();
1386 try symmap.resize(gpa, symnum);
1387 try elf.symtab.ensureUnusedCapacity(gpa, symnum);
1388 try elf.globals.ensureUnusedCapacity(gpa, symnum);
1389 try fr.seekTo(symtab.shdr.offset + symtab.shdr.entsize);
1390 symmap.items[0] = .null;
1391 for (symmap.items[1..]) |*si| {
1392 si.* = .null;
1393 const input_sym = try r.peekStruct(ElfN.Sym, target_endian);
1394 try fr.seekBy(@intCast(symtab.shdr.entsize));
1395 if (input_sym.name >= strtab.len or
1396 input_sym.shndx == std.elf.SHN_UNDEF or
1397 input_sym.shndx >= ehdr.shnum) continue;
1398 switch (input_sym.info.type) {
1399 else => continue,
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.*;
14371447 },
1438 ).bind) {
1439 else => unreachable,
1440 .GLOBAL => return diags.failParse(
1448 }
1449 }
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(
14411462 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 }
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 },
1503 };
14571504 },
14581505 }
14591506 },
......@@ -1512,11 +1559,10 @@ pub fn getVAddr(elf: *Elf, reloc_info: link.File.RelocInfo, target_si: Symbol.In
15121559 reloc_info.addend,
15131560 switch (elf.ehdrField(.machine)) {
15141561 else => unreachable,
1515 .X86_64 => .{ .X86_64 = switch (elf.identClass()) {
1516 .NONE, _ => unreachable,
1517 .@"32" => .@"32",
1518 .@"64" => .@"64",
1519 } },
1562 .AARCH64 => .{ .AARCH64 = .ABS64 },
1563 .PPC64 => .{ .PPC64 = .ADDR64 },
1564 .RISCV => .{ .RISCV = .@"64" },
1565 .X86_64 => .{ .X86_64 = .@"64" },
15201566 },
15211567 );
15221568 return switch (elf.symPtr(target_si)) {
......@@ -1912,11 +1958,11 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool {
19121958 if (elf.input_section_pending_index < elf.input_sections.items.len) {
19131959 const isi: Node.InputSectionIndex = @enumFromInt(elf.input_section_pending_index);
19141960 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)));
19161962 defer sub_prog_node.end();
19171963 elf.flushInputSection(isi) catch |err| switch (err) {
19181964 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),
19201966 isi.input(elf).path(elf).fmtEscapeString(),
19211967 e,
19221968 }),
......@@ -1954,7 +2000,7 @@ fn idleProgNode(
19542000 .section => |si| elf.sectionName(si),
19552001 .input_section => |isi| std.fmt.bufPrint(&name, "{f} {s}", .{
19562002 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),
19582004 }) catch &name,
19592005 .nav => |nmi| {
19602006 const ip = &elf.base.comp.zcu.?.intern_pool;
......@@ -2078,8 +2124,8 @@ fn flushLazy(elf: *Elf, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void {
20782124}
20792125
20802126fn flushInputSection(elf: *Elf, isi: Node.InputSectionIndex) !void {
2081 const offset, const size = isi.fileLocation(elf);
2082 if (size == 0) return;
2127 const file_loc = isi.fileLocation(elf);
2128 if (file_loc.size == 0) return;
20832129 const comp = elf.base.comp;
20842130 const gpa = comp.gpa;
20852131 const io = comp.io;
......@@ -2087,11 +2133,11 @@ fn flushInputSection(elf: *Elf, isi: Node.InputSectionIndex) !void {
20872133 const file = try path.root_dir.handle.adaptToNewApi().openFile(io, path.sub_path, .{});
20882134 defer file.close(io);
20892135 var fr = file.reader(io, &.{});
2090 try fr.seekTo(offset);
2136 try fr.seekTo(file_loc.offset);
20912137 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);
20932139 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;
20952141}
20962142
20972143fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {
......@@ -2132,13 +2178,13 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {
21322178 },
21332179 },
21342180 .input_section => |isi| {
2135 const addr = isi.addr(elf);
2136 const old_addr = addr.*;
2181 const old_addr = switch (elf.symPtr(isi.symbol(elf))) {
2182 inline else => |sym| elf.targetLoad(&sym.value),
2183 };
21372184 const new_addr = elf.computeNodeVAddr(ni);
2138 addr.* = new_addr;
21392185 const ii = isi.input(elf);
21402186 var si = ii.symbol(elf);
2141 const end_si = ii.nextSymbol(elf);
2187 const end_si = ii.endSymbol(elf);
21422188 while (cond: {
21432189 si = si.next();
21442190 break :cond si != end_si;
src/link/MappedFile.zig+3-3
......@@ -144,6 +144,8 @@ pub const Node = extern struct {
144144 }
145145 };
146146
147 pub const FileLocation = struct { offset: u64, size: u64 };
148
147149 pub const Index = enum(u32) {
148150 none,
149151 _,
......@@ -275,7 +277,7 @@ pub const Node = extern struct {
275277 ni: Node.Index,
276278 mf: *const MappedFile,
277279 set_has_content: bool,
278 ) struct { offset: u64, size: u64 } {
280 ) FileLocation {
279281 var offset, const size = ni.location(mf).resolve(mf);
280282 var parent_ni = ni;
281283 while (true) {
......@@ -402,8 +404,6 @@ pub const Node = extern struct {
402404 file_reader.interface.toss(n);
403405 return n;
404406 }
405
406 assert(file_reader.logicalPos() == file_reader.pos);
407407 const w: *Writer = @fieldParentPtr("interface", interface);
408408 const n: usize = @intCast(w.mf.copyFileRange(
409409 file_reader.file,