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 {...@@ -943,11 +943,30 @@ pub const Elf32 = struct {
943 unused: u5 = 0,943 unused: u5 = 0,
944 };944 };
945 };945 };
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 };
946 comptime {963 comptime {
947 assert(@sizeOf(Elf32.Ehdr) == 52);964 assert(@sizeOf(Elf32.Ehdr) == 52);
948 assert(@sizeOf(Elf32.Phdr) == 32);965 assert(@sizeOf(Elf32.Phdr) == 32);
949 assert(@sizeOf(Elf32.Shdr) == 40);966 assert(@sizeOf(Elf32.Shdr) == 40);
950 assert(@sizeOf(Elf32.Sym) == 16);967 assert(@sizeOf(Elf32.Sym) == 16);
968 assert(@sizeOf(Elf32.Rel) == 8);
969 assert(@sizeOf(Elf32.Rela) == 12);
951 }970 }
952};971};
953pub const Elf64 = struct {972pub const Elf64 = struct {
...@@ -1008,11 +1027,30 @@ pub const Elf64 = struct {...@@ -1008,11 +1027,30 @@ pub const Elf64 = struct {
1008 pub const Info = Elf32.Sym.Info;1027 pub const Info = Elf32.Sym.Info;
1009 pub const Other = Elf32.Sym.Other;1028 pub const Other = Elf32.Sym.Other;
1010 };1029 };
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 };
1011 comptime {1047 comptime {
1012 assert(@sizeOf(Elf64.Ehdr) == 64);1048 assert(@sizeOf(Elf64.Ehdr) == 64);
1013 assert(@sizeOf(Elf64.Phdr) == 56);1049 assert(@sizeOf(Elf64.Phdr) == 56);
1014 assert(@sizeOf(Elf64.Shdr) == 64);1050 assert(@sizeOf(Elf64.Shdr) == 64);
1015 assert(@sizeOf(Elf64.Sym) == 24);1051 assert(@sizeOf(Elf64.Sym) == 24);
1052 assert(@sizeOf(Elf64.Rel) == 16);
1053 assert(@sizeOf(Elf64.Rela) == 24);
1016 }1054 }
1017};1055};
1018pub const ElfN = switch (@sizeOf(usize)) {1056pub const ElfN = switch (@sizeOf(usize)) {
...@@ -1428,6 +1466,14 @@ pub const CLASS = enum(u8) {...@@ -1428,6 +1466,14 @@ pub const CLASS = enum(u8) {
1428 _,1466 _,
14291467
1430 pub const NUM = @typeInfo(CLASS).@"enum".fields.len;1468 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 }
1431};1477};
14321478
1433/// Deprecated, use `@intFromEnum(std.elf.DATA.NONE)`1479/// 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,...@@ -1989,7 +1989,7 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,
1989 break :s if (is_exe_or_dyn_lib and build_options.have_llvm) .dyn_lib else .zcu;1989 break :s if (is_exe_or_dyn_lib and build_options.have_llvm) .dyn_lib else .zcu;
1990 },1990 },
1991 }1991 }
1992 if (options.config.use_new_linker) break :s .zcu;1992 if (options.config.use_new_linker) break :s .obj;
1993 }1993 }
1994 if (need_llvm and !build_options.have_llvm) break :s .none; // impossible to build without llvm1994 if (need_llvm and !build_options.have_llvm) break :s .none; // impossible to build without llvm
1995 if (is_exe_or_dyn_lib) break :s .lib;1995 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 {...@@ -217,9 +217,7 @@ pub fn emitMir(emit: *Emit) Error!void {
217 }, emit.lower.target), reloc_info),217 }, emit.lower.target), reloc_info),
218 .mov => try emit.encodeInst(try .new(.none, .mov, &.{218 .mov => try emit.encodeInst(try .new(.none, .mov, &.{
219 lowered_inst.ops[0],219 lowered_inst.ops[0],
220 .{ .mem = .initSib(lowered_inst.ops[reloc.op_index].mem.sib.ptr_size, .{220 .{ .mem = .initSib(lowered_inst.ops[reloc.op_index].mem.sib.ptr_size, .{}) },
221 .base = .{ .reg = .ds },
222 }) },
223 }, emit.lower.target), reloc_info),221 }, emit.lower.target), reloc_info),
224 else => unreachable,222 else => unreachable,
225 } else if (reloc.target.is_extern) switch (lowered_inst.encoding.mnemonic) {223 } else if (reloc.target.is_extern) switch (lowered_inst.encoding.mnemonic) {
...@@ -720,7 +718,7 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -720,7 +718,7 @@ pub fn emitMir(emit: *Emit) Error!void {
720718
721 for (emit.table_relocs.items) |table_reloc| try atom.addReloc(gpa, .{719 for (emit.table_relocs.items) |table_reloc| try atom.addReloc(gpa, .{
722 .r_offset = table_reloc.source_offset,720 .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"),
724 .r_addend = @as(i64, table_offset) + table_reloc.target_offset,722 .r_addend = @as(i64, table_offset) + table_reloc.target_offset,
725 }, zo);723 }, zo);
726 for (emit.lower.mir.table) |entry| {724 for (emit.lower.mir.table) |entry| {
...@@ -738,7 +736,7 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -738,7 +736,7 @@ pub fn emitMir(emit: *Emit) Error!void {
738 table_reloc.source_offset,736 table_reloc.source_offset,
739 @enumFromInt(emit.atom_index),737 @enumFromInt(emit.atom_index),
740 @as(i64, table_offset) + table_reloc.target_offset,738 @as(i64, table_offset) + table_reloc.target_offset,
741 .{ .X86_64 = .@"32" },739 .{ .X86_64 = .@"32S" },
742 );740 );
743 for (emit.lower.mir.table) |entry| {741 for (emit.lower.mir.table) |entry| {
744 try elf.addReloc(742 try elf.addReloc(
...@@ -824,7 +822,7 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI...@@ -824,7 +822,7 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI
824 const zo = elf_file.zigObjectPtr().?;822 const zo = elf_file.zigObjectPtr().?;
825 const atom = zo.symbol(emit.atom_index).atom(elf_file).?;823 const atom = zo.symbol(emit.atom_index).atom(elf_file).?;
826 const r_type: std.elf.R_X86_64 = if (!emit.pic)824 const r_type: std.elf.R_X86_64 = if (!emit.pic)
827 .@"32"825 .@"32S"
828 else if (reloc.target.is_extern and !reloc.target.force_pcrel_direct)826 else if (reloc.target.is_extern and !reloc.target.force_pcrel_direct)
829 .GOTPCREL827 .GOTPCREL
830 else828 else
...@@ -855,7 +853,7 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI...@@ -855,7 +853,7 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI
855 end_offset - 4,853 end_offset - 4,
856 @enumFromInt(reloc.target.index),854 @enumFromInt(reloc.target.index),
857 reloc.off,855 reloc.off,
858 .{ .X86_64 = .@"32" },856 .{ .X86_64 = .@"32S" },
859 ) else if (emit.bin_file.cast(.coff2)) |coff| try coff.addReloc(857 ) else if (emit.bin_file.cast(.coff2)) |coff| try coff.addReloc(
860 @enumFromInt(emit.atom_index),858 @enumFromInt(emit.atom_index),
861 end_offset - 4,859 end_offset - 4,
src/link/Elf2.zig+234-188
...@@ -12,10 +12,8 @@ inputs: std.ArrayList(struct {...@@ -12,10 +12,8 @@ inputs: std.ArrayList(struct {
12}),12}),
13input_sections: std.ArrayList(struct {13input_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}),
20input_section_pending_index: u32,18input_section_pending_index: u32,
21globals: std.AutoArrayHashMapUnmanaged(u32, Symbol.Index),19globals: 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 }
6159
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 }
7775
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 }
8179
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 };
9184
...@@ -302,9 +295,12 @@ pub const Symbol = struct {...@@ -302,9 +295,12 @@ pub const Symbol = struct {
302 }295 }
303296
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 }
310306
...@@ -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();
726719
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}
20792125
2080fn flushInputSection(elf: *Elf, isi: Node.InputSectionIndex) !void {2126fn 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}
20962142
2097fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {2143fn 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;
src/link/MappedFile.zig+3-3
...@@ -144,6 +144,8 @@ pub const Node = extern struct {...@@ -144,6 +144,8 @@ pub const Node = extern struct {
144 }144 }
145 };145 };
146146
147 pub const FileLocation = struct { offset: u64, size: u64 };
148
147 pub const Index = enum(u32) {149 pub const Index = enum(u32) {
148 none,150 none,
149 _,151 _,
...@@ -275,7 +277,7 @@ pub const Node = extern struct {...@@ -275,7 +277,7 @@ pub const Node = extern struct {
275 ni: Node.Index,277 ni: Node.Index,
276 mf: *const MappedFile,278 mf: *const MappedFile,
277 set_has_content: bool,279 set_has_content: bool,
278 ) struct { offset: u64, size: u64 } {280 ) FileLocation {
279 var offset, const size = ni.location(mf).resolve(mf);281 var offset, const size = ni.location(mf).resolve(mf);
280 var parent_ni = ni;282 var parent_ni = ni;
281 while (true) {283 while (true) {
...@@ -402,8 +404,6 @@ pub const Node = extern struct {...@@ -402,8 +404,6 @@ pub const Node = extern struct {
402 file_reader.interface.toss(n);404 file_reader.interface.toss(n);
403 return n;405 return n;
404 }406 }
405
406 assert(file_reader.logicalPos() == file_reader.pos);
407 const w: *Writer = @fieldParentPtr("interface", interface);407 const w: *Writer = @fieldParentPtr("interface", interface);
408 const n: usize = @intCast(w.mf.copyFileRange(408 const n: usize = @intCast(w.mf.copyFileRange(
409 file_reader.file,409 file_reader.file,