authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-05-18 08:22:47+02:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-05-18 08:22:47+02:00
log27be3b069a8f577184ca8d2c41f1001ca46af646
treea163f31a1195095a834a61005d2582aaeda00b89
parent1deaf5a085308b7a48eadd7f4f22de6096681e94
parent9ba45527931e9e43a77d42a52b63a0203e029bd0

Merge pull request 'Elf2: various enhancements' (#35332) from elf2 into master

Reviewed-on: https://codeberg.org/ziglang/zig/pulls/35332

19 files changed, 2489 insertions(+), 1491 deletions(-)

lib/std/elf.zig+16-2
...@@ -1043,7 +1043,7 @@ pub const Elf32 = struct {...@@ -1043,7 +1043,7 @@ pub const Elf32 = struct {
1043 pub const Addr = u32;1043 pub const Addr = u32;
1044 pub const Off = u32;1044 pub const Off = u32;
1045 pub const Ehdr = extern struct {1045 pub const Ehdr = extern struct {
1046 ident: [EI.NIDENT]u8,1046 ident: Ident,
1047 type: ET,1047 type: ET,
1048 machine: EM,1048 machine: EM,
1049 version: Word,1049 version: Word,
...@@ -1133,7 +1133,7 @@ pub const Elf64 = struct {...@@ -1133,7 +1133,7 @@ pub const Elf64 = struct {
1133 pub const Addr = u64;1133 pub const Addr = u64;
1134 pub const Off = u64;1134 pub const Off = u64;
1135 pub const Ehdr = extern struct {1135 pub const Ehdr = extern struct {
1136 ident: [EI.NIDENT]u8,1136 ident: Ident,
1137 type: ET,1137 type: ET,
1138 machine: EM,1138 machine: EM,
1139 version: Word,1139 version: Word,
...@@ -1611,6 +1611,20 @@ pub const Sym = switch (@sizeOf(usize)) {...@@ -1611,6 +1611,20 @@ pub const Sym = switch (@sizeOf(usize)) {
1611/// Deprecated, use `std.elf.ElfN.Addr`1611/// Deprecated, use `std.elf.ElfN.Addr`
1612pub const Addr = ElfN.Addr;1612pub const Addr = ElfN.Addr;
16131613
1614pub const Ident = extern struct {
1615 magic: [MAGIC.len]u8 = MAGIC.*,
1616 class: CLASS,
1617 data: DATA,
1618 version: u8,
1619 osabi: OSABI,
1620 abiversion: u8,
1621 pad: [7]u8 = @splat(0),
1622
1623 comptime {
1624 assert(@sizeOf(Ident) == EI.NIDENT);
1625 }
1626};
1627
1614/// Deprecated, use `@intFromEnum(std.elf.CLASS.NONE)`1628/// Deprecated, use `@intFromEnum(std.elf.CLASS.NONE)`
1615pub const ELFCLASSNONE = @intFromEnum(CLASS.NONE);1629pub const ELFCLASSNONE = @intFromEnum(CLASS.NONE);
1616/// Deprecated, use `@intFromEnum(std.elf.CLASS.@"32")`1630/// Deprecated, use `@intFromEnum(std.elf.CLASS.@"32")`
lib/std/posix.zig+1-1
...@@ -834,7 +834,7 @@ pub fn dl_iterate_phdr(...@@ -834,7 +834,7 @@ pub fn dl_iterate_phdr(
834 while (it.next()) |entry| {834 while (it.next()) |entry| {
835 const phdrs: []elf.ElfN.Phdr = if (entry.addr != 0) phdrs: {835 const phdrs: []elf.ElfN.Phdr = if (entry.addr != 0) phdrs: {
836 const ehdr: *elf.ElfN.Ehdr = @ptrFromInt(entry.addr);836 const ehdr: *elf.ElfN.Ehdr = @ptrFromInt(entry.addr);
837 assert(mem.eql(u8, ehdr.ident[0..4], elf.MAGIC));837 assert(mem.eql(u8, &ehdr.ident.magic, elf.MAGIC));
838 const phdrs: [*]elf.ElfN.Phdr = @ptrFromInt(entry.addr + ehdr.phoff);838 const phdrs: [*]elf.ElfN.Phdr = @ptrFromInt(entry.addr + ehdr.phoff);
839 break :phdrs phdrs[0..ehdr.phnum];839 break :phdrs phdrs[0..ehdr.phnum];
840 } else getSelfPhdrs();840 } else getSelfPhdrs();
src/codegen.zig+17-30
...@@ -178,7 +178,7 @@ pub fn emitFunction(...@@ -178,7 +178,7 @@ pub fn emitFunction(
178 pt: Zcu.PerThread,178 pt: Zcu.PerThread,
179 src_loc: Zcu.LazySrcLoc,179 src_loc: Zcu.LazySrcLoc,
180 func_index: InternPool.Index,180 func_index: InternPool.Index,
181 atom_index: u32,181 atom_id: link.File.AtomId,
182 any_mir: *const AnyMir,182 any_mir: *const AnyMir,
183 w: *std.Io.Writer,183 w: *std.Io.Writer,
184 debug_output: link.File.DebugInfoOutput,184 debug_output: link.File.DebugInfoOutput,
...@@ -195,7 +195,7 @@ pub fn emitFunction(...@@ -195,7 +195,7 @@ pub fn emitFunction(
195 => |backend| {195 => |backend| {
196 dev.check(devFeatureForBackend(backend));196 dev.check(devFeatureForBackend(backend));
197 const mir = &@field(any_mir, AnyMir.tag(backend));197 const mir = &@field(any_mir, AnyMir.tag(backend));
198 return mir.emit(lf, pt, src_loc, func_index, atom_index, w, debug_output);198 return mir.emit(lf, pt, src_loc, func_index, atom_id, w, debug_output);
199 },199 },
200 }200 }
201}201}
...@@ -205,7 +205,7 @@ pub fn generateLazyFunction(...@@ -205,7 +205,7 @@ pub fn generateLazyFunction(
205 pt: Zcu.PerThread,205 pt: Zcu.PerThread,
206 src_loc: Zcu.LazySrcLoc,206 src_loc: Zcu.LazySrcLoc,
207 lazy_sym: link.File.LazySymbol,207 lazy_sym: link.File.LazySymbol,
208 atom_index: u32,208 atom_id: link.File.AtomId,
209 w: *std.Io.Writer,209 w: *std.Io.Writer,
210 debug_output: link.File.DebugInfoOutput,210 debug_output: link.File.DebugInfoOutput,
211) (CodeGenError || std.Io.Writer.Error)!void {211) (CodeGenError || std.Io.Writer.Error)!void {
...@@ -218,7 +218,7 @@ pub fn generateLazyFunction(...@@ -218,7 +218,7 @@ pub fn generateLazyFunction(
218 else => unreachable,218 else => unreachable,
219 inline .stage2_riscv64, .stage2_x86_64 => |backend| {219 inline .stage2_riscv64, .stage2_x86_64 => |backend| {
220 dev.check(devFeatureForBackend(backend));220 dev.check(devFeatureForBackend(backend));
221 return importBackend(backend).generateLazy(lf, pt, src_loc, lazy_sym, atom_index, w, debug_output);221 return importBackend(backend).generateLazy(lf, pt, src_loc, lazy_sym, atom_id, w, debug_output);
222 },222 },
223 }223 }
224}224}
...@@ -852,20 +852,7 @@ fn lowerNavRef(...@@ -852,20 +852,7 @@ fn lowerNavRef(
852 }852 }
853}853}
854854
855/// Helper struct to denote that the value is in memory but requires a linker relocation fixup:855pub const SymbolResult = union(enum) { sym_index: link.File.SymbolId, fail: *ErrorMsg };
856/// * got - the value is referenced indirectly via GOT entry index (the linker emits a got-type reloc)
857/// * direct - the value is referenced directly via symbol index index (the linker emits a displacement reloc)
858/// * import - the value is referenced indirectly via import entry index (the linker emits an import-type reloc)
859pub const LinkerLoad = struct {
860 type: enum {
861 got,
862 direct,
863 import,
864 },
865 sym_index: u32,
866};
867
868pub const SymbolResult = union(enum) { sym_index: u32, fail: *ErrorMsg };
869856
870pub fn genNavRef(857pub fn genNavRef(
871 lf: *link.File,858 lf: *link.File,
...@@ -890,7 +877,7 @@ pub fn genNavRef(...@@ -890,7 +877,7 @@ pub fn genNavRef(
890 .internal => {877 .internal => {
891 const sym_index = try zo.getOrCreateMetadataForNav(zcu, nav_index);878 const sym_index = try zo.getOrCreateMetadataForNav(zcu, nav_index);
892 if (is_threadlocal) zo.symbol(sym_index).flags.is_tls = true;879 if (is_threadlocal) zo.symbol(sym_index).flags.is_tls = true;
893 return .{ .sym_index = sym_index };880 return .{ .sym_index = @enumFromInt(sym_index) };
894 },881 },
895 .strong, .weak => {882 .strong, .weak => {
896 const sym_index = try elf_file.getGlobalSymbol(nav.name.toSlice(ip), lib_name.toSlice(ip));883 const sym_index = try elf_file.getGlobalSymbol(nav.name.toSlice(ip), lib_name.toSlice(ip));
...@@ -901,12 +888,12 @@ pub fn genNavRef(...@@ -901,12 +888,12 @@ pub fn genNavRef(
901 .link_once => unreachable,888 .link_once => unreachable,
902 }889 }
903 if (is_threadlocal) zo.symbol(sym_index).flags.is_tls = true;890 if (is_threadlocal) zo.symbol(sym_index).flags.is_tls = true;
904 return .{ .sym_index = sym_index };891 return .{ .sym_index = @enumFromInt(sym_index) };
905 },892 },
906 .link_once => unreachable,893 .link_once => unreachable,
907 }894 }
908 } else if (lf.cast(.elf2)) |elf| {895 } else if (lf.cast(.elf2)) |elf| {
909 return .{ .sym_index = @intFromEnum(elf.navSymbol(zcu, nav_index) catch |err| switch (err) {896 return .{ .sym_index = elf.navSymbol(nav_index) catch |err| switch (err) {
910 error.OutOfMemory => |e| return e,897 error.OutOfMemory => |e| return e,
911 else => |e| return .{ .fail = try ErrorMsg.create(898 else => |e| return .{ .fail = try ErrorMsg.create(
912 zcu.gpa,899 zcu.gpa,
...@@ -914,14 +901,14 @@ pub fn genNavRef(...@@ -914,14 +901,14 @@ pub fn genNavRef(
914 "linker failed to create a nav: {t}",901 "linker failed to create a nav: {t}",
915 .{e},902 .{e},
916 ) },903 ) },
917 }) };904 } };
918 } else if (lf.cast(.macho)) |macho_file| {905 } else if (lf.cast(.macho)) |macho_file| {
919 const zo = macho_file.getZigObject().?;906 const zo = macho_file.getZigObject().?;
920 switch (linkage) {907 switch (linkage) {
921 .internal => {908 .internal => {
922 const sym_index = try zo.getOrCreateMetadataForNav(macho_file, nav_index);909 const sym_index = try zo.getOrCreateMetadataForNav(macho_file, nav_index);
923 if (is_threadlocal) zo.symbols.items[sym_index].flags.tlv = true;910 if (is_threadlocal) zo.symbols.items[sym_index].flags.tlv = true;
924 return .{ .sym_index = sym_index };911 return .{ .sym_index = @enumFromInt(sym_index) };
925 },912 },
926 .strong, .weak => {913 .strong, .weak => {
927 const sym_index = try macho_file.getGlobalSymbol(nav.name.toSlice(ip), lib_name.toSlice(ip));914 const sym_index = try macho_file.getGlobalSymbol(nav.name.toSlice(ip), lib_name.toSlice(ip));
...@@ -932,12 +919,12 @@ pub fn genNavRef(...@@ -932,12 +919,12 @@ pub fn genNavRef(
932 .link_once => unreachable,919 .link_once => unreachable,
933 }920 }
934 if (is_threadlocal) zo.symbols.items[sym_index].flags.tlv = true;921 if (is_threadlocal) zo.symbols.items[sym_index].flags.tlv = true;
935 return .{ .sym_index = sym_index };922 return .{ .sym_index = @enumFromInt(sym_index) };
936 },923 },
937 .link_once => unreachable,924 .link_once => unreachable,
938 }925 }
939 } else if (lf.cast(.coff2)) |coff| {926 } else if (lf.cast(.coff2)) |coff| {
940 return .{ .sym_index = @intFromEnum(try coff.navSymbol(zcu, nav_index)) };927 return .{ .sym_index = @enumFromInt(@intFromEnum(try coff.navSymbol(zcu, nav_index))) };
941 } else {928 } else {
942 const msg = try ErrorMsg.create(zcu.gpa, src_loc, "TODO genNavRef for target {}", .{target});929 const msg = try ErrorMsg.create(zcu.gpa, src_loc, "TODO genNavRef for target {}", .{target});
943 return .{ .fail = msg };930 return .{ .fail = msg };
...@@ -957,22 +944,22 @@ pub const GenResult = union(enum) {...@@ -957,22 +944,22 @@ pub const GenResult = union(enum) {
957 immediate: u64,944 immediate: u64,
958 /// Decl with address deferred until the linker allocates everything in virtual memory.945 /// Decl with address deferred until the linker allocates everything in virtual memory.
959 /// Payload is a symbol index.946 /// Payload is a symbol index.
960 load_direct: u32,947 load_direct: link.File.SymbolId,
961 /// Decl with address deferred until the linker allocates everything in virtual memory.948 /// Decl with address deferred until the linker allocates everything in virtual memory.
962 /// Payload is a symbol index.949 /// Payload is a symbol index.
963 lea_direct: u32,950 lea_direct: link.File.SymbolId,
964 /// Decl referenced via GOT with address deferred until the linker allocates951 /// Decl referenced via GOT with address deferred until the linker allocates
965 /// everything in virtual memory.952 /// everything in virtual memory.
966 /// Payload is a symbol index.953 /// Payload is a symbol index.
967 load_got: u32,954 load_got: link.File.SymbolId,
968 /// Direct by-address reference to memory location.955 /// Direct by-address reference to memory location.
969 memory: u64,956 memory: u64,
970 /// Reference to memory location but deferred until linker allocated the Decl in memory.957 /// Reference to memory location but deferred until linker allocated the Decl in memory.
971 /// Traditionally, this corresponds to emitting a relocation in a relocatable object file.958 /// Traditionally, this corresponds to emitting a relocation in a relocatable object file.
972 load_symbol: u32,959 load_symbol: link.File.SymbolId,
973 /// Reference to memory location but deferred until linker allocated the Decl in memory.960 /// Reference to memory location but deferred until linker allocated the Decl in memory.
974 /// Traditionally, this corresponds to emitting a relocation in a relocatable object file.961 /// Traditionally, this corresponds to emitting a relocation in a relocatable object file.
975 lea_symbol: u32,962 lea_symbol: link.File.SymbolId,
976 };963 };
977};964};
978965
src/codegen/aarch64/Mir.zig+26-26
...@@ -56,7 +56,7 @@ pub fn emit(...@@ -56,7 +56,7 @@ pub fn emit(
56 pt: Zcu.PerThread,56 pt: Zcu.PerThread,
57 src_loc: Zcu.LazySrcLoc,57 src_loc: Zcu.LazySrcLoc,
58 func_index: InternPool.Index,58 func_index: InternPool.Index,
59 atom_index: u32,59 atom_index: link.File.AtomId,
60 w: *std.Io.Writer,60 w: *std.Io.Writer,
61 debug_output: link.File.DebugInfoOutput,61 debug_output: link.File.DebugInfoOutput,
62) !void {62) !void {
...@@ -132,11 +132,11 @@ pub fn emit(...@@ -132,11 +132,11 @@ pub fn emit(
132 zcu,132 zcu,
133 atom_index,133 atom_index,
134 if (lf.cast(.elf)) |ef|134 if (lf.cast(.elf)) |ef|
135 ef.zigObjectPtr().?.getOrCreateMetadataForLazySymbol(ef, pt, lazy_reloc.symbol) catch |err|135 @enumFromInt(ef.zigObjectPtr().?.getOrCreateMetadataForLazySymbol(ef, pt, lazy_reloc.symbol) catch |err|
136 return zcu.codegenFail(func.owner_nav, "{s} creating lazy symbol", .{@errorName(err)})136 return zcu.codegenFail(func.owner_nav, "{s} creating lazy symbol", .{@errorName(err)}))
137 else if (lf.cast(.macho)) |mf|137 else if (lf.cast(.macho)) |mf|
138 mf.getZigObject().?.getOrCreateMetadataForLazySymbol(mf, pt, lazy_reloc.symbol) catch |err|138 @enumFromInt(mf.getZigObject().?.getOrCreateMetadataForLazySymbol(mf, pt, lazy_reloc.symbol) catch |err|
139 return zcu.codegenFail(func.owner_nav, "{s} creating lazy symbol", .{@errorName(err)})139 return zcu.codegenFail(func.owner_nav, "{s} creating lazy symbol", .{@errorName(err)}))
140 else140 else
141 return zcu.codegenFail(func.owner_nav, "external symbols unimplemented for {t}", .{lf.tag}),141 return zcu.codegenFail(func.owner_nav, "external symbols unimplemented for {t}", .{lf.tag}),
142 mir.body[lazy_reloc.reloc.label],142 mir.body[lazy_reloc.reloc.label],
...@@ -149,9 +149,9 @@ pub fn emit(...@@ -149,9 +149,9 @@ pub fn emit(
149 zcu,149 zcu,
150 atom_index,150 atom_index,
151 if (lf.cast(.elf)) |ef|151 if (lf.cast(.elf)) |ef|
152 try ef.getGlobalSymbol(std.mem.span(global_reloc.name), null)152 @enumFromInt(try ef.getGlobalSymbol(std.mem.span(global_reloc.name), null))
153 else if (lf.cast(.macho)) |mf|153 else if (lf.cast(.macho)) |mf|
154 try mf.getGlobalSymbol(std.mem.span(global_reloc.name), null)154 @enumFromInt(try mf.getGlobalSymbol(std.mem.span(global_reloc.name), null))
155 else155 else
156 return zcu.codegenFail(func.owner_nav, "external symbols unimplemented for {t}", .{lf.tag}),156 return zcu.codegenFail(func.owner_nav, "external symbols unimplemented for {t}", .{lf.tag}),
157 mir.body[global_reloc.reloc.label],157 mir.body[global_reloc.reloc.label],
...@@ -187,8 +187,8 @@ fn emitInstruction(w: *std.Io.Writer, instruction: Instruction) !void {...@@ -187,8 +187,8 @@ fn emitInstruction(w: *std.Io.Writer, instruction: Instruction) !void {
187fn emitReloc(187fn emitReloc(
188 lf: *link.File,188 lf: *link.File,
189 zcu: *Zcu,189 zcu: *Zcu,
190 atom_index: u32,190 atom_index: link.File.AtomId,
191 sym_index: u32,191 sym_index: link.File.SymbolId,
192 instruction: Instruction,192 instruction: Instruction,
193 offset: u32,193 offset: u32,
194 addend: u64,194 addend: u64,
...@@ -199,7 +199,7 @@ fn emitReloc(...@@ -199,7 +199,7 @@ fn emitReloc(
199 else => unreachable,199 else => unreachable,
200 .data_processing_immediate => |decoded| if (lf.cast(.elf)) |ef| {200 .data_processing_immediate => |decoded| if (lf.cast(.elf)) |ef| {
201 const zo = ef.zigObjectPtr().?;201 const zo = ef.zigObjectPtr().?;
202 const atom = zo.symbol(atom_index).atom(ef).?;202 const atom = zo.symbol(@intFromEnum(atom_index)).atom(ef).?;
203 const r_type: std.elf.R_AARCH64 = switch (decoded.decode()) {203 const r_type: std.elf.R_AARCH64 = switch (decoded.decode()) {
204 else => unreachable,204 else => unreachable,
205 .pc_relative_addressing => |pc_relative_addressing| switch (pc_relative_addressing.group.op) {205 .pc_relative_addressing => |pc_relative_addressing| switch (pc_relative_addressing.group.op) {
...@@ -222,12 +222,12 @@ fn emitReloc(...@@ -222,12 +222,12 @@ fn emitReloc(
222 };222 };
223 try atom.addReloc(gpa, .{223 try atom.addReloc(gpa, .{
224 .r_offset = offset,224 .r_offset = offset,
225 .r_info = @as(u64, sym_index) << 32 | @intFromEnum(r_type),225 .r_info = @as(u64, @intFromEnum(sym_index)) << 32 | @intFromEnum(r_type),
226 .r_addend = @bitCast(addend),226 .r_addend = @bitCast(addend),
227 }, zo);227 }, zo);
228 } else if (lf.cast(.macho)) |mf| {228 } else if (lf.cast(.macho)) |mf| {
229 const zo = mf.getZigObject().?;229 const zo = mf.getZigObject().?;
230 const atom = zo.symbols.items[atom_index].getAtom(mf).?;230 const atom = zo.symbols.items[@intFromEnum(atom_index)].getAtom(mf).?;
231 switch (decoded.decode()) {231 switch (decoded.decode()) {
232 else => unreachable,232 else => unreachable,
233 .pc_relative_addressing => |pc_relative_addressing| switch (pc_relative_addressing.group.op) {233 .pc_relative_addressing => |pc_relative_addressing| switch (pc_relative_addressing.group.op) {
...@@ -235,7 +235,7 @@ fn emitReloc(...@@ -235,7 +235,7 @@ fn emitReloc(
235 .adrp => try atom.addReloc(mf, .{235 .adrp => try atom.addReloc(mf, .{
236 .tag = .@"extern",236 .tag = .@"extern",
237 .offset = offset,237 .offset = offset,
238 .target = sym_index,238 .target = @intFromEnum(sym_index),
239 .addend = @bitCast(addend),239 .addend = @bitCast(addend),
240 .type = switch (kind) {240 .type = switch (kind) {
241 .direct => .page,241 .direct => .page,
...@@ -245,7 +245,7 @@ fn emitReloc(...@@ -245,7 +245,7 @@ fn emitReloc(
245 .pcrel = true,245 .pcrel = true,
246 .has_subtractor = false,246 .has_subtractor = false,
247 .length = 2,247 .length = 2,
248 .symbolnum = @intCast(sym_index),248 .symbolnum = @intCast(@intFromEnum(sym_index)),
249 },249 },
250 }),250 }),
251 },251 },
...@@ -253,7 +253,7 @@ fn emitReloc(...@@ -253,7 +253,7 @@ fn emitReloc(
253 .add => try atom.addReloc(mf, .{253 .add => try atom.addReloc(mf, .{
254 .tag = .@"extern",254 .tag = .@"extern",
255 .offset = offset,255 .offset = offset,
256 .target = sym_index,256 .target = @intFromEnum(sym_index),
257 .addend = @bitCast(addend),257 .addend = @bitCast(addend),
258 .type = switch (kind) {258 .type = switch (kind) {
259 .direct => .pageoff,259 .direct => .pageoff,
...@@ -263,7 +263,7 @@ fn emitReloc(...@@ -263,7 +263,7 @@ fn emitReloc(
263 .pcrel = false,263 .pcrel = false,
264 .has_subtractor = false,264 .has_subtractor = false,
265 .length = 2,265 .length = 2,
266 .symbolnum = @intCast(sym_index),266 .symbolnum = @intCast(@intFromEnum(sym_index)),
267 },267 },
268 }),268 }),
269 .sub => unreachable,269 .sub => unreachable,
...@@ -272,36 +272,36 @@ fn emitReloc(...@@ -272,36 +272,36 @@ fn emitReloc(
272 },272 },
273 .branch_exception_generating_system => |decoded| if (lf.cast(.elf)) |ef| {273 .branch_exception_generating_system => |decoded| if (lf.cast(.elf)) |ef| {
274 const zo = ef.zigObjectPtr().?;274 const zo = ef.zigObjectPtr().?;
275 const atom = zo.symbol(atom_index).atom(ef).?;275 const atom = zo.symbol(@intFromEnum(atom_index)).atom(ef).?;
276 const r_type: std.elf.R_AARCH64 = switch (decoded.decode().unconditional_branch_immediate.group.op) {276 const r_type: std.elf.R_AARCH64 = switch (decoded.decode().unconditional_branch_immediate.group.op) {
277 .b => .JUMP26,277 .b => .JUMP26,
278 .bl => .CALL26,278 .bl => .CALL26,
279 };279 };
280 try atom.addReloc(gpa, .{280 try atom.addReloc(gpa, .{
281 .r_offset = offset,281 .r_offset = offset,
282 .r_info = @as(u64, sym_index) << 32 | @intFromEnum(r_type),282 .r_info = @as(u64, @intFromEnum(sym_index)) << 32 | @intFromEnum(r_type),
283 .r_addend = @bitCast(addend),283 .r_addend = @bitCast(addend),
284 }, zo);284 }, zo);
285 } else if (lf.cast(.macho)) |mf| {285 } else if (lf.cast(.macho)) |mf| {
286 const zo = mf.getZigObject().?;286 const zo = mf.getZigObject().?;
287 const atom = zo.symbols.items[atom_index].getAtom(mf).?;287 const atom = zo.symbols.items[@intFromEnum(atom_index)].getAtom(mf).?;
288 try atom.addReloc(mf, .{288 try atom.addReloc(mf, .{
289 .tag = .@"extern",289 .tag = .@"extern",
290 .offset = offset,290 .offset = offset,
291 .target = sym_index,291 .target = @intFromEnum(sym_index),
292 .addend = @bitCast(addend),292 .addend = @bitCast(addend),
293 .type = .branch,293 .type = .branch,
294 .meta = .{294 .meta = .{
295 .pcrel = true,295 .pcrel = true,
296 .has_subtractor = false,296 .has_subtractor = false,
297 .length = 2,297 .length = 2,
298 .symbolnum = @intCast(sym_index),298 .symbolnum = @intCast(@intFromEnum(sym_index)),
299 },299 },
300 });300 });
301 },301 },
302 .load_store => |decoded| if (lf.cast(.elf)) |ef| {302 .load_store => |decoded| if (lf.cast(.elf)) |ef| {
303 const zo = ef.zigObjectPtr().?;303 const zo = ef.zigObjectPtr().?;
304 const atom = zo.symbol(atom_index).atom(ef).?;304 const atom = zo.symbol(@intFromEnum(atom_index)).atom(ef).?;
305 const r_type: std.elf.R_AARCH64 = switch (decoded.decode().register_unsigned_immediate.decode()) {305 const r_type: std.elf.R_AARCH64 = switch (decoded.decode().register_unsigned_immediate.decode()) {
306 .integer => |integer| switch (integer.decode()) {306 .integer => |integer| switch (integer.decode()) {
307 .unallocated, .prfm => unreachable,307 .unallocated, .prfm => unreachable,
...@@ -342,16 +342,16 @@ fn emitReloc(...@@ -342,16 +342,16 @@ fn emitReloc(
342 };342 };
343 try atom.addReloc(gpa, .{343 try atom.addReloc(gpa, .{
344 .r_offset = offset,344 .r_offset = offset,
345 .r_info = @as(u64, sym_index) << 32 | @intFromEnum(r_type),345 .r_info = @as(u64, @intFromEnum(sym_index)) << 32 | @intFromEnum(r_type),
346 .r_addend = @bitCast(addend),346 .r_addend = @bitCast(addend),
347 }, zo);347 }, zo);
348 } else if (lf.cast(.macho)) |mf| {348 } else if (lf.cast(.macho)) |mf| {
349 const zo = mf.getZigObject().?;349 const zo = mf.getZigObject().?;
350 const atom = zo.symbols.items[atom_index].getAtom(mf).?;350 const atom = zo.symbols.items[@intFromEnum(atom_index)].getAtom(mf).?;
351 try atom.addReloc(mf, .{351 try atom.addReloc(mf, .{
352 .tag = .@"extern",352 .tag = .@"extern",
353 .offset = offset,353 .offset = offset,
354 .target = sym_index,354 .target = @intFromEnum(sym_index),
355 .addend = @bitCast(addend),355 .addend = @bitCast(addend),
356 .type = switch (kind) {356 .type = switch (kind) {
357 .direct => .pageoff,357 .direct => .pageoff,
...@@ -361,7 +361,7 @@ fn emitReloc(...@@ -361,7 +361,7 @@ fn emitReloc(
361 .pcrel = false,361 .pcrel = false,
362 .has_subtractor = false,362 .has_subtractor = false,
363 .length = 2,363 .length = 2,
364 .symbolnum = @intCast(sym_index),364 .symbolnum = @intCast(@intFromEnum(sym_index)),
365 },365 },
366 });366 });
367 },367 },
src/codegen/riscv64/CodeGen.zig+13-13
...@@ -130,7 +130,7 @@ air_bookkeeping: @TypeOf(air_bookkeeping_init) = air_bookkeeping_init,...@@ -130,7 +130,7 @@ air_bookkeeping: @TypeOf(air_bookkeeping_init) = air_bookkeeping_init,
130130
131const air_bookkeeping_init = if (std.debug.runtime_safety) @as(usize, 0) else {};131const air_bookkeeping_init = if (std.debug.runtime_safety) @as(usize, 0) else {};
132132
133const SymbolOffset = struct { sym: u32, off: i32 = 0 };133const SymbolOffset = struct { sym: link.File.SymbolId, off: i32 = 0 };
134const RegisterOffset = struct { reg: Register, off: i32 = 0 };134const RegisterOffset = struct { reg: Register, off: i32 = 0 };
135pub const FrameAddr = struct { index: FrameIndex, off: i32 = 0 };135pub const FrameAddr = struct { index: FrameIndex, off: i32 = 0 };
136136
...@@ -166,7 +166,7 @@ const MCValue = union(enum) {...@@ -166,7 +166,7 @@ const MCValue = union(enum) {
166 dead: u32,166 dead: u32,
167 /// The value is undefined. Contains a symbol index to an undefined constant. Null means167 /// The value is undefined. Contains a symbol index to an undefined constant. Null means
168 /// set the undefined value via immediate instead of a load.168 /// set the undefined value via immediate instead of a load.
169 undef: ?u32,169 undef: ?link.File.SymbolId,
170 /// A pointer-sized integer that fits in a register.170 /// A pointer-sized integer that fits in a register.
171 /// If the type is a pointer, this is the pointer address in virtual address space.171 /// If the type is a pointer, this is the pointer address in virtual address space.
172 immediate: u64,172 immediate: u64,
...@@ -859,7 +859,7 @@ pub fn generateLazy(...@@ -859,7 +859,7 @@ pub fn generateLazy(
859 pt: Zcu.PerThread,859 pt: Zcu.PerThread,
860 src_loc: Zcu.LazySrcLoc,860 src_loc: Zcu.LazySrcLoc,
861 lazy_sym: link.File.LazySymbol,861 lazy_sym: link.File.LazySymbol,
862 atom_index: u32,862 atom_index: link.File.AtomId,
863 w: *std.Io.Writer,863 w: *std.Io.Writer,
864 debug_output: link.File.DebugInfoOutput,864 debug_output: link.File.DebugInfoOutput,
865) (CodeGenError || std.Io.Writer.Error)!void {865) (CodeGenError || std.Io.Writer.Error)!void {
...@@ -1305,7 +1305,7 @@ fn genLazy(func: *Func, lazy_sym: link.File.LazySymbol) InnerError!void {...@@ -1305,7 +1305,7 @@ fn genLazy(func: *Func, lazy_sym: link.File.LazySymbol) InnerError!void {
1305 }) catch |err|1305 }) catch |err|
1306 return func.fail("{s} creating lazy symbol", .{@errorName(err)});1306 return func.fail("{s} creating lazy symbol", .{@errorName(err)});
13071307
1308 try func.genSetReg(Type.u64, data_reg, .{ .lea_symbol = .{ .sym = sym_index } });1308 try func.genSetReg(Type.u64, data_reg, .{ .lea_symbol = .{ .sym = @enumFromInt(sym_index) } });
13091309
1310 const cmp_reg, const cmp_lock = try func.allocReg(.int);1310 const cmp_reg, const cmp_lock = try func.allocReg(.int);
1311 defer func.register_manager.unlockReg(cmp_lock);1311 defer func.register_manager.unlockReg(cmp_lock);
...@@ -3595,8 +3595,8 @@ fn airRuntimeNavPtr(func: *Func, inst: Air.Inst.Index) !void {...@@ -3595,8 +3595,8 @@ fn airRuntimeNavPtr(func: *Func, inst: Air.Inst.Index) !void {
3595 .tag = .pseudo_load_tlv,3595 .tag = .pseudo_load_tlv,
3596 .data = .{ .reloc = .{3596 .data = .{ .reloc = .{
3597 .register = dest_mcv.getReg().?,3597 .register = dest_mcv.getReg().?,
3598 .atom_index = try func.owner.getSymbolIndex(func),3598 .atom_index = @enumFromInt(try func.owner.getSymbolIndex(func)),
3599 .sym_index = tlv_sym_index,3599 .sym_index = @enumFromInt(tlv_sym_index),
3600 } },3600 } },
3601 });3601 });
3602 } else {3602 } else {
...@@ -3606,8 +3606,8 @@ fn airRuntimeNavPtr(func: *Func, inst: Air.Inst.Index) !void {...@@ -3606,8 +3606,8 @@ fn airRuntimeNavPtr(func: *Func, inst: Air.Inst.Index) !void {
3606 .tag = .pseudo_load_tlv,3606 .tag = .pseudo_load_tlv,
3607 .data = .{ .reloc = .{3607 .data = .{ .reloc = .{
3608 .register = tmp_reg,3608 .register = tmp_reg,
3609 .atom_index = try func.owner.getSymbolIndex(func),3609 .atom_index = @enumFromInt(try func.owner.getSymbolIndex(func)),
3610 .sym_index = tlv_sym_index,3610 .sym_index = @enumFromInt(tlv_sym_index),
3611 } },3611 } },
3612 });3612 });
3613 try func.genCopy(ptr_ty, dest_mcv, .{ .register = tmp_reg });3613 try func.genCopy(ptr_ty, dest_mcv, .{ .register = tmp_reg });
...@@ -4958,7 +4958,7 @@ fn genCall(...@@ -4958,7 +4958,7 @@ fn genCall(
4958 .func => |func_val| {4958 .func => |func_val| {
4959 if (func.bin_file.cast(.elf)) |elf_file| {4959 if (func.bin_file.cast(.elf)) |elf_file| {
4960 const zo = elf_file.zigObjectPtr().?;4960 const zo = elf_file.zigObjectPtr().?;
4961 const sym_index = try zo.getOrCreateMetadataForNav(zcu, func_val.owner_nav);4961 const sym_index: link.File.SymbolId = @enumFromInt(try zo.getOrCreateMetadataForNav(zcu, func_val.owner_nav));
49624962
4963 if (func.mod.pic) {4963 if (func.mod.pic) {
4964 return func.fail("TODO: genCall pic", .{});4964 return func.fail("TODO: genCall pic", .{});
...@@ -4978,7 +4978,7 @@ fn genCall(...@@ -4978,7 +4978,7 @@ fn genCall(
4978 .@"extern" => |@"extern"| {4978 .@"extern" => |@"extern"| {
4979 const lib_name = @"extern".lib_name.toSlice(&zcu.intern_pool);4979 const lib_name = @"extern".lib_name.toSlice(&zcu.intern_pool);
4980 const name = @"extern".name.toSlice(&zcu.intern_pool);4980 const name = @"extern".name.toSlice(&zcu.intern_pool);
4981 const atom_index = try func.owner.getSymbolIndex(func);4981 const atom_index: link.File.AtomId = @enumFromInt(try func.owner.getSymbolIndex(func));
49824982
4983 const elf_file = func.bin_file.cast(.elf).?;4983 const elf_file = func.bin_file.cast(.elf).?;
4984 _ = try func.addInst(.{4984 _ = try func.addInst(.{
...@@ -4986,7 +4986,7 @@ fn genCall(...@@ -4986,7 +4986,7 @@ fn genCall(
4986 .data = .{ .reloc = .{4986 .data = .{ .reloc = .{
4987 .register = .ra,4987 .register = .ra,
4988 .atom_index = atom_index,4988 .atom_index = atom_index,
4989 .sym_index = try elf_file.getGlobalSymbol(name, lib_name),4989 .sym_index = @enumFromInt(try elf_file.getGlobalSymbol(name, lib_name)),
4990 } },4990 } },
4991 });4991 });
4992 },4992 },
...@@ -6405,7 +6405,7 @@ fn airAsm(func: *Func, inst: Air.Inst.Index) !void {...@@ -6405,7 +6405,7 @@ fn airAsm(func: *Func, inst: Air.Inst.Index) !void {
6405 .tag = .pseudo_extern_fn_reloc,6405 .tag = .pseudo_extern_fn_reloc,
6406 .data = .{ .reloc = .{6406 .data = .{ .reloc = .{
6407 .register = random_link_reg,6407 .register = random_link_reg,
6408 .atom_index = try func.owner.getSymbolIndex(func),6408 .atom_index = @enumFromInt(try func.owner.getSymbolIndex(func)),
6409 .sym_index = sym_offset.sym,6409 .sym_index = sym_offset.sym,
6410 } },6410 } },
6411 });6411 });
...@@ -7036,7 +7036,7 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!...@@ -7036,7 +7036,7 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
7036 },7036 },
7037 .lea_symbol => |sym_off| {7037 .lea_symbol => |sym_off| {
7038 assert(sym_off.off == 0);7038 assert(sym_off.off == 0);
7039 const atom_index = try func.owner.getSymbolIndex(func);7039 const atom_index: link.File.AtomId = @enumFromInt(try func.owner.getSymbolIndex(func));
70407040
7041 _ = try func.addInst(.{7041 _ = try func.addInst(.{
7042 .tag = .pseudo_load_symbol,7042 .tag = .pseudo_load_symbol,
src/codegen/riscv64/Emit.zig+10-10
...@@ -47,8 +47,8 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -47,8 +47,8 @@ pub fn emitMir(emit: *Emit) Error!void {
47 const elf_file = emit.bin_file.cast(.elf).?;47 const elf_file = emit.bin_file.cast(.elf).?;
48 const zo = elf_file.zigObjectPtr().?;48 const zo = elf_file.zigObjectPtr().?;
4949
50 const atom_ptr = zo.symbol(symbol.atom_index).atom(elf_file).?;50 const atom_ptr = zo.symbol(@intFromEnum(symbol.atom_index)).atom(elf_file).?;
51 const sym = zo.symbol(symbol.sym_index);51 const sym = zo.symbol(@intFromEnum(symbol.sym_index));
5252
53 if (emit.lower.pic) {53 if (emit.lower.pic) {
54 return emit.fail("know when to emit GOT relocation for symbol '{s}'", .{sym.name(elf_file)});54 return emit.fail("know when to emit GOT relocation for symbol '{s}'", .{sym.name(elf_file)});
...@@ -59,13 +59,13 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -59,13 +59,13 @@ pub fn emitMir(emit: *Emit) Error!void {
5959
60 try atom_ptr.addReloc(gpa, .{60 try atom_ptr.addReloc(gpa, .{
61 .r_offset = start_offset,61 .r_offset = start_offset,
62 .r_info = (@as(u64, @intCast(symbol.sym_index)) << 32) | hi_r_type,62 .r_info = (@as(u64, @intFromEnum(symbol.sym_index)) << 32) | hi_r_type,
63 .r_addend = 0,63 .r_addend = 0,
64 }, zo);64 }, zo);
6565
66 try atom_ptr.addReloc(gpa, .{66 try atom_ptr.addReloc(gpa, .{
67 .r_offset = start_offset + 4,67 .r_offset = start_offset + 4,
68 .r_info = (@as(u64, @intCast(symbol.sym_index)) << 32) | lo_r_type,68 .r_info = (@as(u64, @intFromEnum(symbol.sym_index)) << 32) | lo_r_type,
69 .r_addend = 0,69 .r_addend = 0,
70 }, zo);70 }, zo);
71 },71 },
...@@ -73,38 +73,38 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -73,38 +73,38 @@ pub fn emitMir(emit: *Emit) Error!void {
73 const elf_file = emit.bin_file.cast(.elf).?;73 const elf_file = emit.bin_file.cast(.elf).?;
74 const zo = elf_file.zigObjectPtr().?;74 const zo = elf_file.zigObjectPtr().?;
7575
76 const atom_ptr = zo.symbol(symbol.atom_index).atom(elf_file).?;76 const atom_ptr = zo.symbol(@intFromEnum(symbol.atom_index)).atom(elf_file).?;
7777
78 const R_RISCV = std.elf.R_RISCV;78 const R_RISCV = std.elf.R_RISCV;
7979
80 try atom_ptr.addReloc(gpa, .{80 try atom_ptr.addReloc(gpa, .{
81 .r_offset = start_offset,81 .r_offset = start_offset,
82 .r_info = (@as(u64, @intCast(symbol.sym_index)) << 32) | @intFromEnum(R_RISCV.TPREL_HI20),82 .r_info = (@as(u64, @intFromEnum(symbol.sym_index)) << 32) | @intFromEnum(R_RISCV.TPREL_HI20),
83 .r_addend = 0,83 .r_addend = 0,
84 }, zo);84 }, zo);
8585
86 try atom_ptr.addReloc(gpa, .{86 try atom_ptr.addReloc(gpa, .{
87 .r_offset = start_offset + 4,87 .r_offset = start_offset + 4,
88 .r_info = (@as(u64, @intCast(symbol.sym_index)) << 32) | @intFromEnum(R_RISCV.TPREL_ADD),88 .r_info = (@as(u64, @intFromEnum(symbol.sym_index)) << 32) | @intFromEnum(R_RISCV.TPREL_ADD),
89 .r_addend = 0,89 .r_addend = 0,
90 }, zo);90 }, zo);
9191
92 try atom_ptr.addReloc(gpa, .{92 try atom_ptr.addReloc(gpa, .{
93 .r_offset = start_offset + 8,93 .r_offset = start_offset + 8,
94 .r_info = (@as(u64, @intCast(symbol.sym_index)) << 32) | @intFromEnum(R_RISCV.TPREL_LO12_I),94 .r_info = (@as(u64, @intFromEnum(symbol.sym_index)) << 32) | @intFromEnum(R_RISCV.TPREL_LO12_I),
95 .r_addend = 0,95 .r_addend = 0,
96 }, zo);96 }, zo);
97 },97 },
98 .call_extern_fn_reloc => |symbol| {98 .call_extern_fn_reloc => |symbol| {
99 const elf_file = emit.bin_file.cast(.elf).?;99 const elf_file = emit.bin_file.cast(.elf).?;
100 const zo = elf_file.zigObjectPtr().?;100 const zo = elf_file.zigObjectPtr().?;
101 const atom_ptr = zo.symbol(symbol.atom_index).atom(elf_file).?;101 const atom_ptr = zo.symbol(@intFromEnum(symbol.atom_index)).atom(elf_file).?;
102102
103 const r_type: u32 = @intFromEnum(std.elf.R_RISCV.CALL_PLT);103 const r_type: u32 = @intFromEnum(std.elf.R_RISCV.CALL_PLT);
104104
105 try atom_ptr.addReloc(gpa, .{105 try atom_ptr.addReloc(gpa, .{
106 .r_offset = start_offset,106 .r_offset = start_offset,
107 .r_info = (@as(u64, @intCast(symbol.sym_index)) << 32) | r_type,107 .r_info = (@as(u64, @intFromEnum(symbol.sym_index)) << 32) | r_type,
108 .r_addend = 0,108 .r_addend = 0,
109 }, zo);109 }, zo);
110 },110 },
src/codegen/riscv64/Mir.zig+5-5
...@@ -67,8 +67,8 @@ pub const Inst = struct {...@@ -67,8 +67,8 @@ pub const Inst = struct {
67 },67 },
68 reloc: struct {68 reloc: struct {
69 register: Register,69 register: Register,
70 atom_index: u32,70 atom_index: link.File.AtomId,
71 sym_index: u32,71 sym_index: link.File.SymbolId,
72 },72 },
73 fence: struct {73 fence: struct {
74 pred: Barrier,74 pred: Barrier,
...@@ -109,7 +109,7 @@ pub fn emit(...@@ -109,7 +109,7 @@ pub fn emit(
109 pt: Zcu.PerThread,109 pt: Zcu.PerThread,
110 src_loc: Zcu.LazySrcLoc,110 src_loc: Zcu.LazySrcLoc,
111 func_index: InternPool.Index,111 func_index: InternPool.Index,
112 atom_index: u32,112 atom_index: link.File.AtomId,
113 w: *std.Io.Writer,113 w: *std.Io.Writer,
114 debug_output: link.File.DebugInfoOutput,114 debug_output: link.File.DebugInfoOutput,
115) (codegen.CodeGenError || std.Io.Writer.Error)!void {115) (codegen.CodeGenError || std.Io.Writer.Error)!void {
...@@ -183,8 +183,8 @@ pub const FcvtOp = enum(u5) {...@@ -183,8 +183,8 @@ pub const FcvtOp = enum(u5) {
183183
184pub const LoadSymbolPayload = struct {184pub const LoadSymbolPayload = struct {
185 register: u32,185 register: u32,
186 atom_index: u32,186 atom_index: link.File.AtomId,
187 sym_index: u32,187 sym_index: link.File.SymbolId,
188};188};
189189
190/// Used in conjunction with payload to transfer a list of used registers in a compact manner.190/// Used in conjunction with payload to transfer a list of used registers in a compact manner.
src/codegen/riscv64/bits.zig+3-2
...@@ -4,6 +4,7 @@ const testing = std.testing;...@@ -4,6 +4,7 @@ const testing = std.testing;
4const Target = std.Target;4const Target = std.Target;
55
6const Zcu = @import("../../Zcu.zig");6const Zcu = @import("../../Zcu.zig");
7const link = @import("../../link.zig");
7const Mir = @import("Mir.zig");8const Mir = @import("Mir.zig");
8const abi = @import("abi.zig");9const abi = @import("abi.zig");
910
...@@ -260,9 +261,9 @@ pub const FrameIndex = enum(u32) {...@@ -260,9 +261,9 @@ pub const FrameIndex = enum(u32) {
260/// A linker symbol not yet allocated in VM.261/// A linker symbol not yet allocated in VM.
261pub const Symbol = struct {262pub const Symbol = struct {
262 /// Index of the containing atom.263 /// Index of the containing atom.
263 atom_index: u32,264 atom_index: link.File.AtomId,
264 /// Index into the linker's symbol table.265 /// Index into the linker's symbol table.
265 sym_index: u32,266 sym_index: link.File.SymbolId,
266};267};
267268
268pub const VType = packed struct(u8) {269pub const VType = packed struct(u8) {
src/codegen/sparc64/Mir.zig+1-1
...@@ -380,7 +380,7 @@ pub fn emit(...@@ -380,7 +380,7 @@ pub fn emit(
380 pt: Zcu.PerThread,380 pt: Zcu.PerThread,
381 src_loc: Zcu.LazySrcLoc,381 src_loc: Zcu.LazySrcLoc,
382 func_index: InternPool.Index,382 func_index: InternPool.Index,
383 atom_index: u32,383 atom_index: link.File.AtomId,
384 w: *std.Io.Writer,384 w: *std.Io.Writer,
385 debug_output: link.File.DebugInfoOutput,385 debug_output: link.File.DebugInfoOutput,
386) (codegen.CodeGenError || std.Io.Writer.Error)!void {386) (codegen.CodeGenError || std.Io.Writer.Error)!void {
src/codegen/x86_64/CodeGen.zig+2-2
...@@ -1029,7 +1029,7 @@ pub fn generateLazy(...@@ -1029,7 +1029,7 @@ pub fn generateLazy(
1029 pt: Zcu.PerThread,1029 pt: Zcu.PerThread,
1030 src_loc: Zcu.LazySrcLoc,1030 src_loc: Zcu.LazySrcLoc,
1031 lazy_sym: link.File.LazySymbol,1031 lazy_sym: link.File.LazySymbol,
1032 atom_index: u32,1032 atom_id: link.File.AtomId,
1033 w: *std.Io.Writer,1033 w: *std.Io.Writer,
1034 debug_output: link.File.DebugInfoOutput,1034 debug_output: link.File.DebugInfoOutput,
1035) codegen.CodeGenError!void {1035) codegen.CodeGenError!void {
...@@ -1073,7 +1073,7 @@ pub fn generateLazy(...@@ -1073,7 +1073,7 @@ pub fn generateLazy(
1073 else => |e| return e,1073 else => |e| return e,
1074 };1074 };
10751075
1076 try function.getTmpMir().emitLazy(bin_file, pt, src_loc, lazy_sym, atom_index, w, debug_output);1076 try function.getTmpMir().emitLazy(bin_file, pt, src_loc, lazy_sym, atom_id, w, debug_output);
1077}1077}
10781078
1079const FormatNavData = struct {1079const FormatNavData = struct {
src/codegen/x86_64/Emit.zig+133-134
...@@ -4,7 +4,7 @@ lower: Lower,...@@ -4,7 +4,7 @@ lower: Lower,
4bin_file: *link.File,4bin_file: *link.File,
5pt: Zcu.PerThread,5pt: Zcu.PerThread,
6pic: bool,6pic: bool,
7atom_index: u32,7atom_id: link.File.AtomId,
8debug_output: link.File.DebugInfoOutput,8debug_output: link.File.DebugInfoOutput,
9w: *std.Io.Writer,9w: *std.Io.Writer,
1010
...@@ -98,53 +98,48 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -98,53 +98,48 @@ pub fn emitMir(emit: *Emit) Error!void {
98 .op_index = lowered_relocs[0].op_index,98 .op_index = lowered_relocs[0].op_index,
99 .off = lowered_relocs[0].off,99 .off = lowered_relocs[0].off,
100 .target = target: switch (lowered_relocs[0].target) {100 .target = target: switch (lowered_relocs[0].target) {
101 .inst => |inst| .{ .index = inst, .is_extern = false, .type = .inst },101 .inst => |inst| .{ .inst = inst },
102 .table => .{ .index = undefined, .is_extern = false, .type = .table },102 .table => .table,
103 .nav => |nav| {103 .nav => |nav| {
104 const sym_index = switch (try codegen.genNavRef(104 const symbol_id = switch (try codegen.genNavRef(
105 emit.bin_file,105 emit.bin_file,
106 emit.pt,106 emit.pt,
107 emit.lower.src_loc,107 emit.lower.src_loc,
108 nav,108 nav,
109 emit.lower.target,109 emit.lower.target,
110 )) {110 )) {
111 .sym_index => |sym_index| sym_index,111 .sym_index => |symbol_id| symbol_id,
112 .fail => |em| {112 .fail => |em| {
113 assert(emit.lower.err_msg == null);113 assert(emit.lower.err_msg == null);
114 emit.lower.err_msg = em;114 emit.lower.err_msg = em;
115 return error.EmitFail;115 return error.EmitFail;
116 },116 },
117 };117 };
118 const resolved_nav = ip.getNav(nav).resolved.?;118 const target_symbol: RelocInfo.Target.Symbol = if (ip.getNav(nav).getExtern(ip)) |@"extern"| .{
119 if (resolved_nav.value != .none) switch (ip.indexToKey(resolved_nav.value)) {119 .symbol = symbol_id,
120 .@"extern" => |@"extern"| break :target .{120 .is_extern = switch (@"extern".visibility) {
121 .index = sym_index,121 .default => true,
122 .is_extern = switch (@"extern".visibility) {122 .hidden, .protected => false,
123 .default => true,
124 .hidden, .protected => false,
125 },
126 .type = if (resolved_nav.@"threadlocal" and comp.config.any_non_single_threaded) .tlv else .symbol,
127 .force_pcrel_direct = switch (@"extern".relocation) {
128 .any => false,
129 .pcrel => true,
130 },
131 },123 },
132 else => {},124 .force_pcrel_direct = switch (@"extern".relocation) {
133 };125 .any => false,
134 break :target .{126 .pcrel => true,
135 .index = sym_index,127 },
136 .is_extern = false,128 } else .{ .symbol = symbol_id, .is_extern = false };
137 .type = if (resolved_nav.@"threadlocal" and comp.config.any_non_single_threaded) .tlv else .symbol,129 if (ip.getNav(nav).resolved.?.@"threadlocal" and comp.config.any_non_single_threaded) {
138 };130 break :target .{ .tlv = target_symbol };
131 } else {
132 break :target .{ .symbol = target_symbol };
133 }
139 },134 },
140 .uav => |uav| .{135 .uav => |uav| .{ .symbol = .{
141 .index = switch (try emit.bin_file.lowerUav(136 .symbol = switch (try emit.bin_file.lowerUav(
142 emit.pt,137 emit.pt,
143 uav.val,138 uav.val,
144 Type.fromInterned(uav.orig_ty).ptrAlignment(emit.pt.zcu),139 Type.fromInterned(uav.orig_ty).ptrAlignment(emit.pt.zcu),
145 emit.lower.src_loc,140 emit.lower.src_loc,
146 )) {141 )) {
147 .sym_index => |sym_index| sym_index,142 .sym_index => |symbol_id| symbol_id,
148 .fail => |em| {143 .fail => |em| {
149 assert(emit.lower.err_msg == null);144 assert(emit.lower.err_msg == null);
150 emit.lower.err_msg = em;145 emit.lower.err_msg = em;
...@@ -152,55 +147,57 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -152,55 +147,57 @@ pub fn emitMir(emit: *Emit) Error!void {
152 },147 },
153 },148 },
154 .is_extern = false,149 .is_extern = false,
155 .type = .symbol,150 } },
156 },151 .lazy_sym => |lazy_sym| .{ .symbol = .{
157 .lazy_sym => |lazy_sym| .{152 .symbol = if (emit.bin_file.cast(.elf)) |elf_file|
158 .index = if (emit.bin_file.cast(.elf)) |elf_file|153 @enumFromInt(
159 elf_file.zigObjectPtr().?.getOrCreateMetadataForLazySymbol(elf_file, emit.pt, lazy_sym) catch |err|154 elf_file.zigObjectPtr().?.getOrCreateMetadataForLazySymbol(elf_file, emit.pt, lazy_sym) catch |err|
160 return emit.fail("{s} creating lazy symbol", .{@errorName(err)})155 return emit.fail("{s} creating lazy symbol", .{@errorName(err)}),
156 )
161 else if (emit.bin_file.cast(.elf2)) |elf|157 else if (emit.bin_file.cast(.elf2)) |elf|
162 @intFromEnum(try elf.lazySymbol(lazy_sym))158 try elf.lazySymbol(lazy_sym)
163 else if (emit.bin_file.cast(.macho)) |macho_file|159 else if (emit.bin_file.cast(.macho)) |macho_file|
164 macho_file.getZigObject().?.getOrCreateMetadataForLazySymbol(macho_file, emit.pt, lazy_sym) catch |err|160 @enumFromInt(macho_file.getZigObject().?.getOrCreateMetadataForLazySymbol(macho_file, emit.pt, lazy_sym) catch |err|
165 return emit.fail("{s} creating lazy symbol", .{@errorName(err)})161 return emit.fail("{s} creating lazy symbol", .{@errorName(err)}))
166 else if (emit.bin_file.cast(.coff2)) |elf|162 else if (emit.bin_file.cast(.coff2)) |coff|
167 @intFromEnum(try elf.lazySymbol(lazy_sym))163 @enumFromInt(@intFromEnum(try coff.lazySymbol(lazy_sym)))
168 else164 else
169 return emit.fail("lazy symbols unimplemented for {s}", .{@tagName(emit.bin_file.tag)}),165 return emit.fail("lazy symbols unimplemented for {s}", .{@tagName(emit.bin_file.tag)}),
170 .is_extern = false,166 .is_extern = false,
171 .type = .symbol,167 } },
172 },168 .extern_func => |extern_func| .{ .symbol = .{
173 .extern_func => |extern_func| .{169 .symbol = if (emit.bin_file.cast(.elf)) |elf_file|
174 .index = if (emit.bin_file.cast(.elf)) |elf_file|170 @enumFromInt(try elf_file.getGlobalSymbol(extern_func.toSlice(&emit.lower.mir).?, null))
175 try elf_file.getGlobalSymbol(extern_func.toSlice(&emit.lower.mir).?, null)171 else if (emit.bin_file.cast(.elf2)) |elf| elf.externSymbol(.{
176 else if (emit.bin_file.cast(.elf2)) |elf| @intFromEnum(try elf.globalSymbol(.{
177 .name = extern_func.toSlice(&emit.lower.mir).?,172 .name = extern_func.toSlice(&emit.lower.mir).?,
178 .lib_name = switch (comp.compiler_rt_strat) {173 .lib_name = switch (comp.compiler_rt_strat) {
179 .none, .lib, .obj, .zcu => null,174 .none, .lib, .obj, .zcu => null,
180 .dyn_lib => "compiler_rt",175 .dyn_lib => "compiler_rt",
181 },176 },
182 .type = .FUNC,177 .type = .FUNC,
183 })) else if (emit.bin_file.cast(.macho)) |macho_file|178 }) catch |err| switch (err) {
184 try macho_file.getGlobalSymbol(extern_func.toSlice(&emit.lower.mir).?, null)179 error.LinkOnceUnsupported => unreachable,
185 else if (emit.bin_file.cast(.coff2)) |coff| @intFromEnum(try coff.globalSymbol(180 else => |e| return e,
181 } else if (emit.bin_file.cast(.macho)) |macho_file|
182 @enumFromInt(try macho_file.getGlobalSymbol(extern_func.toSlice(&emit.lower.mir).?, null))
183 else if (emit.bin_file.cast(.coff2)) |coff| @enumFromInt(@intFromEnum(try coff.globalSymbol(
186 extern_func.toSlice(&emit.lower.mir).?,184 extern_func.toSlice(&emit.lower.mir).?,
187 switch (comp.compiler_rt_strat) {185 switch (comp.compiler_rt_strat) {
188 .none, .lib, .obj, .zcu => null,186 .none, .lib, .obj, .zcu => null,
189 .dyn_lib => "compiler_rt",187 .dyn_lib => "compiler_rt",
190 },188 },
191 )) else return emit.fail("external symbol unimplemented for {s}", .{@tagName(emit.bin_file.tag)}),189 ))) else return emit.fail("external symbol unimplemented for {s}", .{@tagName(emit.bin_file.tag)}),
192 .is_extern = true,190 .is_extern = true,
193 .type = .symbol,191 } },
194 },
195 },192 },
196 };193 };
197 const reloc_info = reloc_info_buf[0..reloc_info_index];194 const reloc_info = reloc_info_buf[0..reloc_info_index];
198 for (reloc_info) |*reloc| switch (reloc.target.type) {195 for (reloc_info) |*reloc| switch (reloc.target) {
199 .inst, .table => {},196 .inst, .table => {},
200 .symbol => {197 .symbol => |target| {
201 switch (lowered_inst.encoding.mnemonic) {198 switch (lowered_inst.encoding.mnemonic) {
202 .call => {199 .call => {
203 reloc.target.type = .branch;200 reloc.target = .{ .branch = target };
204 try emit.encodeInst(lowered_inst, reloc_info);201 try emit.encodeInst(lowered_inst, reloc_info);
205 continue :lowered_inst;202 continue :lowered_inst;
206 },203 },
...@@ -217,7 +214,7 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -217,7 +214,7 @@ pub fn emitMir(emit: *Emit) Error!void {
217 .{ .mem = .initSib(lowered_inst.ops[reloc.op_index].mem.sib.ptr_size, .{}) },214 .{ .mem = .initSib(lowered_inst.ops[reloc.op_index].mem.sib.ptr_size, .{}) },
218 }, emit.lower.target), reloc_info),215 }, emit.lower.target), reloc_info),
219 else => unreachable,216 else => unreachable,
220 } else if (reloc.target.is_extern) switch (lowered_inst.encoding.mnemonic) {217 } else if (target.is_extern) switch (lowered_inst.encoding.mnemonic) {
221 .lea => try emit.encodeInst(try .new(.none, .mov, &.{218 .lea => try emit.encodeInst(try .new(.none, .mov, &.{
222 lowered_inst.ops[0],219 lowered_inst.ops[0],
223 .{ .mem = .initRip(.ptr, 0) },220 .{ .mem = .initRip(.ptr, 0) },
...@@ -247,7 +244,7 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -247,7 +244,7 @@ pub fn emitMir(emit: *Emit) Error!void {
247 else => unreachable,244 else => unreachable,
248 }245 }
249 } else if (emit.bin_file.cast(.macho)) |_| {246 } else if (emit.bin_file.cast(.macho)) |_| {
250 if (reloc.target.is_extern) switch (lowered_inst.encoding.mnemonic) {247 if (target.is_extern) switch (lowered_inst.encoding.mnemonic) {
251 .lea => try emit.encodeInst(try .new(.none, .mov, &.{248 .lea => try emit.encodeInst(try .new(.none, .mov, &.{
252 lowered_inst.ops[0],249 lowered_inst.ops[0],
253 .{ .mem = .initRip(.ptr, 0) },250 .{ .mem = .initRip(.ptr, 0) },
...@@ -294,7 +291,7 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -294,7 +291,7 @@ pub fn emitMir(emit: *Emit) Error!void {
294 continue :lowered_inst;291 continue :lowered_inst;
295 },292 },
296 .branch, .tls => unreachable,293 .branch, .tls => unreachable,
297 .tlv => {294 .tlv => |target| {
298 if (emit.bin_file.cast(.elf) != null or emit.bin_file.cast(.elf2) != null) {295 if (emit.bin_file.cast(.elf) != null or emit.bin_file.cast(.elf2) != null) {
299 // TODO handle extern TLS vars, i.e., emit GD model296 // TODO handle extern TLS vars, i.e., emit GD model
300 if (emit.pic) switch (lowered_inst.encoding.mnemonic) {297 if (emit.pic) switch (lowered_inst.encoding.mnemonic) {
...@@ -306,28 +303,26 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -306,28 +303,26 @@ pub fn emitMir(emit: *Emit) Error!void {
306 .{ .mem = .initRip(.none, 0) },303 .{ .mem = .initRip(.none, 0) },
307 }, emit.lower.target), &.{.{304 }, emit.lower.target), &.{.{
308 .op_index = 1,305 .op_index = 1,
309 .target = .{306 .target = .{ .tls = target.symbol },
310 .index = reloc.target.index,
311 .is_extern = false,
312 .type = .tls,
313 },
314 }});307 }});
315 try emit.encodeInst(try .new(.none, .call, &.{308 try emit.encodeInst(try .new(.none, .call, &.{
316 .{ .imm = .s(0) },309 .{ .imm = .s(0) },
317 }, emit.lower.target), &.{.{310 }, emit.lower.target), &.{.{
318 .op_index = 0,311 .op_index = 0,
319 .target = .{312 .target = .{ .branch = .{
320 .index = if (emit.bin_file.cast(.elf)) |elf_file| try elf_file.getGlobalSymbol(313 .symbol = if (emit.bin_file.cast(.elf)) |elf_file| @enumFromInt(try elf_file.getGlobalSymbol(
321 "__tls_get_addr",314 "__tls_get_addr",
322 if (comp.config.link_libc) "c" else null,315 if (comp.config.link_libc) "c" else null,
323 ) else if (emit.bin_file.cast(.elf2)) |elf| @intFromEnum(try elf.globalSymbol(.{316 )) else if (emit.bin_file.cast(.elf2)) |elf| elf.externSymbol(.{
324 .name = "__tls_get_addr",317 .name = "__tls_get_addr",
325 .lib_name = if (comp.config.link_libc) "c" else null,318 .lib_name = if (comp.config.link_libc) "c" else null,
326 .type = .FUNC,319 .type = .FUNC,
327 })) else unreachable,320 }) catch |err| switch (err) {
321 error.LinkOnceUnsupported => unreachable,
322 else => |e| return e,
323 } else unreachable,
328 .is_extern = true,324 .is_extern = true,
329 .type = .branch,325 } },
330 },
331 }});326 }});
332 try emit.encodeInst(try .new(.none, lowered_inst.encoding.mnemonic, &.{327 try emit.encodeInst(try .new(.none, lowered_inst.encoding.mnemonic, &.{
333 lowered_inst.ops[0],328 lowered_inst.ops[0],
...@@ -399,13 +394,12 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -399,13 +394,12 @@ pub fn emitMir(emit: *Emit) Error!void {
399 .{ .mem = .initSib(.dword, .{}) },394 .{ .mem = .initSib(.dword, .{}) },
400 }, emit.lower.target), &.{.{395 }, emit.lower.target), &.{.{
401 .op_index = 1,396 .op_index = 1,
402 .target = .{397 .target = .{ .symbol = .{
403 .index = @intFromEnum(398 .symbol = @enumFromInt(@intFromEnum(
404 try coff.globalSymbol("__tls_index", null),399 try coff.globalSymbol("__tls_index", null),
405 ),400 )),
406 .is_extern = false,401 .is_extern = false,
407 .type = .symbol,402 } },
408 },
409 }});403 }});
410 try emit.encodeInst(try .new(.none, .mov, &.{404 try emit.encodeInst(try .new(.none, .mov, &.{
411 .{ .reg = .eax },405 .{ .reg = .eax },
...@@ -435,13 +429,12 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -435,13 +429,12 @@ pub fn emitMir(emit: *Emit) Error!void {
435 .{ .mem = .initRip(.dword, 0) },429 .{ .mem = .initRip(.dword, 0) },
436 }, emit.lower.target), &.{.{430 }, emit.lower.target), &.{.{
437 .op_index = 1,431 .op_index = 1,
438 .target = .{432 .target = .{ .symbol = .{
439 .index = @intFromEnum(433 .symbol = @enumFromInt(@intFromEnum(
440 try coff.globalSymbol("_tls_index", null),434 try coff.globalSymbol("_tls_index", null),
441 ),435 )),
442 .is_extern = false,436 .is_extern = false,
443 .type = .symbol,437 } },
444 },
445 }});438 }});
446 try emit.encodeInst(try .new(.none, .mov, &.{439 try emit.encodeInst(try .new(.none, .mov, &.{
447 .{ .reg = .rax },440 .{ .reg = .rax },
...@@ -713,17 +706,17 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -713,17 +706,17 @@ pub fn emitMir(emit: *Emit) Error!void {
713 var table_offset = std.mem.alignForward(u32, @intCast(emit.w.end), ptr_size);706 var table_offset = std.mem.alignForward(u32, @intCast(emit.w.end), ptr_size);
714 if (emit.bin_file.cast(.elf)) |elf_file| {707 if (emit.bin_file.cast(.elf)) |elf_file| {
715 const zo = elf_file.zigObjectPtr().?;708 const zo = elf_file.zigObjectPtr().?;
716 const atom = zo.symbol(emit.atom_index).atom(elf_file).?;709 const atom = zo.symbol(@intFromEnum(emit.atom_id)).atom(elf_file).?;
717710
718 for (emit.table_relocs.items) |table_reloc| try atom.addReloc(gpa, .{711 for (emit.table_relocs.items) |table_reloc| try atom.addReloc(gpa, .{
719 .r_offset = table_reloc.source_offset,712 .r_offset = table_reloc.source_offset,
720 .r_info = @as(u64, emit.atom_index) << 32 | @intFromEnum(std.elf.R_X86_64.@"32S"),713 .r_info = @as(u64, @intFromEnum(emit.atom_id)) << 32 | @intFromEnum(std.elf.R_X86_64.@"32S"),
721 .r_addend = @as(i64, table_offset) + table_reloc.target_offset,714 .r_addend = @as(i64, table_offset) + table_reloc.target_offset,
722 }, zo);715 }, zo);
723 for (emit.lower.mir.table) |entry| {716 for (emit.lower.mir.table) |entry| {
724 try atom.addReloc(gpa, .{717 try atom.addReloc(gpa, .{
725 .r_offset = table_offset,718 .r_offset = table_offset,
726 .r_info = @as(u64, emit.atom_index) << 32 | @intFromEnum(std.elf.R_X86_64.@"64"),719 .r_info = @as(u64, @intFromEnum(emit.atom_id)) << 32 | @intFromEnum(std.elf.R_X86_64.@"64"),
727 .r_addend = emit.code_offset_mapping.items[entry],720 .r_addend = emit.code_offset_mapping.items[entry],
728 }, zo);721 }, zo);
729 table_offset += ptr_size;722 table_offset += ptr_size;
...@@ -731,17 +724,17 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -731,17 +724,17 @@ pub fn emitMir(emit: *Emit) Error!void {
731 try emit.w.splatByteAll(0, table_offset - emit.w.end);724 try emit.w.splatByteAll(0, table_offset - emit.w.end);
732 } else if (emit.bin_file.cast(.elf2)) |elf| {725 } else if (emit.bin_file.cast(.elf2)) |elf| {
733 for (emit.table_relocs.items) |table_reloc| try elf.addReloc(726 for (emit.table_relocs.items) |table_reloc| try elf.addReloc(
734 @enumFromInt(emit.atom_index),727 emit.atom_id,
735 table_reloc.source_offset,728 table_reloc.source_offset,
736 @enumFromInt(emit.atom_index),729 elf.symbolForAtom(emit.atom_id),
737 @as(i64, table_offset) + table_reloc.target_offset,730 @as(i64, table_offset) + table_reloc.target_offset,
738 .{ .X86_64 = .@"32S" },731 .{ .X86_64 = .@"32S" },
739 );732 );
740 for (emit.lower.mir.table) |entry| {733 for (emit.lower.mir.table) |entry| {
741 try elf.addReloc(734 try elf.addReloc(
742 @enumFromInt(emit.atom_index),735 emit.atom_id,
743 table_offset,736 table_offset,
744 @enumFromInt(emit.atom_index),737 elf.symbolForAtom(emit.atom_id),
745 emit.code_offset_mapping.items[entry],738 emit.code_offset_mapping.items[entry],
746 .{ .X86_64 = .@"64" },739 .{ .X86_64 = .@"64" },
747 );740 );
...@@ -765,13 +758,19 @@ const RelocInfo = struct {...@@ -765,13 +758,19 @@ const RelocInfo = struct {
765 off: i32 = 0,758 off: i32 = 0,
766 target: Target,759 target: Target,
767760
768 const Target = struct {761 const Target = union(enum) {
769 index: u32,762 inst: Mir.Inst.Index,
770 is_extern: bool,763 table,
771 type: Target.Type,764 branch: Symbol,
772 force_pcrel_direct: bool = false,765 symbol: Symbol,
766 tlv: Symbol,
767 tls: link.File.SymbolId,
773768
774 const Type = enum { inst, table, symbol, branch, tls, tlv };769 const Symbol = struct {
770 symbol: link.File.SymbolId,
771 is_extern: bool,
772 force_pcrel_direct: bool = false,
773 };
775 };774 };
776};775};
777776
...@@ -784,8 +783,8 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI...@@ -784,8 +783,8 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI
784 else => |e| return e,783 else => |e| return e,
785 };784 };
786 const end_offset: u32 = @intCast(emit.w.end);785 const end_offset: u32 = @intCast(emit.w.end);
787 for (reloc_info) |reloc| switch (reloc.target.type) {786 for (reloc_info) |reloc| switch (reloc.target) {
788 .inst => {787 .inst => |target_inst| {
789 const inst_length: u4 = @intCast(end_offset - start_offset);788 const inst_length: u4 = @intCast(end_offset - start_offset);
790 const reloc_offset, const reloc_length = reloc_offset_length: {789 const reloc_offset, const reloc_length = reloc_offset_length: {
791 var reloc_offset = inst_length;790 var reloc_offset = inst_length;
...@@ -809,7 +808,7 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI...@@ -809,7 +808,7 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI
809 .inst_length = inst_length,808 .inst_length = inst_length,
810 .source_offset = reloc_offset,809 .source_offset = reloc_offset,
811 .source_length = reloc_length,810 .source_length = reloc_length,
812 .target = reloc.target.index,811 .target = target_inst,
813 .target_offset = reloc.off,812 .target_offset = reloc.off,
814 });813 });
815 },814 },
...@@ -817,146 +816,146 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI...@@ -817,146 +816,146 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI
817 .source_offset = end_offset - 4,816 .source_offset = end_offset - 4,
818 .target_offset = reloc.off,817 .target_offset = reloc.off,
819 }),818 }),
820 .symbol => if (emit.bin_file.cast(.elf)) |elf_file| {819 .symbol => |target| if (emit.bin_file.cast(.elf)) |elf_file| {
821 const zo = elf_file.zigObjectPtr().?;820 const zo = elf_file.zigObjectPtr().?;
822 const atom = zo.symbol(emit.atom_index).atom(elf_file).?;821 const atom = zo.symbol(@intFromEnum(emit.atom_id)).atom(elf_file).?;
823 const r_type: std.elf.R_X86_64 = if (!emit.pic)822 const r_type: std.elf.R_X86_64 = if (!emit.pic)
824 .@"32S"823 .@"32S"
825 else if (reloc.target.is_extern and !reloc.target.force_pcrel_direct)824 else if (target.is_extern and !target.force_pcrel_direct)
826 .GOTPCREL825 .GOTPCREL
827 else826 else
828 .PC32;827 .PC32;
829 try atom.addReloc(gpa, .{828 try atom.addReloc(gpa, .{
830 .r_offset = end_offset - 4,829 .r_offset = end_offset - 4,
831 .r_info = @as(u64, reloc.target.index) << 32 | @intFromEnum(r_type),830 .r_info = @as(u64, @intFromEnum(target.symbol)) << 32 | @intFromEnum(r_type),
832 .r_addend = if (emit.pic) reloc.off - 4 else reloc.off,831 .r_addend = if (emit.pic) reloc.off - 4 else reloc.off,
833 }, zo);832 }, zo);
834 } else if (emit.bin_file.cast(.macho)) |macho_file| {833 } else if (emit.bin_file.cast(.macho)) |macho_file| {
835 const zo = macho_file.getZigObject().?;834 const zo = macho_file.getZigObject().?;
836 const atom = zo.symbols.items[emit.atom_index].getAtom(macho_file).?;835 const atom = zo.symbols.items[@intFromEnum(emit.atom_id)].getAtom(macho_file).?;
837 try atom.addReloc(macho_file, .{836 try atom.addReloc(macho_file, .{
838 .tag = .@"extern",837 .tag = .@"extern",
839 .offset = end_offset - 4,838 .offset = end_offset - 4,
840 .target = reloc.target.index,839 .target = @intFromEnum(target.symbol),
841 .addend = reloc.off,840 .addend = reloc.off,
842 .type = if (reloc.target.is_extern and !reloc.target.force_pcrel_direct) .got_load else .signed,841 .type = if (target.is_extern and !target.force_pcrel_direct) .got_load else .signed,
843 .meta = .{842 .meta = .{
844 .pcrel = true,843 .pcrel = true,
845 .has_subtractor = false,844 .has_subtractor = false,
846 .length = 2,845 .length = 2,
847 .symbolnum = @intCast(reloc.target.index),846 .symbolnum = @intCast(@intFromEnum(target.symbol)),
848 },847 },
849 });848 });
850 } else if (emit.bin_file.cast(.elf2)) |elf| try elf.addReloc(849 } else if (emit.bin_file.cast(.elf2)) |elf| try elf.addReloc(
851 @enumFromInt(emit.atom_index),850 emit.atom_id,
852 end_offset - 4,851 end_offset - 4,
853 @enumFromInt(reloc.target.index),852 target.symbol,
854 reloc.off,853 reloc.off,
855 .{ .X86_64 = .@"32S" },854 .{ .X86_64 = .@"32S" },
856 ) else if (emit.bin_file.cast(.coff2)) |coff| try coff.addReloc(855 ) else if (emit.bin_file.cast(.coff2)) |coff| try coff.addReloc(
857 @enumFromInt(emit.atom_index),856 @enumFromInt(@intFromEnum(emit.atom_id)),
858 end_offset - 4,857 end_offset - 4,
859 @enumFromInt(reloc.target.index),858 @enumFromInt(@intFromEnum(target.symbol)),
860 reloc.off,859 reloc.off,
861 .{ .AMD64 = .REL32 },860 .{ .AMD64 = .REL32 },
862 ) else unreachable,861 ) else unreachable,
863 .branch => if (emit.bin_file.cast(.elf)) |elf_file| {862 .branch => |target| if (emit.bin_file.cast(.elf)) |elf_file| {
864 const zo = elf_file.zigObjectPtr().?;863 const zo = elf_file.zigObjectPtr().?;
865 const atom = zo.symbol(emit.atom_index).atom(elf_file).?;864 const atom = zo.symbol(@intFromEnum(emit.atom_id)).atom(elf_file).?;
866 const r_type: std.elf.R_X86_64 = .PLT32;865 const r_type: std.elf.R_X86_64 = .PLT32;
867 try atom.addReloc(gpa, .{866 try atom.addReloc(gpa, .{
868 .r_offset = end_offset - 4,867 .r_offset = end_offset - 4,
869 .r_info = @as(u64, reloc.target.index) << 32 | @intFromEnum(r_type),868 .r_info = @as(u64, @intFromEnum(target.symbol)) << 32 | @intFromEnum(r_type),
870 .r_addend = reloc.off - 4,869 .r_addend = reloc.off - 4,
871 }, zo);870 }, zo);
872 } else if (emit.bin_file.cast(.elf2)) |elf| try elf.addReloc(871 } else if (emit.bin_file.cast(.elf2)) |elf| try elf.addReloc(
873 @enumFromInt(emit.atom_index),872 emit.atom_id,
874 end_offset - 4,873 end_offset - 4,
875 @enumFromInt(reloc.target.index),874 target.symbol,
876 reloc.off - 4,875 reloc.off - 4,
877 .{ .X86_64 = .PLT32 },876 .{ .X86_64 = .PLT32 },
878 ) else if (emit.bin_file.cast(.macho)) |macho_file| {877 ) else if (emit.bin_file.cast(.macho)) |macho_file| {
879 const zo = macho_file.getZigObject().?;878 const zo = macho_file.getZigObject().?;
880 const atom = zo.symbols.items[emit.atom_index].getAtom(macho_file).?;879 const atom = zo.symbols.items[@intFromEnum(emit.atom_id)].getAtom(macho_file).?;
881 try atom.addReloc(macho_file, .{880 try atom.addReloc(macho_file, .{
882 .tag = .@"extern",881 .tag = .@"extern",
883 .offset = end_offset - 4,882 .offset = end_offset - 4,
884 .target = reloc.target.index,883 .target = @intFromEnum(target.symbol),
885 .addend = reloc.off,884 .addend = reloc.off,
886 .type = .branch,885 .type = .branch,
887 .meta = .{886 .meta = .{
888 .pcrel = true,887 .pcrel = true,
889 .has_subtractor = false,888 .has_subtractor = false,
890 .length = 2,889 .length = 2,
891 .symbolnum = @intCast(reloc.target.index),890 .symbolnum = @intCast(@intFromEnum(target.symbol)),
892 },891 },
893 });892 });
894 } else if (emit.bin_file.cast(.coff2)) |coff| try coff.addReloc(893 } else if (emit.bin_file.cast(.coff2)) |coff| try coff.addReloc(
895 @enumFromInt(emit.atom_index),894 @enumFromInt(@intFromEnum(emit.atom_id)),
896 end_offset - 4,895 end_offset - 4,
897 @enumFromInt(reloc.target.index),896 @enumFromInt(@intFromEnum(target.symbol)),
898 reloc.off,897 reloc.off,
899 .{ .AMD64 = .REL32 },898 .{ .AMD64 = .REL32 },
900 ) else return emit.fail("TODO implement {s} reloc for {s}", .{899 ) else return emit.fail("TODO implement {s} reloc for {s}", .{
901 @tagName(reloc.target.type), @tagName(emit.bin_file.tag),900 @tagName(reloc.target), @tagName(emit.bin_file.tag),
902 }),901 }),
903 .tls => if (emit.bin_file.cast(.elf)) |elf_file| {902 .tls => |target_symbol| if (emit.bin_file.cast(.elf)) |elf_file| {
904 const zo = elf_file.zigObjectPtr().?;903 const zo = elf_file.zigObjectPtr().?;
905 const atom = zo.symbol(emit.atom_index).atom(elf_file).?;904 const atom = zo.symbol(@intFromEnum(emit.atom_id)).atom(elf_file).?;
906 const r_type: std.elf.R_X86_64 = if (emit.pic) .TLSLD else unreachable;905 const r_type: std.elf.R_X86_64 = if (emit.pic) .TLSLD else unreachable;
907 try atom.addReloc(gpa, .{906 try atom.addReloc(gpa, .{
908 .r_offset = end_offset - 4,907 .r_offset = end_offset - 4,
909 .r_info = @as(u64, reloc.target.index) << 32 | @intFromEnum(r_type),908 .r_info = @as(u64, @intFromEnum(target_symbol)) << 32 | @intFromEnum(r_type),
910 .r_addend = reloc.off - 4,909 .r_addend = reloc.off - 4,
911 }, zo);910 }, zo);
912 } else if (emit.bin_file.cast(.elf2)) |elf| try elf.addReloc(911 } else if (emit.bin_file.cast(.elf2)) |elf| try elf.addReloc(
913 @enumFromInt(emit.atom_index),912 emit.atom_id,
914 end_offset - 4,913 end_offset - 4,
915 @enumFromInt(reloc.target.index),914 target_symbol,
916 reloc.off - 4,915 reloc.off - 4,
917 .{ .X86_64 = if (emit.pic) .TLSLD else unreachable },916 .{ .X86_64 = if (emit.pic) .TLSLD else unreachable },
918 ) else return emit.fail("TODO implement {s} reloc for {s}", .{917 ) else return emit.fail("TODO implement {s} reloc for {s}", .{
919 @tagName(reloc.target.type), @tagName(emit.bin_file.tag),918 @tagName(reloc.target), @tagName(emit.bin_file.tag),
920 }),919 }),
921 .tlv => if (emit.bin_file.cast(.elf)) |elf_file| {920 .tlv => |target| if (emit.bin_file.cast(.elf)) |elf_file| {
922 const zo = elf_file.zigObjectPtr().?;921 const zo = elf_file.zigObjectPtr().?;
923 const atom = zo.symbol(emit.atom_index).atom(elf_file).?;922 const atom = zo.symbol(@intFromEnum(emit.atom_id)).atom(elf_file).?;
924 const r_type: std.elf.R_X86_64 = if (emit.pic) .DTPOFF32 else .TPOFF32;923 const r_type: std.elf.R_X86_64 = if (emit.pic) .DTPOFF32 else .TPOFF32;
925 try atom.addReloc(gpa, .{924 try atom.addReloc(gpa, .{
926 .r_offset = end_offset - 4,925 .r_offset = end_offset - 4,
927 .r_info = @as(u64, reloc.target.index) << 32 | @intFromEnum(r_type),926 .r_info = @as(u64, @intFromEnum(target.symbol)) << 32 | @intFromEnum(r_type),
928 .r_addend = reloc.off,927 .r_addend = reloc.off,
929 }, zo);928 }, zo);
930 } else if (emit.bin_file.cast(.elf2)) |elf| try elf.addReloc(929 } else if (emit.bin_file.cast(.elf2)) |elf| try elf.addReloc(
931 @enumFromInt(emit.atom_index),930 emit.atom_id,
932 end_offset - 4,931 end_offset - 4,
933 @enumFromInt(reloc.target.index),932 target.symbol,
934 reloc.off,933 reloc.off,
935 .{ .X86_64 = if (emit.pic) .DTPOFF32 else .TPOFF32 },934 .{ .X86_64 = if (emit.pic) .DTPOFF32 else .TPOFF32 },
936 ) else if (emit.bin_file.cast(.macho)) |macho_file| {935 ) else if (emit.bin_file.cast(.macho)) |macho_file| {
937 const zo = macho_file.getZigObject().?;936 const zo = macho_file.getZigObject().?;
938 const atom = zo.symbols.items[emit.atom_index].getAtom(macho_file).?;937 const atom = zo.symbols.items[@intFromEnum(emit.atom_id)].getAtom(macho_file).?;
939 try atom.addReloc(macho_file, .{938 try atom.addReloc(macho_file, .{
940 .tag = .@"extern",939 .tag = .@"extern",
941 .offset = end_offset - 4,940 .offset = end_offset - 4,
942 .target = reloc.target.index,941 .target = @intFromEnum(target.symbol),
943 .addend = reloc.off,942 .addend = reloc.off,
944 .type = .tlv,943 .type = .tlv,
945 .meta = .{944 .meta = .{
946 .pcrel = true,945 .pcrel = true,
947 .has_subtractor = false,946 .has_subtractor = false,
948 .length = 2,947 .length = 2,
949 .symbolnum = @intCast(reloc.target.index),948 .symbolnum = @intCast(@intFromEnum(target.symbol)),
950 },949 },
951 });950 });
952 } else if (emit.bin_file.cast(.coff2)) |coff| try coff.addReloc(951 } else if (emit.bin_file.cast(.coff2)) |coff| try coff.addReloc(
953 @enumFromInt(emit.atom_index),952 @enumFromInt(@intFromEnum(emit.atom_id)),
954 end_offset - 4,953 end_offset - 4,
955 @enumFromInt(reloc.target.index),954 @enumFromInt(@intFromEnum(target.symbol)),
956 reloc.off,955 reloc.off,
957 .{ .AMD64 = .SECREL },956 .{ .AMD64 = .SECREL },
958 ) else return emit.fail("TODO implement {s} reloc for {s}", .{957 ) else return emit.fail("TODO implement {s} reloc for {s}", .{
959 @tagName(reloc.target.type), @tagName(emit.bin_file.tag),958 @tagName(reloc.target), @tagName(emit.bin_file.tag),
960 }),959 }),
961 };960 };
962}961}
src/codegen/x86_64/Mir.zig+4-4
...@@ -1976,7 +1976,7 @@ pub fn emit(...@@ -1976,7 +1976,7 @@ pub fn emit(
1976 pt: Zcu.PerThread,1976 pt: Zcu.PerThread,
1977 src_loc: Zcu.LazySrcLoc,1977 src_loc: Zcu.LazySrcLoc,
1978 func_index: InternPool.Index,1978 func_index: InternPool.Index,
1979 atom_index: u32,1979 atom_id: link.File.AtomId,
1980 w: *std.Io.Writer,1980 w: *std.Io.Writer,
1981 debug_output: link.File.DebugInfoOutput,1981 debug_output: link.File.DebugInfoOutput,
1982) codegen.CodeGenError!void {1982) codegen.CodeGenError!void {
...@@ -1998,7 +1998,7 @@ pub fn emit(...@@ -1998,7 +1998,7 @@ pub fn emit(
1998 .bin_file = lf,1998 .bin_file = lf,
1999 .pt = pt,1999 .pt = pt,
2000 .pic = mod.pic,2000 .pic = mod.pic,
2001 .atom_index = atom_index,2001 .atom_id = atom_id,
2002 .debug_output = debug_output,2002 .debug_output = debug_output,
2003 .w = w,2003 .w = w,
20042004
...@@ -2030,7 +2030,7 @@ pub fn emitLazy(...@@ -2030,7 +2030,7 @@ pub fn emitLazy(
2030 pt: Zcu.PerThread,2030 pt: Zcu.PerThread,
2031 src_loc: Zcu.LazySrcLoc,2031 src_loc: Zcu.LazySrcLoc,
2032 lazy_sym: link.File.LazySymbol,2032 lazy_sym: link.File.LazySymbol,
2033 atom_index: u32,2033 atom_id: link.File.AtomId,
2034 w: *std.Io.Writer,2034 w: *std.Io.Writer,
2035 debug_output: link.File.DebugInfoOutput,2035 debug_output: link.File.DebugInfoOutput,
2036) codegen.CodeGenError!void {2036) codegen.CodeGenError!void {
...@@ -2049,7 +2049,7 @@ pub fn emitLazy(...@@ -2049,7 +2049,7 @@ pub fn emitLazy(
2049 .bin_file = lf,2049 .bin_file = lf,
2050 .pt = pt,2050 .pt = pt,
2051 .pic = mod.pic,2051 .pic = mod.pic,
2052 .atom_index = atom_index,2052 .atom_id = atom_id,
2053 .debug_output = debug_output,2053 .debug_output = debug_output,
2054 .w = w,2054 .w = w,
20552055
src/link.zig+14-2
...@@ -759,12 +759,24 @@ pub const File = struct {...@@ -759,12 +759,24 @@ pub const File = struct {
759 /// must be attached to `Zcu.failed_codegen` rather than `Compilation.link_diags`.759 /// must be attached to `Zcu.failed_codegen` rather than `Compilation.link_diags`.
760 pub const UpdateNavError = codegen.CodeGenError;760 pub const UpdateNavError = codegen.CodeGenError;
761761
762 /// Opaque identifier for a function currently being emitted.
763 ///
764 /// The function may be an interned function with a NAV, or it may be a lazy function.
765 ///
766 /// This type exists for type-safe interaction between codegen and link.
767 pub const AtomId = enum(u32) { _ };
768
769 /// Opaque identifier for some symbol in the output binary.
770 ///
771 /// This type exists for type-safe interaction between codegen and link.
772 pub const SymbolId = enum(u32) { _ };
773
762 /// Called from within CodeGen to retrieve the symbol index of a global symbol.774 /// Called from within CodeGen to retrieve the symbol index of a global symbol.
763 /// If no symbol exists yet with this name, a new undefined global symbol will775 /// If no symbol exists yet with this name, a new undefined global symbol will
764 /// be created. This symbol may get resolved once all relocatables are (re-)linked.776 /// be created. This symbol may get resolved once all relocatables are (re-)linked.
765 /// Optionally, it is possible to specify where to expect the symbol defined if it777 /// Optionally, it is possible to specify where to expect the symbol defined if it
766 /// is an import.778 /// is an import.
767 pub fn getGlobalSymbol(base: *File, name: []const u8, lib_name: ?[]const u8) UpdateNavError!u32 {779 pub fn getGlobalSymbol(base: *File, name: []const u8, lib_name: ?[]const u8) UpdateNavError!SymbolId {
768 log.debug("getGlobalSymbol '{s}' (expected in '{?s}')", .{ name, lib_name });780 log.debug("getGlobalSymbol '{s}' (expected in '{?s}')", .{ name, lib_name });
769 switch (base.tag) {781 switch (base.tag) {
770 .lld => unreachable,782 .lld => unreachable,
...@@ -1008,7 +1020,7 @@ pub const File = struct {...@@ -1008,7 +1020,7 @@ pub const File = struct {
10081020
1009 pub const Parent = union(enum) {1021 pub const Parent = union(enum) {
1010 none,1022 none,
1011 atom_index: u32,1023 atom_index: AtomId,
1012 debug_output: DebugInfoOutput,1024 debug_output: DebugInfoOutput,
1013 };1025 };
1014 };1026 };
src/link/Coff.zig+8-8
...@@ -1328,7 +1328,7 @@ pub fn getUavVAddr(...@@ -1328,7 +1328,7 @@ pub fn getUavVAddr(
13281328
1329pub fn getVAddr(coff: *Coff, reloc_info: link.File.RelocInfo, target_si: Symbol.Index) !u64 {1329pub fn getVAddr(coff: *Coff, reloc_info: link.File.RelocInfo, target_si: Symbol.Index) !u64 {
1330 try coff.addReloc(1330 try coff.addReloc(
1331 @enumFromInt(reloc_info.parent.atom_index),1331 @enumFromInt(@intFromEnum(reloc_info.parent.atom_index)),
1332 reloc_info.offset,1332 reloc_info.offset,
1333 target_si,1333 target_si,
1334 reloc_info.addend,1334 reloc_info.addend,
...@@ -1581,7 +1581,7 @@ fn updateNavInner(coff: *Coff, pt: Zcu.PerThread, nav_index: InternPool.Nav.Inde...@@ -1581,7 +1581,7 @@ fn updateNavInner(coff: *Coff, pt: Zcu.PerThread, nav_index: InternPool.Nav.Inde
1581 zcu.navSrcLoc(nav_index),1581 zcu.navSrcLoc(nav_index),
1582 .fromInterned(nav.resolved.?.value),1582 .fromInterned(nav.resolved.?.value),
1583 &nw.interface,1583 &nw.interface,
1584 .{ .atom_index = @intFromEnum(si) },1584 .{ .atom_index = @enumFromInt(@intFromEnum(si)) },
1585 ) catch |err| switch (err) {1585 ) catch |err| switch (err) {
1586 error.WriteFailed => return error.OutOfMemory,1586 error.WriteFailed => return error.OutOfMemory,
1587 else => |e| return e,1587 else => |e| return e,
...@@ -1637,7 +1637,7 @@ pub fn lowerUav(...@@ -1637,7 +1637,7 @@ pub fn lowerUav(
1637 coff.const_prog_node.increaseEstimatedTotalItems(1);1637 coff.const_prog_node.increaseEstimatedTotalItems(1);
1638 }1638 }
1639 }1639 }
1640 return .{ .sym_index = @intFromEnum(si) };1640 return .{ .sym_index = @enumFromInt(@intFromEnum(si)) };
1641}1641}
16421642
1643pub fn updateFunc(1643pub fn updateFunc(
...@@ -1715,7 +1715,7 @@ fn updateFuncInner(...@@ -1715,7 +1715,7 @@ fn updateFuncInner(
1715 pt,1715 pt,
1716 zcu.navSrcLoc(func.owner_nav),1716 zcu.navSrcLoc(func.owner_nav),
1717 func_index,1717 func_index,
1718 @intFromEnum(si),1718 @enumFromInt(@intFromEnum(si)),
1719 mir,1719 mir,
1720 &nw.interface,1720 &nw.interface,
1721 .none,1721 .none,
...@@ -1930,7 +1930,7 @@ fn flushUav(...@@ -1930,7 +1930,7 @@ fn flushUav(
1930 src_loc,1930 src_loc,
1931 .fromInterned(uav_val),1931 .fromInterned(uav_val),
1932 &nw.interface,1932 &nw.interface,
1933 .{ .atom_index = @intFromEnum(si) },1933 .{ .atom_index = @enumFromInt(@intFromEnum(si)) },
1934 ) catch |err| switch (err) {1934 ) catch |err| switch (err) {
1935 error.WriteFailed => return error.OutOfMemory,1935 error.WriteFailed => return error.OutOfMemory,
1936 else => |e| return e,1936 else => |e| return e,
...@@ -2146,7 +2146,7 @@ fn flushLazy(coff: *Coff, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void {...@@ -2146,7 +2146,7 @@ fn flushLazy(coff: *Coff, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void {
2146 &required_alignment,2146 &required_alignment,
2147 &nw.interface,2147 &nw.interface,
2148 .none,2148 .none,
2149 .{ .atom_index = @intFromEnum(si) },2149 .{ .atom_index = @enumFromInt(@intFromEnum(si)) },
2150 );2150 );
2151 si.get(coff).size = @intCast(nw.interface.end);2151 si.get(coff).size = @intCast(nw.interface.end);
2152 si.applyLocationRelocs(coff);2152 si.applyLocationRelocs(coff);
...@@ -2339,7 +2339,7 @@ fn updateExportsInner(...@@ -2339,7 +2339,7 @@ fn updateExportsInner(
2339 try coff.symbol_table.ensureUnusedCapacity(gpa, export_indices.len);2339 try coff.symbol_table.ensureUnusedCapacity(gpa, export_indices.len);
2340 const exported_si: Symbol.Index = switch (exported) {2340 const exported_si: Symbol.Index = switch (exported) {
2341 .nav => |nav| try coff.navSymbol(zcu, nav),2341 .nav => |nav| try coff.navSymbol(zcu, nav),
2342 .uav => |uav| @enumFromInt(switch (try coff.lowerUav(2342 .uav => |uav| @enumFromInt(@intFromEnum(switch (try coff.lowerUav(
2343 pt,2343 pt,
2344 uav,2344 uav,
2345 Type.fromInterned(ip.typeOf(uav)).abiAlignment(zcu),2345 Type.fromInterned(ip.typeOf(uav)).abiAlignment(zcu),
...@@ -2350,7 +2350,7 @@ fn updateExportsInner(...@@ -2350,7 +2350,7 @@ fn updateExportsInner(
2350 defer em.destroy(gpa);2350 defer em.destroy(gpa);
2351 return coff.base.comp.link_diags.fail("{s}", .{em.msg});2351 return coff.base.comp.link_diags.fail("{s}", .{em.msg});
2352 },2352 },
2353 }),2353 })),
2354 };2354 };
2355 while (try coff.idle(pt.tid)) {}2355 while (try coff.idle(pt.tid)) {}
2356 const exported_ni = exported_si.node(coff);2356 const exported_ni = exported_si.node(coff);
src/link/Dwarf.zig+10-10
...@@ -1151,13 +1151,13 @@ const CrossSectionReloc = struct {...@@ -1151,13 +1151,13 @@ const CrossSectionReloc = struct {
1151};1151};
1152const ExternalReloc = struct {1152const ExternalReloc = struct {
1153 source_off: u32 = 0,1153 source_off: u32 = 0,
1154 target_sym: u32,1154 target_sym: link.File.SymbolId,
1155 target_off: u64 = 0,1155 target_off: u64 = 0,
1156};1156};
11571157
1158pub const Loc = union(enum) {1158pub const Loc = union(enum) {
1159 empty,1159 empty,
1160 addr_reloc: u32,1160 addr_reloc: link.File.SymbolId,
1161 deref: *const Loc,1161 deref: *const Loc,
1162 constu: u64,1162 constu: u64,
1163 consts: i64,1163 consts: i64,
...@@ -1506,7 +1506,7 @@ pub const WipNav = struct {...@@ -1506,7 +1506,7 @@ pub const WipNav = struct {
1506 entry: Entry.Index,1506 entry: Entry.Index,
1507 any_children: bool,1507 any_children: bool,
1508 func: InternPool.Index,1508 func: InternPool.Index,
1509 func_sym_index: u32,1509 func_sym_index: link.File.SymbolId,
1510 func_high_pc: u32,1510 func_high_pc: u32,
1511 blocks: std.ArrayList(struct {1511 blocks: std.ArrayList(struct {
1512 abbrev_code: u32,1512 abbrev_code: u32,
...@@ -1966,7 +1966,7 @@ pub const WipNav = struct {...@@ -1966,7 +1966,7 @@ pub const WipNav = struct {
1966 fn endian(_: ExprLocCounter) std.lang.Endian {1966 fn endian(_: ExprLocCounter) std.lang.Endian {
1967 return @import("builtin").cpu.arch.endian();1967 return @import("builtin").cpu.arch.endian();
1968 }1968 }
1969 fn addrSym(counter: *ExprLocCounter, _: u32) Writer.Error!void {1969 fn addrSym(counter: *ExprLocCounter, _: link.File.SymbolId) Writer.Error!void {
1970 try counter.dw.writer.splatByteAll(undefined, @intFromEnum(counter.address_size));1970 try counter.dw.writer.splatByteAll(undefined, @intFromEnum(counter.address_size));
1971 }1971 }
1972 fn infoEntry(counter: *ExprLocCounter, _: Unit.Index, _: Entry.Index) Writer.Error!void {1972 fn infoEntry(counter: *ExprLocCounter, _: Unit.Index, _: Entry.Index) Writer.Error!void {
...@@ -1987,7 +1987,7 @@ pub const WipNav = struct {...@@ -1987,7 +1987,7 @@ pub const WipNav = struct {
1987 fn endian(ctx: @This()) std.lang.Endian {1987 fn endian(ctx: @This()) std.lang.Endian {
1988 return ctx.wip_nav.dwarf.endian;1988 return ctx.wip_nav.dwarf.endian;
1989 }1989 }
1990 fn addrSym(ctx: @This(), sym_index: u32) (UpdateError || Writer.Error)!void {1990 fn addrSym(ctx: @This(), sym_index: link.File.SymbolId) (UpdateError || Writer.Error)!void {
1991 try ctx.wip_nav.infoAddrSym(sym_index, 0);1991 try ctx.wip_nav.infoAddrSym(sym_index, 0);
1992 }1992 }
1993 fn infoEntry(1993 fn infoEntry(
...@@ -2004,7 +2004,7 @@ pub const WipNav = struct {...@@ -2004,7 +2004,7 @@ pub const WipNav = struct {
20042004
2005 fn infoAddrSym(2005 fn infoAddrSym(
2006 wip_nav: *WipNav,2006 wip_nav: *WipNav,
2007 sym_index: u32,2007 sym_index: link.File.SymbolId,
2008 sym_off: u64,2008 sym_off: u64,
2009 ) (UpdateError || Writer.Error)!void {2009 ) (UpdateError || Writer.Error)!void {
2010 const diw = &wip_nav.debug_info.writer;2010 const diw = &wip_nav.debug_info.writer;
...@@ -2029,7 +2029,7 @@ pub const WipNav = struct {...@@ -2029,7 +2029,7 @@ pub const WipNav = struct {
2029 fn endian(ctx: @This()) std.lang.Endian {2029 fn endian(ctx: @This()) std.lang.Endian {
2030 return ctx.wip_nav.dwarf.endian;2030 return ctx.wip_nav.dwarf.endian;
2031 }2031 }
2032 fn addrSym(ctx: @This(), sym_index: u32) (UpdateError || Writer.Error)!void {2032 fn addrSym(ctx: @This(), sym_index: link.File.SymbolId) (UpdateError || Writer.Error)!void {
2033 try ctx.wip_nav.frameAddrSym(sym_index, 0);2033 try ctx.wip_nav.frameAddrSym(sym_index, 0);
2034 }2034 }
2035 fn infoEntry(2035 fn infoEntry(
...@@ -2046,7 +2046,7 @@ pub const WipNav = struct {...@@ -2046,7 +2046,7 @@ pub const WipNav = struct {
20462046
2047 fn frameAddrSym(2047 fn frameAddrSym(
2048 wip_nav: *WipNav,2048 wip_nav: *WipNav,
2049 sym_index: u32,2049 sym_index: link.File.SymbolId,
2050 sym_off: u64,2050 sym_off: u64,
2051 ) (UpdateError || Writer.Error)!void {2051 ) (UpdateError || Writer.Error)!void {
2052 const dfw = &wip_nav.debug_frame.writer;2052 const dfw = &wip_nav.debug_frame.writer;
...@@ -2591,7 +2591,7 @@ pub fn initWipNav(...@@ -2591,7 +2591,7 @@ pub fn initWipNav(
2591 dwarf: *Dwarf,2591 dwarf: *Dwarf,
2592 pt: Zcu.PerThread,2592 pt: Zcu.PerThread,
2593 nav_index: InternPool.Nav.Index,2593 nav_index: InternPool.Nav.Index,
2594 sym_index: u32,2594 sym_index: link.File.SymbolId,
2595) error{ OutOfMemory, CodegenFail }!WipNav {2595) error{ OutOfMemory, CodegenFail }!WipNav {
2596 return initWipNavInner(dwarf, pt, nav_index, sym_index) catch |err| switch (err) {2596 return initWipNavInner(dwarf, pt, nav_index, sym_index) catch |err| switch (err) {
2597 error.OutOfMemory => error.OutOfMemory,2597 error.OutOfMemory => error.OutOfMemory,
...@@ -2603,7 +2603,7 @@ fn initWipNavInner(...@@ -2603,7 +2603,7 @@ fn initWipNavInner(
2603 dwarf: *Dwarf,2603 dwarf: *Dwarf,
2604 pt: Zcu.PerThread,2604 pt: Zcu.PerThread,
2605 nav_index: InternPool.Nav.Index,2605 nav_index: InternPool.Nav.Index,
2606 sym_index: u32,2606 sym_index: link.File.SymbolId,
2607) !WipNav {2607) !WipNav {
2608 const zcu = pt.zcu;2608 const zcu = pt.zcu;
2609 const ip = &zcu.intern_pool;2609 const ip = &zcu.intern_pool;
src/link/Elf/ZigObject.zig+23-16
...@@ -461,14 +461,14 @@ pub fn flush(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !void {...@@ -461,14 +461,14 @@ pub fn flush(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !void {
461 }, self);461 }, self);
462 }462 }
463 for (entry.external_relocs.items) |reloc| {463 for (entry.external_relocs.items) |reloc| {
464 const target_sym = self.symbol(reloc.target_sym);464 const target_sym = self.symbol(@intFromEnum(reloc.target_sym));
465 const r_offset = entry_off + reloc.source_off;465 const r_offset = entry_off + reloc.source_off;
466 const r_addend: i64 = @intCast(reloc.target_off);466 const r_addend: i64 = @intCast(reloc.target_off);
467 const r_type = relocation.dwarf.externalRelocType(target_sym.*, sect_index, dwarf.address_size, cpu_arch);467 const r_type = relocation.dwarf.externalRelocType(target_sym.*, sect_index, dwarf.address_size, cpu_arch);
468 atom_ptr.addRelocAssumeCapacity(.{468 atom_ptr.addRelocAssumeCapacity(.{
469 .r_offset = r_offset,469 .r_offset = r_offset,
470 .r_addend = r_addend,470 .r_addend = r_addend,
471 .r_info = (@as(u64, @intCast(reloc.target_sym)) << 32) | r_type,471 .r_info = (@as(u64, @intCast(@intFromEnum(reloc.target_sym))) << 32) | r_type,
472 }, self);472 }, self);
473 }473 }
474 }474 }
...@@ -941,7 +941,7 @@ pub fn getNavVAddr(...@@ -941,7 +941,7 @@ pub fn getNavVAddr(
941 switch (reloc_info.parent) {941 switch (reloc_info.parent) {
942 .none => unreachable,942 .none => unreachable,
943 .atom_index => |atom_index| {943 .atom_index => |atom_index| {
944 const parent_atom = self.symbol(atom_index).atom(elf_file).?;944 const parent_atom = self.symbol(@intFromEnum(atom_index)).atom(elf_file).?;
945 const r_type = relocation.encode(.abs, elf_file.getTarget().cpu.arch);945 const r_type = relocation.encode(.abs, elf_file.getTarget().cpu.arch);
946 try parent_atom.addReloc(elf_file.base.comp.gpa, .{946 try parent_atom.addReloc(elf_file.base.comp.gpa, .{
947 .r_offset = reloc_info.offset,947 .r_offset = reloc_info.offset,
...@@ -952,7 +952,7 @@ pub fn getNavVAddr(...@@ -952,7 +952,7 @@ pub fn getNavVAddr(
952 .debug_output => |debug_output| switch (debug_output) {952 .debug_output => |debug_output| switch (debug_output) {
953 .dwarf => |wip_nav| try wip_nav.infoExternalReloc(.{953 .dwarf => |wip_nav| try wip_nav.infoExternalReloc(.{
954 .source_off = @intCast(reloc_info.offset),954 .source_off = @intCast(reloc_info.offset),
955 .target_sym = this_sym_index,955 .target_sym = @enumFromInt(this_sym_index),
956 .target_off = reloc_info.addend,956 .target_off = reloc_info.addend,
957 }),957 }),
958 .none => unreachable,958 .none => unreachable,
...@@ -973,7 +973,7 @@ pub fn getUavVAddr(...@@ -973,7 +973,7 @@ pub fn getUavVAddr(
973 switch (reloc_info.parent) {973 switch (reloc_info.parent) {
974 .none => unreachable,974 .none => unreachable,
975 .atom_index => |atom_index| {975 .atom_index => |atom_index| {
976 const parent_atom = self.symbol(atom_index).atom(elf_file).?;976 const parent_atom = self.symbol(@intFromEnum(atom_index)).atom(elf_file).?;
977 const r_type = relocation.encode(.abs, elf_file.getTarget().cpu.arch);977 const r_type = relocation.encode(.abs, elf_file.getTarget().cpu.arch);
978 try parent_atom.addReloc(elf_file.base.comp.gpa, .{978 try parent_atom.addReloc(elf_file.base.comp.gpa, .{
979 .r_offset = reloc_info.offset,979 .r_offset = reloc_info.offset,
...@@ -984,7 +984,7 @@ pub fn getUavVAddr(...@@ -984,7 +984,7 @@ pub fn getUavVAddr(
984 .debug_output => |debug_output| switch (debug_output) {984 .debug_output => |debug_output| switch (debug_output) {
985 .dwarf => |wip_nav| try wip_nav.infoExternalReloc(.{985 .dwarf => |wip_nav| try wip_nav.infoExternalReloc(.{
986 .source_off = @intCast(reloc_info.offset),986 .source_off = @intCast(reloc_info.offset),
987 .target_sym = sym_index,987 .target_sym = @enumFromInt(sym_index),
988 .target_off = reloc_info.addend,988 .target_off = reloc_info.addend,
989 }),989 }),
990 .none => unreachable,990 .none => unreachable,
...@@ -1013,7 +1013,7 @@ pub fn lowerUav(...@@ -1013,7 +1013,7 @@ pub fn lowerUav(
1013 const sym = self.symbol(metadata.symbol_index);1013 const sym = self.symbol(metadata.symbol_index);
1014 const existing_alignment = sym.atom(elf_file).?.alignment;1014 const existing_alignment = sym.atom(elf_file).?.alignment;
1015 if (uav_alignment.order(existing_alignment).compare(.lte))1015 if (uav_alignment.order(existing_alignment).compare(.lte))
1016 return .{ .sym_index = metadata.symbol_index };1016 return .{ .sym_index = @enumFromInt(metadata.symbol_index) };
1017 }1017 }
10181018
1019 const osec = if (self.data_relro_index) |sym_index|1019 const osec = if (self.data_relro_index) |sym_index|
...@@ -1051,7 +1051,10 @@ pub fn lowerUav(...@@ -1051,7 +1051,10 @@ pub fn lowerUav(
1051 ) },1051 ) },
1052 };1052 };
1053 switch (res) {1053 switch (res) {
1054 .sym_index => |sym_index| try self.uavs.put(gpa, uav, .{ .symbol_index = sym_index, .allocated = true }),1054 .sym_index => |sym_index| try self.uavs.put(gpa, uav, .{
1055 .symbol_index = @intFromEnum(sym_index),
1056 .allocated = true,
1057 }),
1055 .fail => {},1058 .fail => {},
1056 }1059 }
1057 return res;1060 return res;
...@@ -1545,7 +1548,11 @@ pub fn updateFunc(...@@ -1545,7 +1548,11 @@ pub fn updateFunc(
1545 var aw: std.Io.Writer.Allocating = .init(gpa);1548 var aw: std.Io.Writer.Allocating = .init(gpa);
1546 defer aw.deinit();1549 defer aw.deinit();
15471550
1548 var debug_wip_nav = if (self.dwarf) |*dwarf| try dwarf.initWipNav(pt, func.owner_nav, sym_index) else null;1551 var debug_wip_nav = if (self.dwarf) |*dwarf| try dwarf.initWipNav(
1552 pt,
1553 func.owner_nav,
1554 @enumFromInt(sym_index),
1555 ) else null;
1549 defer if (debug_wip_nav) |*wip_nav| wip_nav.deinit();1556 defer if (debug_wip_nav) |*wip_nav| wip_nav.deinit();
15501557
1551 codegen.emitFunction(1558 codegen.emitFunction(
...@@ -1553,7 +1560,7 @@ pub fn updateFunc(...@@ -1553,7 +1560,7 @@ pub fn updateFunc(
1553 pt,1560 pt,
1554 zcu.navSrcLoc(func.owner_nav),1561 zcu.navSrcLoc(func.owner_nav),
1555 func_index,1562 func_index,
1556 sym_index,1563 @enumFromInt(sym_index),
1557 mir,1564 mir,
1558 &aw.writer,1565 &aw.writer,
1559 if (debug_wip_nav) |*dn| .{ .dwarf = dn } else .none,1566 if (debug_wip_nav) |*dn| .{ .dwarf = dn } else .none,
...@@ -1660,7 +1667,7 @@ pub fn updateNav(...@@ -1660,7 +1667,7 @@ pub fn updateNav(
1660 self.symbol(sym_index).flags.is_tls = true;1667 self.symbol(sym_index).flags.is_tls = true;
1661 }1668 }
1662 if (self.dwarf) |*dwarf| {1669 if (self.dwarf) |*dwarf| {
1663 var debug_wip_nav = try dwarf.initWipNav(pt, nav_index, sym_index);1670 var debug_wip_nav = try dwarf.initWipNav(pt, nav_index, @enumFromInt(sym_index));
1664 defer debug_wip_nav.deinit();1671 defer debug_wip_nav.deinit();
1665 dwarf.finishWipNav(pt, nav_index, &debug_wip_nav) catch |err| switch (err) {1672 dwarf.finishWipNav(pt, nav_index, &debug_wip_nav) catch |err| switch (err) {
1666 error.OutOfMemory, error.Overflow => |e| return e,1673 error.OutOfMemory, error.Overflow => |e| return e,
...@@ -1678,7 +1685,7 @@ pub fn updateNav(...@@ -1678,7 +1685,7 @@ pub fn updateNav(
1678 var aw: std.Io.Writer.Allocating = .init(zcu.gpa);1685 var aw: std.Io.Writer.Allocating = .init(zcu.gpa);
1679 defer aw.deinit();1686 defer aw.deinit();
16801687
1681 var debug_wip_nav = if (self.dwarf) |*dwarf| try dwarf.initWipNav(pt, nav_index, sym_index) else null;1688 var debug_wip_nav = if (self.dwarf) |*dwarf| try dwarf.initWipNav(pt, nav_index, @enumFromInt(sym_index)) else null;
1682 defer if (debug_wip_nav) |*wip_nav| wip_nav.deinit();1689 defer if (debug_wip_nav) |*wip_nav| wip_nav.deinit();
16831690
1684 codegen.generateSymbol(1691 codegen.generateSymbol(
...@@ -1687,7 +1694,7 @@ pub fn updateNav(...@@ -1687,7 +1694,7 @@ pub fn updateNav(
1687 zcu.navSrcLoc(nav_index),1694 zcu.navSrcLoc(nav_index),
1688 .fromInterned(nav.resolved.?.value),1695 .fromInterned(nav.resolved.?.value),
1689 &aw.writer,1696 &aw.writer,
1690 .{ .atom_index = sym_index },1697 .{ .atom_index = @enumFromInt(sym_index) },
1691 ) catch |err| switch (err) {1698 ) catch |err| switch (err) {
1692 error.WriteFailed => return error.OutOfMemory,1699 error.WriteFailed => return error.OutOfMemory,
1693 else => |e| return e,1700 else => |e| return e,
...@@ -1757,7 +1764,7 @@ fn updateLazySymbol(...@@ -1757,7 +1764,7 @@ fn updateLazySymbol(
1757 &required_alignment,1764 &required_alignment,
1758 &aw.writer,1765 &aw.writer,
1759 .none,1766 .none,
1760 .{ .atom_index = symbol_index },1767 .{ .atom_index = @enumFromInt(symbol_index) },
1761 ) catch |err| switch (err) {1768 ) catch |err| switch (err) {
1762 error.WriteFailed => return error.OutOfMemory,1769 error.WriteFailed => return error.OutOfMemory,
1763 else => |e| return e,1770 else => |e| return e,
...@@ -1836,7 +1843,7 @@ fn lowerConst(...@@ -1836,7 +1843,7 @@ fn lowerConst(
1836 src_loc,1843 src_loc,
1837 val,1844 val,
1838 &aw.writer,1845 &aw.writer,
1839 .{ .atom_index = sym_index },1846 .{ .atom_index = @enumFromInt(sym_index) },
1840 ) catch |err| switch (err) {1847 ) catch |err| switch (err) {
1841 error.WriteFailed => return error.OutOfMemory,1848 error.WriteFailed => return error.OutOfMemory,
1842 else => |e| return e,1849 else => |e| return e,
...@@ -1858,7 +1865,7 @@ fn lowerConst(...@@ -1858,7 +1865,7 @@ fn lowerConst(
18581865
1859 try elf_file.pwriteAll(code, atom_ptr.offset(elf_file));1866 try elf_file.pwriteAll(code, atom_ptr.offset(elf_file));
18601867
1861 return .{ .sym_index = sym_index };1868 return .{ .sym_index = @enumFromInt(sym_index) };
1862}1869}
18631870
1864pub fn updateExports(1871pub fn updateExports(
src/link/Elf2.zig+2180-1211
...@@ -25,55 +25,102 @@ ni: Node.Known,...@@ -25,55 +25,102 @@ ni: Node.Known,
25nodes: std.MultiArrayList(Node),25nodes: std.MultiArrayList(Node),
26shdrs: std.ArrayList(Section),26shdrs: std.ArrayList(Section),
27phdrs: std.ArrayList(MappedFile.Node.Index),27phdrs: std.ArrayList(MappedFile.Node.Index),
28si: Symbol.Known,28shndx: struct {
29 got: Section.Index,
30 got_plt: Section.Index,
31 plt: Section.Index,
32 plt_sec: Section.Index,
33 dynsym: Section.Index,
34 dynstr: Section.Index,
35 dynamic: Section.Index,
36 tdata: Section.Index,
37},
29symtab: std.ArrayList(Symbol),38symtab: std.ArrayList(Symbol),
39globals: struct {
40 strong_def: std.array_hash_map.Auto(String(.strtab), Symbol.Global),
41 weak_def: std.array_hash_map.Auto(String(.strtab), Symbol.Global),
42 strong_undef: std.array_hash_map.Auto(String(.strtab), Symbol.Global),
43 weak_undef: std.array_hash_map.Auto(String(.strtab), Symbol.Global),
44},
45/// Key is a node which is a valid `Symbol.node` value, value is the name of the first global symbol
46/// in that node. That symbol is the head of a linked list: see `Symbol.Global.next_in_node`.
47///
48/// Value is never `.empty`.
49///
50/// We use a separate hash map for this data rather than storing it in `navs` etc to save memory,
51/// because the vast majority of nodes which can export global symbols actually will not.
52node_global_symbols: std.array_hash_map.Auto(MappedFile.Node.Index, String(.strtab)),
30shstrtab: StringTable,53shstrtab: StringTable,
31strtab: StringTable,54strtab: StringTable,
32dynsym: std.AutoArrayHashMapUnmanaged(Symbol.Index, void),
33dynstr: StringTable,55dynstr: StringTable,
34got: struct {56got: struct {
35 len: u32,57 len: u32,
36 tlsld: GotIndex,58 tlsld: GotIndex,
37 plt: std.AutoArrayHashMapUnmanaged(Symbol.Index, void),59 plt: std.AutoArrayHashMapUnmanaged(Symbol.Id, void),
38},60},
39needed: std.AutoArrayHashMapUnmanaged(u32, void),61first_plt_reloc: Reloc.Index,
62first_dynamic_reloc: Reloc.Index,
63needed: std.AutoArrayHashMapUnmanaged(String(.dynstr), void),
40inputs: std.ArrayList(struct {64inputs: std.ArrayList(struct {
41 path: std.Build.Cache.Path,65 path: std.Build.Cache.Path,
42 member: ?[]const u8,66 member: ?[]const u8,
43 si: Symbol.Index,67 file_symbol: Symbol.LocalIndex,
44}),
45input_sections: std.ArrayList(struct {
46 ii: Node.InputIndex,
47 file_location: MappedFile.Node.FileLocation,
48 si: Symbol.Index,
49}),68}),
69input_sections: std.ArrayList(InputSection),
50input_section_pending_index: u32,70input_section_pending_index: u32,
51globals: std.AutoArrayHashMapUnmanaged(u32, Symbol.Index),71navs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, struct {
52navs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, Symbol.Index),72 /// The start index of the contiguous sequence of relocations in this NAV.
53uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, Symbol.Index),73 first_reloc: Reloc.Index,
74 lsi: Symbol.LocalIndex,
75}),
76uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, struct {
77 /// The start index of the contiguous sequence of relocations in this UAV.
78 first_reloc: Reloc.Index,
79 lsi: Symbol.LocalIndex,
80}),
54lazy: std.EnumArray(link.File.LazySymbol.Kind, struct {81lazy: std.EnumArray(link.File.LazySymbol.Kind, struct {
55 map: std.AutoArrayHashMapUnmanaged(InternPool.Index, Symbol.Index),82 map: std.AutoArrayHashMapUnmanaged(InternPool.Index, struct {
83 /// The start index of the contiguous sequence of relocations in this lazy code/data.
84 first_reloc: Reloc.Index,
85 lsi: Symbol.LocalIndex,
86 }),
56 pending_index: u32,87 pending_index: u32,
57}),88}),
58pending_uavs: std.AutoArrayHashMapUnmanaged(Node.UavMapIndex, struct {89pending_uavs: std.ArrayList(Node.UavMapIndex),
59 alignment: InternPool.Alignment,
60 src_loc: Zcu.LazySrcLoc,
61}),
62relocs: std.ArrayList(Reloc),90relocs: std.ArrayList(Reloc),
91
92/// Key is the name of a global symbol which has been moved to a new symtab index. Any relocation
93/// entries which target that symbol must be updated to reference the correct symbol index.
94changed_symtab_index: std.array_hash_map.Auto(String(.strtab), void),
95
63const_prog_node: std.Progress.Node,96const_prog_node: std.Progress.Node,
64synth_prog_node: std.Progress.Node,97synth_prog_node: std.Progress.Node,
65input_prog_node: std.Progress.Node,98input_prog_node: std.Progress.Node,
6699
67pub const Node = union(enum) {100const Node = union(enum) {
101 /// Cannot contain relocations.
68 file,102 file,
103 /// Cannot contain relocations.
69 ehdr,104 ehdr,
105 /// Cannot contain relocations.
70 shdr,106 shdr,
107 /// Cannot contain relocations.
71 segment: u32,108 segment: u32,
72 section: Symbol.Index,109 /// The section '.plt' may contain relocations via `elf.first_plt_reloc`.
73 input_section: InputSectionIndex,110 ///
111 /// The section '.dynamic' may contain relocations via `elf.first_dynamic_reloc`.
112 ///
113 /// Otherwise, cannot contain relocations.
114 section: Section.Index,
115 /// May contain relocations through the `first_reloc` field in `elf.input_sections`.
116 input_section: InputSection.Index,
117 /// May contain relocations through the `first_reloc` field in `elf.navs`.
74 nav: NavMapIndex,118 nav: NavMapIndex,
119 /// May contain relocations through the `first_reloc` field in `elf.uavs`.
75 uav: UavMapIndex,120 uav: UavMapIndex,
121 /// May contain relocations through the `first_reloc` field in `elf.lazy.map`.
76 lazy_code: LazyMapRef.Index(.code),122 lazy_code: LazyMapRef.Index(.code),
123 /// May contain relocations through the `first_reloc` field in `elf.lazy.map`.
77 lazy_const_data: LazyMapRef.Index(.const_data),124 lazy_const_data: LazyMapRef.Index(.const_data),
78125
79 pub const InputIndex = enum(u32) {126 pub const InputIndex = enum(u32) {
...@@ -87,32 +134,20 @@ pub const Node = union(enum) {...@@ -87,32 +134,20 @@ pub const Node = union(enum) {
87 return elf.inputs.items[@intFromEnum(ii)].member;134 return elf.inputs.items[@intFromEnum(ii)].member;
88 }135 }
89136
90 pub fn symbol(ii: InputIndex, elf: *const Elf) Symbol.Index {137 pub fn fileSymbol(ii: InputIndex, elf: *const Elf) Symbol.LocalIndex {
91 return elf.inputs.items[@intFromEnum(ii)].si;138 return elf.inputs.items[@intFromEnum(ii)].file_symbol;
92 }
93
94 pub fn endSymbol(ii: InputIndex, elf: *const Elf) Symbol.Index {
95 const next_ii = @intFromEnum(ii) + 1;
96 return if (next_ii < elf.inputs.items.len)
97 @as(InputIndex, @enumFromInt(next_ii)).symbol(elf)
98 else
99 @enumFromInt(elf.symtab.items.len);
100 }
101 };
102
103 pub const InputSectionIndex = enum(u32) {
104 _,
105
106 pub fn input(isi: InputSectionIndex, elf: *const Elf) InputIndex {
107 return elf.input_sections.items[@intFromEnum(isi)].ii;
108 }139 }
109140
110 pub fn fileLocation(isi: InputSectionIndex, elf: *const Elf) MappedFile.Node.FileLocation {141 pub fn localSymbolRange(ii: InputIndex, elf: *Elf) [2]Symbol.LocalIndex {
111 return elf.input_sections.items[@intFromEnum(isi)].file_location;142 if (@intFromEnum(ii) + 1 < elf.inputs.items.len) {
112 }143 const next_ii: InputIndex = @enumFromInt(@intFromEnum(ii) + 1);
113144 return .{ ii.fileSymbol(elf), next_ii.fileSymbol(elf) };
114 pub fn symbol(isi: InputSectionIndex, elf: *const Elf) Symbol.Index {145 } else {
115 return elf.input_sections.items[@intFromEnum(isi)].si;146 const local_symbols_len = switch (elf.shdrPtr(.symtab)) {
147 inline else => |shdr| elf.targetLoad(&shdr.info),
148 };
149 return .{ ii.fileSymbol(elf), @enumFromInt(local_symbols_len) };
150 }
116 }151 }
117 };152 };
118153
...@@ -123,8 +158,12 @@ pub const Node = union(enum) {...@@ -123,8 +158,12 @@ pub const Node = union(enum) {
123 return elf.navs.keys()[@intFromEnum(nmi)];158 return elf.navs.keys()[@intFromEnum(nmi)];
124 }159 }
125160
126 pub fn symbol(nmi: NavMapIndex, elf: *const Elf) Symbol.Index {161 pub fn symbol(nmi: NavMapIndex, elf: *const Elf) Symbol.LocalIndex {
127 return elf.navs.values()[@intFromEnum(nmi)];162 return elf.navs.values()[@intFromEnum(nmi)].lsi;
163 }
164
165 fn firstReloc(nmi: NavMapIndex, elf: *const Elf) Reloc.Index {
166 return elf.navs.values()[@intFromEnum(nmi)].first_reloc;
128 }167 }
129 };168 };
130169
...@@ -135,8 +174,12 @@ pub const Node = union(enum) {...@@ -135,8 +174,12 @@ pub const Node = union(enum) {
135 return elf.uavs.keys()[@intFromEnum(umi)];174 return elf.uavs.keys()[@intFromEnum(umi)];
136 }175 }
137176
138 pub fn symbol(umi: UavMapIndex, elf: *const Elf) Symbol.Index {177 pub fn symbol(umi: UavMapIndex, elf: *const Elf) Symbol.LocalIndex {
139 return elf.uavs.values()[@intFromEnum(umi)];178 return elf.uavs.values()[@intFromEnum(umi)].lsi;
179 }
180
181 fn firstReloc(umi: UavMapIndex, elf: *const Elf) Reloc.Index {
182 return elf.uavs.values()[@intFromEnum(umi)].first_reloc;
140 }183 }
141 };184 };
142185
...@@ -156,9 +199,13 @@ pub const Node = union(enum) {...@@ -156,9 +199,13 @@ pub const Node = union(enum) {
156 return lmi.ref().lazySymbol(elf);199 return lmi.ref().lazySymbol(elf);
157 }200 }
158201
159 pub fn symbol(lmi: @This(), elf: *const Elf) Symbol.Index {202 pub fn symbol(lmi: @This(), elf: *const Elf) Symbol.LocalIndex {
160 return lmi.ref().symbol(elf);203 return lmi.ref().symbol(elf);
161 }204 }
205
206 fn firstReloc(lmi: @This(), elf: *const Elf) Reloc.Index {
207 return lmi.ref().firstReloc(elf);
208 }
162 };209 };
163 }210 }
164211
...@@ -166,8 +213,12 @@ pub const Node = union(enum) {...@@ -166,8 +213,12 @@ pub const Node = union(enum) {
166 return .{ .kind = lmr.kind, .ty = elf.lazy.getPtrConst(lmr.kind).map.keys()[lmr.index] };213 return .{ .kind = lmr.kind, .ty = elf.lazy.getPtrConst(lmr.kind).map.keys()[lmr.index] };
167 }214 }
168215
169 pub fn symbol(lmr: LazyMapRef, elf: *const Elf) Symbol.Index {216 pub fn symbol(lmr: LazyMapRef, elf: *const Elf) Symbol.LocalIndex {
170 return elf.lazy.getPtrConst(lmr.kind).map.values()[lmr.index];217 return elf.lazy.getPtrConst(lmr.kind).map.values()[lmr.index].lsi;
218 }
219
220 fn firstReloc(lmr: LazyMapRef, elf: *const Elf) Reloc.Index {
221 return elf.lazy.getPtrConst(lmr.kind).map.values()[lmr.index].first_reloc;
171 }222 }
172 };223 };
173224
...@@ -180,17 +231,66 @@ pub const Node = union(enum) {...@@ -180,17 +231,66 @@ pub const Node = union(enum) {
180 comptime text: MappedFile.Node.Index = @enumFromInt(5),231 comptime text: MappedFile.Node.Index = @enumFromInt(5),
181 comptime data: MappedFile.Node.Index = @enumFromInt(6),232 comptime data: MappedFile.Node.Index = @enumFromInt(6),
182 comptime data_rel_ro: MappedFile.Node.Index = @enumFromInt(7),233 comptime data_rel_ro: MappedFile.Node.Index = @enumFromInt(7),
234
183 tls: MappedFile.Node.Index,235 tls: MappedFile.Node.Index,
184 };236 };
185237
186 comptime {238 comptime {
187 if (!std.debug.runtime_safety) std.debug.assert(@sizeOf(Node) == 8);239 if (!std.debug.runtime_safety) std.debug.assert(@sizeOf(Node) == 8);
188 }240 }
241
242 /// In this linker implementation, `link.File.AtomId` is a type-erased `MappedFile.Node.Index`.
243 fn toAtom(ni: MappedFile.Node.Index) link.File.AtomId {
244 return @enumFromInt(@intFromEnum(ni));
245 }
246 /// In this linker implementation, `link.File.AtomId` is a type-erased `MappedFile.Node.Index`.
247 fn fromAtom(atom: link.File.AtomId) MappedFile.Node.Index {
248 return @enumFromInt(@intFromEnum(atom));
249 }
189};250};
190251
191pub const Section = struct {252const InputSection = struct {
192 si: Symbol.Index,253 input: Node.InputIndex,
193 rela_si: Symbol.Index,254 file_location: MappedFile.Node.FileLocation,
255 vaddr: u64,
256 /// The node corresponding to this input section.
257 node: MappedFile.Node.Index,
258 /// The start index of the contiguous sequence of relocations in this input section.
259 first_reloc: Reloc.Index,
260
261 const Index = enum(u32) {
262 _,
263
264 fn ptr(isi: InputSection.Index, elf: *Elf) *InputSection {
265 return &elf.input_sections.items[@intFromEnum(isi)];
266 }
267
268 fn ptrConst(isi: InputSection.Index, elf: *const Elf) *const InputSection {
269 return &elf.input_sections.items[@intFromEnum(isi)];
270 }
271
272 fn input(isi: InputSection.Index, elf: *const Elf) Node.InputIndex {
273 return isi.ptrConst(elf).input;
274 }
275
276 fn fileLocation(isi: InputSection.Index, elf: *const Elf) MappedFile.Node.FileLocation {
277 return isi.ptrConst(elf).file_location;
278 }
279
280 fn node(isi: InputSection.Index, elf: *const Elf) MappedFile.Node.Index {
281 return isi.ptrConst(elf).node;
282 }
283 };
284};
285
286const Section = struct {
287 /// The node corresponding to this section.
288 ni: MappedFile.Node.Index,
289 /// A symbol which is exactly at the start of this section.
290 ///
291 /// If the section does not have flag `std.elf.SHF.ALLOC`, this is `.null`.
292 lsi: Symbol.LocalIndex,
293 rela_shndx: Section.Index,
194 rela_free: RelIndex,294 rela_free: RelIndex,
195295
196 pub const RelIndex = enum(u32) {296 pub const RelIndex = enum(u32) {
...@@ -207,394 +307,1165 @@ pub const Section = struct {...@@ -207,394 +307,1165 @@ pub const Section = struct {
207 };307 };
208 }308 }
209 };309 };
210};
211310
212pub const Symbol = struct {311 pub const Index = enum(Tag) {
213 ni: MappedFile.Node.Index,312 UNDEF = std.elf.SHN_UNDEF,
214 /// Relocations contained within this symbol313 LIVEPATCH = reserve(std.elf.SHN_LIVEPATCH),
215 loc_relocs: Reloc.Index,314 ABS = reserve(std.elf.SHN_ABS),
216 /// Relocations targeting this symbol315 COMMON = reserve(std.elf.SHN_COMMON),
217 target_relocs: Reloc.Index,
218 unused: u32,
219316
220 pub const Index = enum(u32) {317 symtab = 1,
221 null,
222 symtab,
223 shstrtab,318 shstrtab,
224 strtab,319 strtab,
225 rodata,320 rodata,
226 text,321 text,
227 data,322 data,
228 data_rel_ro,323 data_rel_ro,
229 got,324
230 got_plt,
231 plt,
232 plt_sec,
233 _,325 _,
234326
235 pub fn get(si: Symbol.Index, elf: *Elf) *Symbol {327 pub const Tag = u32;
236 return &elf.symtab.items[@intFromEnum(si)];328
329 pub const LORESERVE: Index = .fromSection(std.elf.SHN_LORESERVE);
330 pub const HIRESERVE: Index = .fromSection(std.elf.SHN_HIRESERVE);
331 comptime {
332 assert(@intFromEnum(HIRESERVE) == std.math.maxInt(Tag));
237 }333 }
238334
239 pub fn node(si: Symbol.Index, elf: *Elf) MappedFile.Node.Index {335 fn reserve(sec: std.elf.Section) Tag {
240 const ni = si.get(elf).ni;336 assert(sec >= std.elf.SHN_LORESERVE and sec <= std.elf.SHN_HIRESERVE);
241 assert(ni != .none);337 return @as(Tag, std.math.maxInt(Tag) - std.elf.SHN_HIRESERVE) + sec;
242 return ni;
243 }338 }
244339
245 pub fn next(si: Symbol.Index) Symbol.Index {340 pub fn fromSection(sec: std.elf.Section) Index {
246 return @enumFromInt(@intFromEnum(si) + 1);341 return switch (sec) {
342 std.elf.SHN_UNDEF...std.elf.SHN_LORESERVE - 1 => @enumFromInt(sec),
343 std.elf.SHN_LORESERVE...std.elf.SHN_HIRESERVE => @enumFromInt(reserve(sec)),
344 };
345 }
346 pub fn toSection(s: Index) ?std.elf.Section {
347 return switch (@intFromEnum(s)) {
348 std.elf.SHN_UNDEF...std.elf.SHN_LORESERVE - 1 => |sec| @intCast(sec),
349 std.elf.SHN_LORESERVE...reserve(std.elf.SHN_LORESERVE) - 1 => null,
350 reserve(std.elf.SHN_LORESERVE)...reserve(std.elf.SHN_HIRESERVE) => |sec| @intCast(
351 sec - reserve(std.elf.SHN_LORESERVE) + std.elf.SHN_LORESERVE,
352 ),
353 };
247 }354 }
248355
249 pub const Shndx = enum(Tag) {356 fn get(s: Index, elf: *Elf) *Section {
250 UNDEF = std.elf.SHN_UNDEF,357 return &elf.shdrs.items[@intFromEnum(s)];
251 LIVEPATCH = reserve(std.elf.SHN_LIVEPATCH),358 }
252 ABS = reserve(std.elf.SHN_ABS),
253 COMMON = reserve(std.elf.SHN_COMMON),
254 _,
255359
256 pub const Tag = u32;360 fn name(s: Index, elf: *Elf) [:0]const u8 {
361 const str: String(.shstrtab) = switch (elf.shdrPtr(s)) {
362 inline else => |shdr| @enumFromInt(elf.targetLoad(&shdr.name)),
363 };
364 return str.slice(elf);
365 }
257366
258 pub const LORESERVE: Shndx = .fromSection(std.elf.SHN_LORESERVE);367 fn vaddr(s: Index, elf: *Elf) u64 {
259 pub const HIRESERVE: Shndx = .fromSection(std.elf.SHN_HIRESERVE);368 return switch (s.get(elf).lsi) {
260 comptime {369 .null => 0,
261 assert(@intFromEnum(HIRESERVE) == std.math.maxInt(Tag));370 else => |lsi| Symbol.Id.local(lsi).value(elf),
262 }371 };
372 }
263373
264 fn reserve(sec: std.elf.Section) Tag {374 fn rename(shndx: Index, elf: *Elf, new_name: []const u8) !void {
265 assert(sec >= std.elf.SHN_LORESERVE and sec <= std.elf.SHN_HIRESERVE);375 const shstrtab_entry = try elf.string(.shstrtab, new_name);
266 return @as(Tag, std.math.maxInt(Tag) - std.elf.SHN_HIRESERVE) + sec;376 switch (elf.shdrPtr(shndx)) {
377 inline else => |shdr| elf.targetStore(&shdr.name, @intFromEnum(shstrtab_entry)),
267 }378 }
379 }
380 };
381};
382
383fn ensureUnusedSymbolCapacity(elf: *Elf, len: u32, kind: enum { all_local, maybe_global }) !void {
384 const gpa = elf.base.comp.gpa;
385
386 try elf.symtab.ensureUnusedCapacity(gpa, len);
387
388 // If adding locals, we may need to move one global out of the way for each local. If adding
389 // globals, they could all get demoted to STB_LOCAL, which would mean we move those N globals
390 // *and* we move up to N other globals out of their way.
391 try elf.changed_symtab_index.ensureUnusedCapacity(gpa, switch (kind) {
392 .all_local => len,
393 .maybe_global => len * 2,
394 });
395
396 {
397 // Ensure the symtab section's node is big enough
398 const need_node_size: u64 = switch (elf.shdrPtr(.symtab)) {
399 inline else => |shdr, class| elf.targetLoad(&shdr.size) + len * @sizeOf(class.ElfN().Sym),
400 };
401 _, const cur_node_size = Section.Index.symtab.get(elf).ni.location(&elf.mf).resolve(&elf.mf);
402 if (cur_node_size < need_node_size) {
403 const new_node_size = need_node_size +| need_node_size / MappedFile.growth_factor;
404 try Section.Index.symtab.get(elf).ni.resize(&elf.mf, gpa, new_node_size);
405 }
406 }
407
408 switch (kind) {
409 .all_local => {},
410 .maybe_global => {
411 try elf.globals.strong_def.ensureUnusedCapacity(gpa, len);
412 try elf.globals.weak_def.ensureUnusedCapacity(gpa, len);
413 try elf.globals.strong_undef.ensureUnusedCapacity(gpa, len);
414 try elf.globals.weak_undef.ensureUnusedCapacity(gpa, len);
415
416 try elf.node_global_symbols.ensureUnusedCapacity(gpa, len);
268417
269 pub fn fromSection(sec: std.elf.Section) Shndx {418 if (elf.shndx.dynsym != .UNDEF) {
270 return switch (sec) {419 // Ensure the `.dynsym` section's node is big enough
271 std.elf.SHN_UNDEF...std.elf.SHN_LORESERVE - 1 => @enumFromInt(sec),420 const dynsym_need_size: u64 = switch (elf.shdrPtr(elf.shndx.dynsym)) {
272 std.elf.SHN_LORESERVE...std.elf.SHN_HIRESERVE => @enumFromInt(reserve(sec)),421 inline else => |shdr, class| elf.targetLoad(&shdr.size) + len * @sizeOf(class.ElfN().Sym),
273 };422 };
423 _, const dynsym_cur_size = elf.shndx.dynsym.get(elf).ni.location(&elf.mf).resolve(&elf.mf);
424 if (dynsym_cur_size < dynsym_need_size) {
425 const new_size = dynsym_need_size +| dynsym_need_size / MappedFile.growth_factor;
426 try elf.shndx.dynsym.get(elf).ni.resize(&elf.mf, gpa, new_size);
427 }
428
429 try elf.got.plt.ensureUnusedCapacity(gpa, len);
430 const need_plt_capacity = elf.got.plt.count() + len;
431
432 switch (elf.ehdrField(.machine)) {
433 else => |machine| @panic(@tagName(machine)),
434 .X86_64 => {
435 // Ensure the `.plt` section's node is big enough
436 const plt_need_size: usize = 16 * (1 + need_plt_capacity);
437 _, const plt_cur_size = elf.shndx.plt.get(elf).ni.location(&elf.mf).resolve(&elf.mf);
438 if (plt_cur_size < plt_need_size) {
439 const new_size = plt_need_size +| plt_need_size / MappedFile.growth_factor;
440 try elf.shndx.plt.get(elf).ni.resize(&elf.mf, gpa, new_size);
441 }
442
443 // Ensure the `.got.plt` section's node is big enough
444 const got_plt_need_size: usize = switch (elf.identClass()) {
445 .NONE, _ => unreachable,
446 inline else => |class| @sizeOf(class.ElfN().Addr) * (3 + need_plt_capacity),
447 };
448 _, const got_plt_cur_size = elf.shndx.got_plt.get(elf).ni.location(&elf.mf).resolve(&elf.mf);
449 if (got_plt_cur_size < got_plt_need_size) {
450 const new_size = got_plt_need_size +| got_plt_need_size / MappedFile.growth_factor;
451 try elf.shndx.got_plt.get(elf).ni.resize(&elf.mf, gpa, new_size);
452 }
453
454 // Ensure the `.plt.sec` section's node is big enough
455 const plt_sec_need_size: usize = 16 * need_plt_capacity;
456 _, const plt_sec_cur_size = elf.shndx.plt_sec.get(elf).ni.location(&elf.mf).resolve(&elf.mf);
457 if (plt_sec_cur_size < plt_sec_need_size) {
458 const new_size = plt_sec_need_size +| plt_sec_need_size / MappedFile.growth_factor;
459 try elf.shndx.plt_sec.get(elf).ni.resize(&elf.mf, gpa, new_size);
460 }
461
462 // Ensure the `.rela.plt` section's node is big enough
463 const rela_plt_shndx = elf.shndx.got_plt.get(elf).rela_shndx;
464 const rela_plt_need_size: usize = switch (elf.shdrPtr(rela_plt_shndx)) {
465 inline else => |shdr| @intCast(elf.targetLoad(&shdr.entsize) * need_plt_capacity),
466 };
467 _, const rela_plt_cur_size = rela_plt_shndx.get(elf).ni.location(&elf.mf).resolve(&elf.mf);
468 if (rela_plt_cur_size < rela_plt_need_size) {
469 const new_size = rela_plt_need_size +| rela_plt_need_size / MappedFile.growth_factor;
470 try rela_plt_shndx.get(elf).ni.resize(&elf.mf, gpa, new_size);
471 } else {
472 // Still mark `.rela.plt` as resized so that the DT_PLTRELSZ entry can
473 // be updated if we do indeed add a PLT entry.
474 try rela_plt_shndx.get(elf).ni.resized(gpa, &elf.mf);
475 }
476 },
477 }
274 }478 }
275 pub fn toSection(s: Shndx) ?std.elf.Section {479 },
276 return switch (@intFromEnum(s)) {480 }
277 std.elf.SHN_UNDEF...std.elf.SHN_LORESERVE - 1 => |sec| @intCast(sec),481}
278 std.elf.SHN_LORESERVE...reserve(std.elf.SHN_LORESERVE) - 1 => null,482
279 reserve(std.elf.SHN_LORESERVE)...reserve(std.elf.SHN_HIRESERVE) => |sec| @intCast(483const AddLocalSymbolOptions = struct {
280 sec - reserve(std.elf.SHN_LORESERVE) + std.elf.SHN_LORESERVE,484 node: MappedFile.Node.Index,
281 ),485 name: String(.strtab),
282 };486 value: u64,
487 size: u64,
488 type: std.elf.STT,
489 shndx: Section.Index,
490};
491fn addLocalSymbolAssumeCapacity(elf: *Elf, opts: AddLocalSymbolOptions) Symbol.LocalIndex {
492 switch (elf.shdrPtr(.symtab)) {
493 inline else => |shdr, class| {
494 const ent_size = @sizeOf(class.ElfN().Sym);
495
496 // `shdr.info` stores the index of the first global symbol. We will replace it with our
497 // new local symbol, and move the global symbol to a new index at the end of the symtab.
498 const target_index: Symbol.Index = @enumFromInt(elf.targetLoad(&shdr.info));
499
500 const old_size = elf.targetLoad(&shdr.size);
501 const new_size = old_size + ent_size;
502
503 assert(elf.symtab.items.len == @divExact(old_size, ent_size));
504
505 elf.targetStore(&shdr.info, @intFromEnum(target_index) + 1);
506 elf.targetStore(&shdr.size, new_size);
507
508 const new_index: Symbol.Index = @enumFromInt(elf.symtab.items.len);
509 elf.symtab.appendAssumeCapacity(undefined);
510
511 const target_sym = @field(elf.symPtr(target_index), @tagName(class));
512
513 if (target_index != new_index) {
514 // Move the global at `target_index` to `new_index`. First the symtab entry...
515 const new_sym = @field(elf.symPtr(new_index), @tagName(class));
516 new_sym.* = target_sym.*;
517 // ...then the `elf.symtab` metadata...
518 new_index.ptr(elf).* = target_index.ptr(elf).*;
519 // ...then update the `elf.globals` tracking.
520 const global_name: String(.strtab) = @enumFromInt(elf.targetLoad(&new_sym.name));
521 elf.globalByName(global_name).?.symtab_index = new_index;
522
523 if (target_index.ptr(elf).first_target_reloc != .none) {
524 // This symbol's index is changing, so queue an update of relocs targeting it.
525 elf.changed_symtab_index.putAssumeCapacity(global_name, {});
526 }
283 }527 }
284528
285 pub fn get(s: Shndx, elf: *Elf) *Section {529 target_index.ptr(elf).* = .{
286 return &elf.shdrs.items[@intFromEnum(s)];530 .node = opts.node,
531 .first_target_reloc = .none,
532 };
533
534 target_sym.* = .{
535 .name = @intFromEnum(opts.name),
536 .value = @intCast(opts.value),
537 .size = @intCast(opts.size),
538 .info = .{ .type = opts.type, .bind = .LOCAL },
539 .other = .{ .visibility = .DEFAULT },
540 .shndx = opts.shndx.toSection().?,
541 };
542 if (elf.targetEndian() != native_endian) {
543 std.mem.byteSwapAllFields(class.ElfN().Sym, target_sym);
287 }544 }
288 };
289 pub fn shndx(si: Symbol.Index, elf: *Elf) Shndx {
290 return .fromSection(switch (elf.symPtr(si)) {
291 inline else => |sym| elf.targetLoad(&sym.shndx),
292 });
293 }
294545
295 pub const InitOptions = struct {546 return @enumFromInt(@intFromEnum(target_index));
296 name: []const u8 = "",547 },
297 lib_name: ?[]const u8 = null,548 }
298 value: u64 = 0,549}
299 size: u64 = 0,550
300 type: std.elf.STT,551const AddGlobalSymbolOptions = struct {
301 bind: std.elf.STB = .LOCAL,552 const Name = struct {
302 visibility: std.elf.STV = .DEFAULT,553 strtab: String(.strtab),
303 shndx: Shndx = .UNDEF,554 dynstr: String(.dynstr),
304 };555 fn string(elf: *Elf, slice: []const u8) !Name {
305 pub fn init(si: Symbol.Index, elf: *Elf, opts: InitOptions) !void {556 return .{
306 const comp = elf.base.comp;557 .strtab = try elf.string(.strtab, slice),
307 const gpa = comp.gpa;558 .dynstr = switch (elf.shndx.dynsym) {
308 const target_endian = elf.targetEndian();559 .UNDEF => .empty,
309 const name_strtab_entry = try elf.string(.strtab, opts.name);560 else => try elf.string(.dynstr, slice),
310 switch (elf.shdrPtr(elf.si.symtab.shndx(elf))) {
311 inline else => |shdr| {
312 const old_size = elf.targetLoad(&shdr.size);
313 const ent_size = elf.targetLoad(&shdr.entsize);
314 const new_size = ent_size * elf.symtab.items.len;
315 if (new_size > old_size) {
316 elf.targetStore(&shdr.size, @intCast(new_size));
317 const symtab_ni = elf.si.symtab.node(elf);
318 _, const node_size = symtab_ni.location(&elf.mf).resolve(&elf.mf);
319 if (new_size > node_size) try symtab_ni.resize(
320 &elf.mf,
321 gpa,
322 new_size +| new_size / MappedFile.growth_factor,
323 );
324 }
325 },561 },
562 };
563 }
564 };
565
566 node: MappedFile.Node.Index,
567 name: Name,
568 lib_name: ?[]const u8 = null,
569 value: u64,
570 size: u64,
571 type: std.elf.STT,
572 bind: enum { strong, weak },
573 visibility: std.elf.STV,
574 shndx: Section.Index,
575};
576fn addGlobalSymbolAssumeCapacity(elf: *Elf, opts: AddGlobalSymbolOptions) error{MultipleDefinitions}!Symbol.Id {
577 _ = opts.lib_name; // TODO
578
579 if (elf.shndx.dynsym == .UNDEF) {
580 assert(opts.name.dynstr == .empty);
581 } else {
582 assert(std.mem.eql(u8, opts.name.dynstr.slice(elf), opts.name.strtab.slice(elf)));
583 }
584
585 // We break from this `switch` only if this symbol name did not previously exist at all and so
586 // we have added a new entry to one of the maps in `elf.globals`. In that case we actually need
587 // a new symtab entry.
588 const new_global_ptr: *Symbol.Global = if (opts.shndx != .UNDEF) switch (opts.bind) {
589 .strong => new_global: {
590 const gop = elf.globals.strong_def.getOrPutAssumeCapacity(opts.name.strtab);
591 if (gop.found_existing) return error.MultipleDefinitions;
592 const old_kv = elf.globals.weak_def.fetchSwapRemove(opts.name.strtab) orelse
593 elf.globals.strong_undef.fetchSwapRemove(opts.name.strtab) orelse
594 elf.globals.weak_undef.fetchSwapRemove(opts.name.strtab) orelse {
595 // The symbol did not already exist, so we'll use the "new global" path.
596 break :new_global gop.value_ptr;
597 };
598 gop.value_ptr.* = old_kv.value;
599 elf.setGlobalSymbolValue(opts.name.strtab, gop.value_ptr, .{
600 .node = opts.node,
601 .value = opts.value,
602 .size = opts.size,
603 .type = opts.type,
604 .shndx = opts.shndx,
605 });
606 elf.mergeGlobalSymbolVisibility(gop.value_ptr, opts.visibility, .strong);
607 return .global(opts.name.strtab);
608 },
609 .weak => new_global: {
610 if (elf.globals.strong_def.getPtr(opts.name.strtab)) |global| {
611 // The existing definition holds, we just merge our visibility in.
612 elf.mergeGlobalSymbolVisibility(global, opts.visibility, .strong);
613 return .global(opts.name.strtab);
326 }614 }
327 switch (elf.symPtr(si)) {615 const gop = elf.globals.weak_def.getOrPutAssumeCapacity(opts.name.strtab);
328 inline else => |sym, class| {616 if (gop.found_existing) {
617 // The existing definition holds, we just merge our visibility in.
618 elf.mergeGlobalSymbolVisibility(gop.value_ptr, opts.visibility, .weak);
619 return .global(opts.name.strtab);
620 }
621 const old_kv = elf.globals.strong_undef.fetchSwapRemove(opts.name.strtab) orelse
622 elf.globals.weak_undef.fetchSwapRemove(opts.name.strtab) orelse {
623 // The symbol did not already exist, so we'll use the "new global" path.
624 break :new_global gop.value_ptr;
625 };
626 gop.value_ptr.* = old_kv.value;
627 elf.setGlobalSymbolValue(opts.name.strtab, gop.value_ptr, .{
628 .node = opts.node,
629 .value = opts.value,
630 .size = opts.size,
631 .type = opts.type,
632 .shndx = opts.shndx,
633 });
634 elf.mergeGlobalSymbolVisibility(gop.value_ptr, opts.visibility, .weak);
635 return .global(opts.name.strtab);
636 },
637 } else switch (opts.bind) {
638 .strong => new_global: {
639 if (elf.globals.strong_def.getPtr(opts.name.strtab)) |global| {
640 // The existing definition holds, we just merge our visibility in.
641 elf.mergeGlobalSymbolVisibility(global, opts.visibility, .strong);
642 return .global(opts.name.strtab);
643 }
644 if (elf.globals.weak_def.getPtr(opts.name.strtab)) |global| {
645 // The existing definition holds, we just merge our visibility in.
646 elf.mergeGlobalSymbolVisibility(global, opts.visibility, .weak);
647 return .global(opts.name.strtab);
648 }
649 const gop = elf.globals.strong_undef.getOrPutAssumeCapacity(opts.name.strtab);
650 if (gop.found_existing) {
651 // The existing symbol is okay, we just merge our visibility in.
652 elf.mergeGlobalSymbolVisibility(gop.value_ptr, opts.visibility, .strong);
653 return .global(opts.name.strtab);
654 }
655 const old_kv = elf.globals.weak_undef.fetchSwapRemove(opts.name.strtab) orelse {
656 // The symbol did not already exist, so we'll use the "new global" path.
657 break :new_global gop.value_ptr;
658 };
659 gop.value_ptr.* = old_kv.value;
660 elf.mergeGlobalSymbolVisibility(gop.value_ptr, opts.visibility, .strong);
661 return .global(opts.name.strtab);
662 },
663 .weak => new_global: {
664 if (elf.globals.strong_def.getPtr(opts.name.strtab) orelse
665 elf.globals.strong_undef.getPtr(opts.name.strtab)) |global|
666 {
667 // The existing symbol is okay, we just merge our visibility in.
668 elf.mergeGlobalSymbolVisibility(global, opts.visibility, .strong);
669 return .global(opts.name.strtab);
670 }
671 if (elf.globals.weak_def.getPtr(opts.name.strtab)) |global| {
672 // The existing symbol is okay, we just merge our visibility in.
673 elf.mergeGlobalSymbolVisibility(global, opts.visibility, .weak);
674 return .global(opts.name.strtab);
675 }
676 const gop = elf.globals.weak_undef.getOrPutAssumeCapacity(opts.name.strtab);
677 if (gop.found_existing) {
678 // The existing symbol is okay, we just merge our visibility in.
679 elf.mergeGlobalSymbolVisibility(gop.value_ptr, opts.visibility, .weak);
680 return .global(opts.name.strtab);
681 }
682 break :new_global gop.value_ptr;
683 },
684 };
685
686 const force_local_bind: bool = switch (opts.visibility) {
687 .HIDDEN, .INTERNAL => elf.ehdrField(.type) != .REL,
688 .PROTECTED, .DEFAULT => false,
689 };
690
691 const bind: std.elf.STB = if (force_local_bind) b: {
692 break :b .LOCAL;
693 } else switch (opts.bind) {
694 .strong => .GLOBAL,
695 .weak => .WEAK,
696 };
697
698 const sym_index: Symbol.Index = @enumFromInt(elf.symtab.items.len);
699 elf.symtab.appendAssumeCapacity(.{
700 .node = opts.node,
701 .first_target_reloc = .none,
702 });
703 switch (elf.shdrPtr(.symtab)) {
704 inline else => |shdr, class| {
705 const Sym = class.ElfN().Sym;
706 // Increase the symtab size...
707 const old_size = elf.targetLoad(&shdr.size);
708 assert(old_size == @intFromEnum(sym_index) * @sizeOf(Sym));
709 elf.targetStore(&shdr.size, old_size + @sizeOf(Sym));
710 // ...then populate the newly-valid symbol pointer
711 const sym = @field(elf.symPtr(sym_index), @tagName(class));
712 sym.* = .{
713 .name = @intFromEnum(opts.name.strtab),
714 .value = @intCast(opts.value),
715 .size = @intCast(opts.size),
716 .info = .{ .type = opts.type, .bind = bind },
717 .other = .{ .visibility = opts.visibility },
718 .shndx = opts.shndx.toSection().?,
719 };
720 if (elf.targetEndian() != native_endian) {
721 std.mem.byteSwapAllFields(Sym, sym);
722 }
723 },
724 }
725
726 const old_head: String(.strtab) = old_head: {
727 if (opts.node == .none) break :old_head .empty;
728 const gop = elf.node_global_symbols.getOrPutAssumeCapacity(opts.node);
729 const old_head: String(.strtab) = if (gop.found_existing) gop.value_ptr.* else .empty;
730 gop.value_ptr.* = opts.name.strtab;
731 break :old_head old_head;
732 };
733
734 new_global_ptr.* = .{
735 .symtab_index = sym_index,
736 .dynsym_index = dynsym_index: {
737 if (elf.shndx.dynsym == .UNDEF) break :dynsym_index 0;
738 if (force_local_bind) break :dynsym_index 0;
739 switch (elf.shdrPtr(elf.shndx.dynsym)) {
740 inline else => |shdr, class| {
329 const Sym = class.ElfN().Sym;741 const Sym = class.ElfN().Sym;
742 // Increase the dynamic symbol table size...
743 const old_size = elf.targetLoad(&shdr.size);
744 elf.targetStore(&shdr.size, old_size + @sizeOf(Sym));
745 const dynsym_index: u32 = @intCast(@divExact(old_size, @sizeOf(Sym)));
746 // ...then populate the newly-valid symbol pointer
747 const sym = @field(elf.dynsymPtr(dynsym_index), @tagName(class));
330 sym.* = .{748 sym.* = .{
331 .name = name_strtab_entry,749 .name = @intFromEnum(opts.name.dynstr),
332 .value = @intCast(opts.value),750 .value = @intCast(opts.value),
333 .size = @intCast(opts.size),751 .size = @intCast(opts.size),
334 .info = .{ .type = opts.type, .bind = opts.bind },752 .info = .{ .type = opts.type, .bind = bind },
335 .other = .{ .visibility = opts.visibility },753 .other = .{ .visibility = opts.visibility },
336 .shndx = opts.shndx.toSection().?,754 .shndx = opts.shndx.toSection().?,
337 };755 };
338 if (target_endian != native_endian) std.mem.byteSwapAllFields(Sym, sym);756 if (elf.targetEndian() != native_endian) {
757 std.mem.byteSwapAllFields(Sym, sym);
758 }
759 break :dynsym_index dynsym_index;
339 },760 },
340 }761 }
341 switch (elf.shdrPtr(elf.si.symtab.shndx(elf))) {762 },
342 inline else => |shdr| elf.targetStore(&shdr.info, @max(763 .prev_in_node = .empty,
343 elf.targetLoad(&shdr.info),764 .next_in_node = old_head,
344 @intFromEnum(si) + 1,765 };
345 )),
346 }
347766
348 if (opts.bind == .LOCAL) return;767 if (old_head != .empty) {
349 no_entry: {768 const old_head_ptr = elf.globalByName(old_head).?;
350 if (std.mem.eql(u8, opts.name, entry: switch (elf.options.entry) {769 assert(old_head_ptr.symtab_index.ptr(elf).node == opts.node);
351 .default => switch (comp.config.output_mode) {770 assert(old_head_ptr.prev_in_node == .empty);
352 .Exe => continue :entry .enabled,771 old_head_ptr.prev_in_node = opts.name.strtab;
353 .Lib, .Obj => continue :entry .disabled,772 }
354 },773
355 .disabled => break :no_entry,774 if (force_local_bind) {
356 .enabled => "_start",775 elf.moveDemotedGlobal(new_global_ptr);
357 .named => |named| named,776 }
358 })) {777
359 elf.si.entry = si;778 if (new_global_ptr.dynsym_index != 0 and
360 switch (elf.ehdrPtr()) {779 opts.visibility == .DEFAULT and
361 inline else => |ehdr| elf.targetStore(&ehdr.entry, @intCast(opts.value)),780 opts.shndx == .UNDEF and
362 }781 opts.type == .FUNC)
363 }782 {
783 // We're adding an undefined global STT_FUNC symbol which could be resolved by another DSO.
784 // We therefore might need a PLT entry, so let's add one now. TODO: it'd be good to remove
785 // the PLT entry if we later discover a link inpu which resolves this reference.
786 elf.addPltEntry(opts.name.strtab, new_global_ptr.dynsym_index);
787 }
788
789 return .global(opts.name.strtab);
790}
791fn setGlobalSymbolValue(
792 elf: *Elf,
793 global_name: String(.strtab),
794 global_ptr: *Symbol.Global,
795 new: struct {
796 node: MappedFile.Node.Index,
797 value: u64,
798 size: u64,
799 type: std.elf.STT,
800 shndx: Section.Index,
801 },
802) void {
803 const old_node = global_ptr.symtab_index.ptr(elf).node;
804 if (old_node != .none) {
805 if (global_ptr.next_in_node != .empty) {
806 const next = elf.globalByName(global_ptr.next_in_node).?;
807 assert(next.prev_in_node == global_name);
808 assert(next.symtab_index.ptr(elf).node == old_node);
809 next.prev_in_node = global_ptr.prev_in_node;
810 }
811 if (global_ptr.prev_in_node != .empty) {
812 const prev = elf.globalByName(global_ptr.prev_in_node).?;
813 assert(prev.next_in_node == global_name);
814 assert(prev.symtab_index.ptr(elf).node == old_node);
815 prev.next_in_node = global_ptr.next_in_node;
816 } else {
817 // We're the start of the linked list, so we need to change the head.
818 if (global_ptr.next_in_node == .empty) {
819 assert(elf.node_global_symbols.fetchSwapRemove(old_node).?.value == global_name);
820 } else {
821 elf.node_global_symbols.getPtr(old_node).?.* = global_ptr.next_in_node;
364 }822 }
823 }
824 } else {
825 assert(global_ptr.next_in_node == .empty);
826 assert(global_ptr.prev_in_node == .empty);
827 }
365828
366 if (elf.si.dynsym == .null) return;829 global_ptr.symtab_index.ptr(elf).node = new.node;
367 const dsi = elf.dynsym.count();830
368 try elf.dynsym.putNoClobber(gpa, si, {});831 const old_head: String(.strtab) = old_head: {
369 const name_dynstr_entry = try elf.string(.dynstr, opts.name);832 if (new.node == .none) break :old_head .empty;
370 switch (elf.shdrPtr(elf.si.dynsym.shndx(elf))) {833 const gop = elf.node_global_symbols.getOrPutAssumeCapacity(new.node);
371 inline else => |shdr| {834 const old_head: String(.strtab) = if (gop.found_existing) gop.value_ptr.* else .empty;
372 const old_size = elf.targetLoad(&shdr.size);835 gop.value_ptr.* = global_name;
373 const ent_size = elf.targetLoad(&shdr.entsize);836 break :old_head old_head;
374 const new_size = ent_size * elf.dynsym.count();837 };
375 if (new_size > old_size) {838
376 elf.targetStore(&shdr.size, @intCast(new_size));839 global_ptr.prev_in_node = .empty;
377 const dynsym_ni = elf.si.dynsym.node(elf);840 global_ptr.next_in_node = old_head;
378 _, const node_size = dynsym_ni.location(&elf.mf).resolve(&elf.mf);841
379 if (new_size > node_size) try dynsym_ni.resize(842 if (old_head != .empty) {
380 &elf.mf,843 const old_head_ptr = elf.globalByName(old_head).?;
381 gpa,844 assert(old_head_ptr.symtab_index.ptr(elf).node == new.node);
382 new_size +| new_size / MappedFile.growth_factor,845 assert(old_head_ptr.prev_in_node == .empty);
383 );846 old_head_ptr.prev_in_node = global_name;
384 }847 }
848
849 // Now for the easy bit where we actually update the symtab entry.
850 switch (elf.symPtr(global_ptr.symtab_index)) {
851 inline else => |sym| {
852 // Don't bother with `sym.value` here: it'll be updated by `flushMoved`.
853 elf.targetStore(&sym.size, @intCast(new.size));
854 elf.targetStore(&sym.shndx, new.shndx.toSection().?);
855 const old_bind = elf.targetLoad(&sym.info).bind;
856 elf.targetStore(&sym.info, .{
857 .type = new.type,
858 .bind = old_bind,
859 });
860 },
861 }
862
863 // ...and also the dynsym entry if there is one.
864 if (global_ptr.dynsym_index != 0) switch (elf.dynsymPtr(global_ptr.dynsym_index)) {
865 inline else => |sym| {
866 // Don't bother with `sym.value` here: it'll be updated by `flushMoved`.
867 elf.targetStore(&sym.size, @intCast(new.size));
868 elf.targetStore(&sym.shndx, new.shndx.toSection().?);
869 const old_bind = elf.targetLoad(&sym.info).bind;
870 elf.targetStore(&sym.info, .{
871 .type = new.type,
872 .bind = old_bind,
873 });
874 },
875 };
876
877 global_ptr.flushMoved(elf, new.value);
878}
879/// When the same global symbol appears in two inputs---even if one symbol is defined and the other
880/// undefined---their visibility values are combined to determine the resulting visibility, which
881/// can also affect the bind of the symbol we output.
882fn mergeGlobalSymbolVisibility(elf: *Elf, global_ptr: *Symbol.Global, other_visibility: std.elf.STV, bind: enum { strong, weak }) void {
883 const old_visibility: std.elf.STV = switch (elf.symPtr(global_ptr.symtab_index)) {
884 inline else => |sym| elf.targetLoad(&sym.other).visibility,
885 };
886 // The combined visibility is essentially the "strictest" of the two, with most strict being
887 // INTERNAL, followed by HIDDEN, PROTECTED, DEFAULT.
888 const new_visibility: std.elf.STV, const newly_hidden: bool = switch (old_visibility) {
889 .INTERNAL => .{ .INTERNAL, false },
890 .HIDDEN => switch (other_visibility) {
891 .INTERNAL => .{ .INTERNAL, false },
892 .HIDDEN, .PROTECTED, .DEFAULT => .{ .HIDDEN, false },
893 },
894 .PROTECTED => switch (other_visibility) {
895 .INTERNAL => .{ .INTERNAL, true },
896 .HIDDEN => .{ .HIDDEN, true },
897 .PROTECTED, .DEFAULT => .{ .PROTECTED, false },
898 },
899 .DEFAULT => switch (other_visibility) {
900 .INTERNAL => .{ .INTERNAL, true },
901 .HIDDEN => .{ .HIDDEN, true },
902 .PROTECTED => .{ .PROTECTED, false },
903 .DEFAULT => .{ .DEFAULT, false },
904 },
905 };
906 // If the symbol is HIDDEN/INTERNAL and we're emitting an ELF module (executable or shared
907 // object), then the symbol should have binding STB_LOCAL in the output. Therefore, if we are
908 // putting the global in this state for the first time---let's call it "demoting" the global to
909 // STB_LOCAL---we need to update its bind in the symtab.
910 const demote_to_local = newly_hidden and elf.ehdrField(.type) != .REL;
911 switch (elf.symPtr(global_ptr.symtab_index)) {
912 inline else => |sym, class| {
913 const old_info = elf.targetLoad(&sym.info);
914 const new_info: class.ElfN().Sym.Info = .{
915 .type = old_info.type,
916 .bind = if (demote_to_local) b: {
917 assert(old_info.bind != .LOCAL);
918 break :b .LOCAL;
919 } else if (old_info.bind == .LOCAL) .LOCAL else switch (bind) {
920 .strong => .GLOBAL,
921 .weak => .WEAK,
385 },922 },
923 };
924 elf.targetStore(&sym.other, .{ .visibility = new_visibility });
925 elf.targetStore(&sym.info, new_info);
926 // also update dynsym
927 if (global_ptr.dynsym_index != 0) {
928 const dynsym = @field(elf.dynsymPtr(global_ptr.dynsym_index), @tagName(class));
929 elf.targetStore(&dynsym.other, .{ .visibility = new_visibility });
930 elf.targetStore(&dynsym.info, new_info);
386 }931 }
387 switch (elf.dynsymSlice()) {932 },
388 inline else => |dynsyms, class| {933 }
389 const Sym = class.ElfN().Sym;934 if (demote_to_local) {
390 const dynsym = &dynsyms[dsi];935 // When demoting a global to STB_LOCAL, we need to move its symtab index so that it is with
391 dynsym.* = .{936 // the STB_LOCAL symbols instead of the global symbols.
392 .name = name_dynstr_entry,937 elf.moveDemotedGlobal(global_ptr);
393 .value = @intCast(opts.value),938 }
394 .size = @intCast(opts.size),939}
395 .info = .{ .type = opts.type, .bind = opts.bind },940/// If a symbol which was STB_GLOBAL/STB_WEAK becomes STB_LOCAL (see `mergeGlobalSymbolVisibility`),
396 .other = .{ .visibility = opts.visibility },941/// the symbol must be moved from the "globals" part of the symtab to the "locals" part, because ELF
397 .shndx = opts.shndx.toSection().?,942/// requires that all STB_LOCAL symbols in a symbol table appear before any global symbols.
398 };943fn moveDemotedGlobal(elf: *Elf, global_ptr: *Symbol.Global) void {
399 if (target_endian != native_endian) std.mem.byteSwapAllFields(Sym, dynsym);944 assert(elf.ehdrField(.type) != .REL); // demotion only happens when emitting an ELF module
400 },945 switch (elf.shdrPtr(.symtab)) {
946 inline else => |shdr, class| {
947 // `shdr.info` stores the index of the first global symbol. We are going to swap the
948 // demoted symbol with that first global symbol, then increment that start index.
949 const dest_index: Symbol.Index = @enumFromInt(elf.targetLoad(&shdr.info));
950 const src_index = global_ptr.symtab_index;
951
952 // This global should currently be in the "global symbols" part of the symtab, since our
953 // job is to move it *out* of that part:
954 assert(@intFromEnum(src_index) >= @intFromEnum(dest_index));
955
956 elf.targetStore(&shdr.info, @intFromEnum(dest_index) + 1);
957
958 if (src_index == dest_index) {
959 // The demoted global was already the first global, so we don't need to do any swap.
960 return;
401 }961 }
402962
403 if (opts.type != .FUNC or opts.shndx != .UNDEF) return;963 const src_sym_ptr = @field(elf.symPtr(src_index), @tagName(class));
404 const plt_index: u32 = @intCast(elf.got.plt.count());964 const dest_sym_ptr = @field(elf.symPtr(dest_index), @tagName(class));
405 try elf.got.plt.putNoClobber(gpa, si, {});
406 switch (elf.ehdrField(.machine)) {
407 else => |machine| @panic(@tagName(machine)),
408 .X86_64 => {
409 const plt_ni = elf.si.plt.node(elf);
410 _, const plt_node_size = plt_ni.location(&elf.mf).resolve(&elf.mf);
411 const plt_addr = plt_addr: switch (elf.shdrPtr(elf.si.plt.shndx(elf))) {
412 inline else => |shdr| {
413 const old_size = 16 * (1 + plt_index);
414 const new_size = old_size + 16;
415 elf.targetStore(&shdr.size, new_size);
416 if (new_size > plt_node_size) try plt_ni.resize(
417 &elf.mf,
418 gpa,
419 new_size +| new_size / MappedFile.growth_factor,
420 );
421 const plt_slice = plt_ni.slice(&elf.mf)[old_size..new_size];
422 @memcpy(plt_slice, &[16]u8{
423 0xf3, 0x0f, 0x1e, 0xfa, // endbr64
424 0x68, 0x00, 0x00, 0x00, 0x00, // push $0x0
425 0xe9, 0x00, 0x00, 0x00, 0x00, // jmp 0
426 0x66, 0x90, // xchg %ax,%ax
427 });
428 std.mem.writeInt(u32, plt_slice[5..][0..4], plt_index, target_endian);
429 std.mem.writeInt(
430 i32,
431 plt_slice[10..][0..4],
432 2 - @as(i32, @intCast(new_size)),
433 target_endian,
434 );
435 break :plt_addr elf.targetLoad(&shdr.addr) + old_size;
436 },
437 };
438965
439 const got_plt_shndx = elf.si.got_plt.shndx(elf);966 const this_name: String(.strtab) = @enumFromInt(elf.targetLoad(&src_sym_ptr.name));
440 const got_plt_ni = elf.si.got_plt.node(elf);967 assert(elf.globalByName(this_name).? == global_ptr);
441 _, const got_plt_node_size = got_plt_ni.location(&elf.mf).resolve(&elf.mf);968 if (global_ptr.symtab_index.ptr(elf).first_target_reloc != .none) {
442 const got_plt_addr = got_plt_addr: switch (elf.shdrPtr(got_plt_shndx)) {969 // This symbol's index is changing, so queue an update of relocs targeting it.
443 inline else => |shdr, class| {970 elf.changed_symtab_index.putAssumeCapacity(this_name, {});
444 const Addr = class.ElfN().Addr;971 }
445 const addr_size = @sizeOf(Addr);972
446 const old_size = addr_size * (3 + plt_index);973 const other_name: String(.strtab) = @enumFromInt(elf.targetLoad(&dest_sym_ptr.name));
447 const new_size = old_size + addr_size;974 const other_global_ptr = elf.globalByName(other_name).?;
448 elf.targetStore(&shdr.size, new_size);975 assert(other_global_ptr.symtab_index == dest_index);
449 if (new_size > got_plt_node_size) try got_plt_ni.resize(976 if (other_global_ptr.symtab_index.ptr(elf).first_target_reloc != .none) {
450 &elf.mf,977 // This other symbol's index is changing, so queue an update of relocs targeting it.
451 gpa,978 elf.changed_symtab_index.putAssumeCapacity(other_name, {});
452 new_size +| new_size / MappedFile.growth_factor,979 }
453 );980
454 std.mem.writeInt(981 // First swap the symtab entries...
455 Addr,982 std.mem.swap(class.ElfN().Sym, src_sym_ptr, dest_sym_ptr);
456 got_plt_ni.slice(&elf.mf)[old_size..][0..addr_size],983 // ...then the `elf.symtab` metadata...
457 @intCast(plt_addr),984 std.mem.swap(Symbol, src_index.ptr(elf), dest_index.ptr(elf));
458 target_endian,985 // ...then update the `elf.globals` tracking.
459 );986 global_ptr.symtab_index = dest_index;
460 break :got_plt_addr elf.targetLoad(&shdr.addr) + old_size;987 other_global_ptr.symtab_index = src_index;
461 },988
462 };989 // We also need to get rid of the dynsym entry if there is one. For simplicity, just
990 // replace it with a dummy entry which will never be used and will not cause problems.
991 // TODO: we should have a free-list of dynsym slots so that other symbols can go here.
992 // TODO: it would also be best to just avoid having gaps in the dynsym altogether.
993 if (global_ptr.dynsym_index != 0) {
994 const dynsym = @field(elf.dynsymPtr(global_ptr.dynsym_index), @tagName(class));
995 dynsym.* = .{
996 .name = @intFromEnum(String(.dynstr).empty),
997 .value = 0,
998 .size = 0,
999 .info = .{
1000 .type = .NOTYPE,
1001 // STB_WEAK is important: we mustn't cause a dynamic linker error if the
1002 // symbol can't be resolved.
1003 .bind = .WEAK,
1004 },
1005 // SHN_UNDEF is important: we mustn't define this symbol for other DSOs.
1006 .shndx = std.elf.SHN_UNDEF,
1007 .other = .{ .visibility = .DEFAULT },
1008 };
1009 if (elf.targetEndian() != native_endian) {
1010 std.mem.byteSwapAllFields(class.ElfN().Sym, dynsym);
1011 }
1012 }
1013 },
1014 }
1015}
1016fn addPltEntry(elf: *Elf, global_name: String(.strtab), dynsym_index: u32) void {
1017 const target_endian = elf.targetEndian();
1018 const plt_index: u32 = @intCast(elf.got.plt.count());
1019 elf.got.plt.putAssumeCapacityNoClobber(.global(global_name), {});
1020 switch (elf.ehdrField(.machine)) {
1021 else => |machine| @panic(@tagName(machine)),
1022 .X86_64 => {
1023 const plt_ni = elf.shndx.plt.get(elf).ni;
1024 const plt_addr = plt_addr: switch (elf.shdrPtr(elf.shndx.plt)) {
1025 inline else => |shdr| {
1026 const old_size = 16 * (1 + plt_index);
1027 assert(elf.targetLoad(&shdr.size) == old_size);
1028 elf.targetStore(&shdr.size, old_size + 16);
1029 const plt_slice = plt_ni.slice(&elf.mf)[old_size..][0..16];
1030 @memcpy(plt_slice, &[16]u8{
1031 0xf3, 0x0f, 0x1e, 0xfa, // endbr64
1032 0x68, 0x00, 0x00, 0x00, 0x00, // push $0x0
1033 0xe9, 0x00, 0x00, 0x00, 0x00, // jmp 0
1034 0x66, 0x90, // xchg %ax,%ax
1035 });
1036 std.mem.writeInt(u32, plt_slice[5..][0..4], plt_index, target_endian);
1037 std.mem.writeInt(
1038 i32,
1039 plt_slice[10..][0..4],
1040 -@as(i32, @intCast(old_size + 14)),
1041 target_endian,
1042 );
1043 break :plt_addr elf.targetLoad(&shdr.addr) + old_size;
1044 },
1045 };
1046
1047 const got_plt_shndx = elf.shndx.got_plt;
1048 const got_plt_ni = elf.shndx.got_plt.get(elf).ni;
1049 const got_plt_addr = got_plt_addr: switch (elf.shdrPtr(got_plt_shndx)) {
1050 inline else => |shdr, class| {
1051 const ent_size = @sizeOf(class.ElfN().Addr);
1052 const old_size = ent_size * (3 + plt_index);
1053 elf.targetStore(&shdr.size, old_size + ent_size);
1054 std.mem.writeInt(
1055 class.ElfN().Addr,
1056 got_plt_ni.slice(&elf.mf)[old_size..][0..ent_size],
1057 @intCast(plt_addr),
1058 target_endian,
1059 );
1060 break :got_plt_addr elf.targetLoad(&shdr.addr) + old_size;
1061 },
1062 };
4631063
464 const plt_sec_ni = elf.si.plt_sec.node(elf);1064 const plt_sec_ni = elf.shndx.plt_sec.get(elf).ni;
465 _, const plt_sec_node_size = plt_sec_ni.location(&elf.mf).resolve(&elf.mf);1065 switch (elf.shdrPtr(elf.shndx.plt_sec)) {
466 switch (elf.shdrPtr(elf.si.plt_sec.shndx(elf))) {1066 inline else => |shdr| {
467 inline else => |shdr| {1067 const old_size = 16 * plt_index;
468 const old_size = 16 * plt_index;1068 elf.targetStore(&shdr.size, old_size + 16);
469 const new_size = old_size + 16;1069 const plt_sec_slice = plt_sec_ni.slice(&elf.mf)[old_size..][0..16];
470 elf.targetStore(&shdr.size, new_size);1070 @memcpy(plt_sec_slice, &[16]u8{
471 if (new_size > plt_sec_node_size) try plt_sec_ni.resize(1071 0xf3, 0x0f, 0x1e, 0xfa, // endbr64
472 &elf.mf,1072 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *0x0(%rip)
473 gpa,1073 0x66, 0x0f, 0x1f, 0x44, 0x00, 0x00, // nopw 0x0(%rax,%rax,1)
474 new_size +| new_size / MappedFile.growth_factor,1074 });
475 );1075 std.mem.writeInt(
476 const plt_sec_slice = plt_sec_ni.slice(&elf.mf)[old_size..new_size];1076 i32,
477 @memcpy(plt_sec_slice, &[16]u8{1077 plt_sec_slice[6..][0..4],
478 0xf3, 0x0f, 0x1e, 0xfa, // endbr641078 @intCast(@as(i64, @bitCast(
479 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *0x0(%rip)1079 got_plt_addr -% (elf.targetLoad(&shdr.addr) + old_size + 10),
480 0x66, 0x0f, 0x1f, 0x44, 0x00, 0x00, // nopw 0x0(%rax,%rax,1)1080 ))),
481 });1081 target_endian,
482 std.mem.writeInt(1082 );
483 i32,1083 },
484 plt_sec_slice[6..][0..4],1084 }
485 @intCast(@as(i64, @bitCast(
486 got_plt_addr -% (elf.targetLoad(&shdr.addr) + old_size + 10),
487 ))),
488 target_endian,
489 );
490 },
491 }
4921085
493 const rela_plt_si = got_plt_shndx.get(elf).rela_si;1086 const rela_plt_shndx = got_plt_shndx.get(elf).rela_shndx;
494 const rela_plt_ni = rela_plt_si.node(elf);1087 const rela_plt_ni = rela_plt_shndx.get(elf).ni;
495 _, const rela_plt_node_size = rela_plt_ni.location(&elf.mf).resolve(&elf.mf);1088 switch (elf.shdrPtr(rela_plt_shndx)) {
496 switch (elf.shdrPtr(rela_plt_si.shndx(elf))) {1089 inline else => |shdr, class| {
497 inline else => |shdr, class| {1090 const Rela = class.ElfN().Rela;
498 const Rela = class.ElfN().Rela;1091 const rela_size = elf.targetLoad(&shdr.entsize);
499 const rela_size = elf.targetLoad(&shdr.entsize);1092 const old_size = rela_size * plt_index;
500 const old_size = rela_size * plt_index;1093 const new_size = old_size + rela_size;
501 const new_size = old_size + rela_size;1094 elf.targetStore(&shdr.size, new_size);
502 elf.targetStore(&shdr.size, new_size);1095 const rela: *Rela = @ptrCast(@alignCast(
503 if (new_size > rela_plt_node_size) try rela_plt_ni.resize(1096 rela_plt_ni.slice(&elf.mf)[@intCast(old_size)..@intCast(new_size)],
504 &elf.mf,1097 ));
505 gpa,1098 rela.* = .{
506 new_size +| new_size / MappedFile.growth_factor,1099 .offset = @intCast(got_plt_addr),
507 );1100 .info = .{
508 const rela: *Rela = @ptrCast(@alignCast(1101 .type = @intFromEnum(std.elf.R_X86_64.JUMP_SLOT),
509 rela_plt_ni.slice(&elf.mf)[@intCast(old_size)..@intCast(new_size)],1102 .sym = @intCast(dynsym_index),
510 ));
511 rela.* = .{
512 .offset = @intCast(got_plt_addr),
513 .info = .{
514 .type = @intFromEnum(std.elf.R_X86_64.JUMP_SLOT),
515 .sym = @intCast(dsi),
516 },
517 .addend = 0,
518 };
519 if (target_endian != native_endian) std.mem.byteSwapAllFields(Rela, rela);
520 },1103 },
521 }1104 .addend = 0,
522 try rela_plt_ni.resized(gpa, &elf.mf);1105 };
1106 if (target_endian != native_endian) std.mem.byteSwapAllFields(Rela, rela);
523 },1107 },
524 }1108 }
525 }1109 },
1110 }
1111}
5261112
527 pub fn flushMoved(si: Symbol.Index, elf: *Elf, value: u64) void {1113const Symbol = struct {
528 switch (elf.symPtr(si)) {1114 /// The node which this symbol's value is defined relative to. Possible values are:
529 inline else => |sym, class| {1115 /// * `.none` for a SHN_ABS or SHN_UNDEF symbol
530 elf.targetStore(&sym.value, @intCast(value));1116 /// * A section (the symbol's value is that section's vaddr)
531 if (si == elf.si.entry) {1117 /// * An input section (the symbol's value is some vaddr in that input section)
532 @branchHint(.unlikely);1118 /// * A NAV, UAV, or lazy code/data (the symbol's value is exactly the vaddr of that node)
533 @field(elf.ehdrPtr(), @tagName(class)).entry = sym.value;1119 node: MappedFile.Node.Index,
534 }1120
535 },1121 /// The head of a linked list of relocations targeting this symbol.
1122 first_target_reloc: Reloc.Index,
1123
1124 const Global = struct {
1125 /// The current index of the symtab entry for this global symbol.
1126 symtab_index: Symbol.Index,
1127 /// The current index of the dynsym entry for this global symbol. If the global has been
1128 /// demoted to STB_LOCAL, it does not have a dynsym entry and this field is set to 0.
1129 dynsym_index: u32,
1130
1131 /// The next entry in a linked list of global symbols with the same `Symbol.node` value.
1132 ///
1133 /// If `node` is `.none`, this is `.empty`.
1134 next_in_node: String(.strtab),
1135 /// The previous entry in a linked list of global symbols with the same `Symbol.node` value.
1136 ///
1137 /// If `node` is `.none`, this is `.empty`.
1138 prev_in_node: String(.strtab),
1139
1140 /// Like `Symbol.Index.flushMoved`, but also updates the dynamic symbol table if necessary.
1141 fn flushMoved(g: *const Global, elf: *Elf, value: u64) void {
1142 g.symtab_index.flushMoved(elf, value);
1143 if (g.dynsym_index != 0) {
1144 switch (elf.dynsymPtr(g.dynsym_index)) {
1145 inline else => |sym| elf.targetStore(&sym.value, @intCast(value)),
1146 }
536 }1147 }
537 si.applyLocationRelocs(elf);
538 si.applyTargetRelocs(elf);
539 }1148 }
1149 };
1150
1151 /// An index directly into the symtab. These values are not stable (global symbols are sometimes
1152 /// moved to new locations in the symtab) and therefore should only be used ephemerally.
1153 ///
1154 /// Local symbols *do* have stable indices into the symtab; see `LocalIndex`.
1155 ///
1156 /// For a stable reference to an arbitrary symbol, see `Id`.
1157 const Index = enum(u32) {
1158 null = 0,
1159 _,
5401160
541 pub fn applyLocationRelocs(si: Symbol.Index, elf: *Elf) void {1161 fn flushMoved(si: Symbol.Index, elf: *Elf, value: u64) void {
542 if (elf.ehdrField(.type) == .REL) return;1162 switch (elf.symPtr(si)) {
543 switch (si.get(elf).loc_relocs) {1163 inline else => |sym| elf.targetStore(&sym.value, @intCast(value)),
544 .none => {},1164 }
545 else => |loc_relocs| for (elf.relocs.items[@intFromEnum(loc_relocs)..]) |*reloc| {1165 if (elf.ehdrField(.type) != .REL) {
546 if (reloc.loc != si) break;1166 var ri = si.ptr(elf).first_target_reloc;
1167 while (ri != .none) {
1168 const reloc = ri.get(elf);
1169 assert(reloc.target.index(elf) == si);
547 reloc.apply(elf);1170 reloc.apply(elf);
548 },1171 ri = reloc.next;
1172 }
549 }1173 }
550 }1174 }
1175 fn ptr(si: Symbol.Index, elf: *Elf) *Symbol {
1176 return &elf.symtab.items[@intFromEnum(si)];
1177 }
1178 };
5511179
552 pub fn applyTargetRelocs(si: Symbol.Index, elf: *Elf) void {1180 /// A `LocalIndex` is a raw index into the symtab like `Index`, but it guarantees that the
553 if (elf.ehdrField(.type) == .REL) return;1181 /// symbol in question has STB_LOCAL binding, which guarantees that its symtab index is stable
554 var ri = si.get(elf).target_relocs;1182 /// so can be stored long-term without needing to be updated
555 while (ri != .none) {1183 ///
556 const reloc = ri.get(elf);1184 /// This is because symbols which have STB_LOCAL binding in the output file gain fixed symtab
557 assert(reloc.target == si);1185 /// indices, thanks to a combination of a few factors:
558 reloc.apply(elf);1186 /// * We never remove STB_LOCAL symbols
559 ri = reloc.next;1187 /// * There is no symbol ordering requirement *within* the leading range of STB_LOCAL symbols
560 }1188 /// * A symbol visibility which demotes a global to STB_LOCAL binding can never be reverted by
1189 /// a subsequent operation (different visibilities resolve to the "strictest" one)
1190 const LocalIndex = enum(u32) {
1191 null = 0,
1192 _,
1193
1194 fn index(li: LocalIndex) Index {
1195 return @enumFromInt(@intFromEnum(li));
561 }1196 }
1197 };
5621198
563 pub fn deleteLocationRelocs(si: Symbol.Index, elf: *Elf) void {1199 /// Opaque, stable identifier for a symbol. Does not necessarily equal the index into the symtab.
564 const sym = si.get(elf);1200 const Id = packed struct(u32) {
565 for (elf.relocs.items[@intFromEnum(sym.loc_relocs)..]) |*reloc| {1201 kind: enum(u1) { local, global },
566 if (reloc.loc != si) break;1202 raw: u31,
567 reloc.delete(elf);1203
568 }1204 const @"null": Symbol.Id = .local(.null);
569 sym.loc_relocs = .none;1205
1206 fn local(lsi: Symbol.LocalIndex) Symbol.Id {
1207 return .{ .kind = .local, .raw = @intCast(@intFromEnum(lsi)) };
1208 }
1209 fn global(name: String(.strtab)) Symbol.Id {
1210 return .{ .kind = .global, .raw = @intCast(@intFromEnum(name)) };
1211 }
1212 fn unwrap(s: Symbol.Id) union(enum) {
1213 local: Symbol.LocalIndex,
1214 global: String(.strtab),
1215 } {
1216 return switch (s.kind) {
1217 .local => .{ .local = @enumFromInt(s.raw) },
1218 .global => .{ .global = @enumFromInt(s.raw) },
1219 };
1220 }
1221
1222 fn toTypeErased(s: Symbol.Id) link.File.SymbolId {
1223 return @enumFromInt(@as(u32, @bitCast(s)));
1224 }
1225 fn fromTypeErased(s: link.File.SymbolId) Symbol.Id {
1226 return @bitCast(@intFromEnum(s));
1227 }
1228
1229 fn index(s: Symbol.Id, elf: *const Elf) Symbol.Index {
1230 return switch (s.unwrap()) {
1231 .local => |lsi| lsi.index(),
1232 .global => |name| elf.globalByName(name).?.symtab_index,
1233 };
1234 }
1235
1236 fn value(s: Symbol.Id, elf: *Elf) u64 {
1237 return switch (elf.symPtr(s.index(elf))) {
1238 inline else => |sym| elf.targetLoad(&sym.value),
1239 };
1240 }
1241
1242 /// Returns `true` if the target of `s` has moved, meaning the symbol's value will change at
1243 /// some point due to a call to `flushMoved`.
1244 fn hasMoved(s: Symbol.Id, elf: *Elf) bool {
1245 const node = s.index(elf).ptr(elf).node;
1246 if (node == .none) return false;
1247 return node.hasMoved(&elf.mf);
570 }1248 }
571 };1249 };
1250};
5721251
573 pub const Known = struct {1252fn globalByName(elf: *const Elf, name: String(.strtab)) ?*Symbol.Global {
574 comptime symtab: Symbol.Index = .symtab,1253 if (elf.globals.strong_def.getPtr(name)) |ptr| return ptr;
575 comptime shstrtab: Symbol.Index = .shstrtab,1254 if (elf.globals.weak_def.getPtr(name)) |ptr| return ptr;
576 comptime strtab: Symbol.Index = .strtab,1255 if (elf.globals.strong_undef.getPtr(name)) |ptr| return ptr;
577 comptime rodata: Symbol.Index = .rodata,1256 if (elf.globals.weak_undef.getPtr(name)) |ptr| return ptr;
578 comptime text: Symbol.Index = .text,1257 return null;
579 comptime data: Symbol.Index = .data,1258}
580 comptime data_rel_ro: Symbol.Index = .data_rel_ro,1259
581 comptime got: Symbol.Index = .got,1260pub fn symbolForAtom(elf: *Elf, atom: link.File.AtomId) link.File.SymbolId {
582 comptime got_plt: Symbol.Index = .got_plt,1261 const lsi: Symbol.LocalIndex = switch (elf.getNode(Node.fromAtom(atom))) {
583 comptime plt: Symbol.Index = .plt,1262 .file,
584 comptime plt_sec: Symbol.Index = .plt_sec,1263 .ehdr,
585 dynsym: Symbol.Index,1264 .shdr,
586 dynstr: Symbol.Index,1265 .segment,
587 dynamic: Symbol.Index,1266 .section,
588 tdata: Symbol.Index,1267 .input_section,
589 entry: Symbol.Index,1268 => unreachable,
1269
1270 inline .nav,
1271 .uav,
1272 .lazy_code,
1273 .lazy_const_data,
1274 => |i| i.symbol(elf),
590 };1275 };
1276 const s: Symbol.Id = .local(lsi);
1277 return s.toTypeErased();
1278}
1279pub fn lazySymbol(elf: *Elf, lazy: link.File.LazySymbol) !link.File.SymbolId {
1280 const gpa = elf.base.comp.gpa;
5911281
592 comptime {1282 try elf.ensureUnusedSymbolCapacity(1, .all_local);
593 if (!std.debug.runtime_safety) std.debug.assert(@sizeOf(Symbol) == 16);1283 try elf.nodes.ensureUnusedCapacity(gpa, 1);
1284 try elf.lazy.getPtr(lazy.kind).map.ensureUnusedCapacity(gpa, 1);
1285
1286 const gop = elf.lazy.getPtr(lazy.kind).map.getOrPutAssumeCapacity(lazy.ty);
1287 if (!gop.found_existing) {
1288 const shndx: Section.Index, const sym_type: std.elf.STT = switch (lazy.kind) {
1289 .code => .{ .text, .FUNC },
1290 .const_data => .{ .rodata, .OBJECT },
1291 };
1292 const node = try elf.mf.addLastChildNode(gpa, shndx.get(elf).ni, .{});
1293 var name_buf: [64]u8 = undefined;
1294 const name = std.fmt.bufPrint(
1295 &name_buf,
1296 "__lazy_{t}_{d}",
1297 .{ lazy.kind, @intFromEnum(lazy.ty) },
1298 ) catch unreachable;
1299 gop.value_ptr.* = .{
1300 .lsi = elf.addLocalSymbolAssumeCapacity(.{
1301 .node = node,
1302 .name = try elf.string(.strtab, name),
1303 .value = 0,
1304 .size = 0,
1305 .type = sym_type,
1306 .shndx = shndx,
1307 }),
1308 .first_reloc = .none,
1309 };
1310 elf.nodes.appendAssumeCapacity(switch (lazy.kind) {
1311 .code => .{ .lazy_code = @enumFromInt(gop.index) },
1312 .const_data => .{ .lazy_const_data = @enumFromInt(gop.index) },
1313 });
1314 elf.synth_prog_node.increaseEstimatedTotalItems(1);
1315 }
1316 const s: Symbol.Id = .local(gop.value_ptr.lsi);
1317 return s.toTypeErased();
1318}
1319pub fn externSymbol(elf: *Elf, opts: struct {
1320 name: []const u8,
1321 lib_name: ?[]const u8,
1322 type: std.elf.STT,
1323 linkage: std.lang.GlobalLinkage = .strong,
1324 visibility: std.lang.SymbolVisibility = .default,
1325}) !link.File.SymbolId {
1326 try elf.ensureUnusedSymbolCapacity(1, .maybe_global);
1327 const symbol = elf.addGlobalSymbolAssumeCapacity(.{
1328 .node = .none,
1329 .name = try .string(elf, opts.name),
1330 .lib_name = opts.lib_name,
1331 .value = 0,
1332 .size = 0,
1333 .type = opts.type,
1334 .bind = switch (opts.linkage) {
1335 .internal => @panic("TODO internal extern symbol"),
1336 .strong => .strong,
1337 .weak => .weak,
1338 .link_once => return error.LinkOnceUnsupported,
1339 },
1340 .visibility = switch (opts.visibility) {
1341 .default => .DEFAULT,
1342 .hidden => .HIDDEN,
1343 .protected => .PROTECTED,
1344 },
1345 .shndx = .UNDEF,
1346 }) catch |err| switch (err) {
1347 error.MultipleDefinitions => unreachable, // shndx is undef
1348 };
1349 return symbol.toTypeErased();
1350}
1351pub fn addReloc(
1352 elf: *Elf,
1353 atom: link.File.AtomId,
1354 offset: u64,
1355 target: link.File.SymbolId,
1356 addend: i64,
1357 @"type": Reloc.Type,
1358) !void {
1359 const node: MappedFile.Node.Index = Node.fromAtom(atom);
1360 try elf.ensureUnusedRelocCapacity(node, 1);
1361 elf.addRelocAssumeCapacity(node, offset, .fromTypeErased(target), addend, @"type");
1362}
1363pub fn navSymbol(elf: *Elf, nav_index: InternPool.Nav.Index) !link.File.SymbolId {
1364 const zcu = elf.base.comp.zcu.?;
1365 const ip = &zcu.intern_pool;
1366 const nav = ip.getNav(nav_index);
1367 if (nav.getExtern(ip)) |@"extern"| {
1368 return elf.externSymbol(.{
1369 .name = @"extern".name.toSlice(ip),
1370 .lib_name = @"extern".lib_name.toSlice(ip),
1371 .type = navType(ip, nav.resolved.?, elf.base.comp.config.any_non_single_threaded),
1372 .linkage = @"extern".linkage,
1373 .visibility = @"extern".visibility,
1374 });
1375 }
1376 const nmi = try elf.navMapIndex(zcu, nav_index);
1377 const s: Symbol.Id = .local(nmi.symbol(elf));
1378 return s.toTypeErased();
1379}
1380pub fn uavSymbol(
1381 elf: *Elf,
1382 uav_val: InternPool.Index,
1383 uav_align: InternPool.Alignment,
1384) !link.File.SymbolId {
1385 const umi = try elf.uavMapIndex(uav_val, uav_align);
1386 const s: Symbol.Id = .local(umi.symbol(elf));
1387 return s.toTypeErased();
1388}
1389pub fn getNavVAddr(
1390 elf: *Elf,
1391 pt: Zcu.PerThread,
1392 nav: InternPool.Nav.Index,
1393 reloc_info: link.File.RelocInfo,
1394) !u64 {
1395 _ = pt;
1396 return elf.getVAddr(reloc_info, try elf.navSymbol(nav));
1397}
1398pub fn getUavVAddr(
1399 elf: *Elf,
1400 uav_val: InternPool.Index,
1401 reloc_info: link.File.RelocInfo,
1402) !u64 {
1403 return elf.getVAddr(reloc_info, try elf.uavSymbol(uav_val, .none));
1404}
1405pub fn getVAddr(elf: *Elf, reloc_info: link.File.RelocInfo, target: link.File.SymbolId) !u64 {
1406 const node: MappedFile.Node.Index = Node.fromAtom(reloc_info.parent.atom_index);
1407 const target_sym: Symbol.Id = .fromTypeErased(target);
1408 try elf.ensureUnusedRelocCapacity(node, 1);
1409 elf.addRelocAssumeCapacity(
1410 node,
1411 reloc_info.offset,
1412 target_sym,
1413 reloc_info.addend,
1414 .absAddr(elf),
1415 );
1416 return target_sym.value(elf);
1417}
1418pub fn lowerUav(
1419 elf: *Elf,
1420 pt: Zcu.PerThread,
1421 uav_val: InternPool.Index,
1422 uav_align: InternPool.Alignment,
1423 src_loc: Zcu.LazySrcLoc,
1424) !codegen.SymbolResult {
1425 _ = pt;
1426 const umi = elf.uavMapIndex(uav_val, uav_align) catch |err| switch (err) {
1427 error.OutOfMemory => |e| return e,
1428 else => |e| return .{ .fail = try Zcu.ErrorMsg.create(
1429 elf.base.comp.gpa,
1430 src_loc,
1431 "linker failed to update constant: {s}",
1432 .{@errorName(e)},
1433 ) },
1434 };
1435 const s: Symbol.Id = .local(umi.symbol(elf));
1436 return .{ .sym_index = s.toTypeErased() };
1437}
1438
1439const StringSection = enum {
1440 shstrtab,
1441 strtab,
1442 dynstr,
1443 fn shndx(s: StringSection, elf: *const Elf) Section.Index {
1444 return switch (s) {
1445 .strtab => .strtab,
1446 .shstrtab => .shstrtab,
1447 .dynstr => elf.shndx.dynstr,
1448 };
594 }1449 }
595};1450};
1451fn String(section: StringSection) type {
1452 return enum(u32) {
1453 empty = 0,
1454 _,
1455
1456 fn slice(str: @This(), elf: *Elf) [:0]const u8 {
1457 const section_node = section.shndx(elf).get(elf).ni;
1458 const overlong = section_node.sliceConst(&elf.mf)[@intFromEnum(str)..];
1459 return overlong[0..std.mem.findScalar(u8, overlong, 0).? :0];
1460 }
1461 };
1462}
1463fn string(elf: *Elf, comptime section: StringSection, key: []const u8) !String(section) {
1464 const st: *StringTable = &@field(elf, @tagName(section));
1465 return @enumFromInt(try st.get(elf, section.shndx(elf), key));
1466}
5961467
597pub const StringTable = struct {1468const StringTable = struct {
598 map: std.HashMapUnmanaged(u32, void, StringTable.Context, std.hash_map.default_max_load_percentage),1469 map: std.HashMapUnmanaged(u32, void, StringTable.Context, std.hash_map.default_max_load_percentage),
5991470
600 const Context = struct {1471 const Context = struct {
...@@ -623,9 +1494,13 @@ pub const StringTable = struct {...@@ -623,9 +1494,13 @@ pub const StringTable = struct {
623 }1494 }
624 };1495 };
6251496
626 pub fn get(st: *StringTable, elf: *Elf, si: Symbol.Index, key: []const u8) !u32 {1497 pub fn get(st: *StringTable, elf: *Elf, shndx: Section.Index, key: []const u8) !u32 {
1498 // If we are in `initHeaders` the strtab might not be initalized yet, so we need to special
1499 // case the empty string.
1500 if (key.len == 0) return 0;
1501
627 const gpa = elf.base.comp.gpa;1502 const gpa = elf.base.comp.gpa;
628 const ni = si.node(elf);1503 const ni = shndx.get(elf).ni;
629 const slice_const = ni.sliceConst(&elf.mf);1504 const slice_const = ni.sliceConst(&elf.mf);
630 const gop = try st.map.getOrPutContextAdapted(1505 const gop = try st.map.getOrPutContextAdapted(
631 gpa,1506 gpa,
...@@ -635,7 +1510,7 @@ pub const StringTable = struct {...@@ -635,7 +1510,7 @@ pub const StringTable = struct {
635 );1510 );
636 if (gop.found_existing) return gop.key_ptr.*;1511 if (gop.found_existing) return gop.key_ptr.*;
637 try ni.resized(gpa, &elf.mf);1512 try ni.resized(gpa, &elf.mf);
638 const old_size, const new_size = size: switch (elf.shdrPtr(si.shndx(elf))) {1513 const old_size, const new_size = size: switch (elf.shdrPtr(shndx)) {
639 inline else => |shdr| {1514 inline else => |shdr| {
640 const old_size: u32 = @intCast(elf.targetLoad(&shdr.size));1515 const old_size: u32 = @intCast(elf.targetLoad(&shdr.size));
641 const new_size: u32 = @intCast(old_size + key.len + 1);1516 const new_size: u32 = @intCast(old_size + key.len + 1);
...@@ -654,7 +1529,7 @@ pub const StringTable = struct {...@@ -654,7 +1529,7 @@ pub const StringTable = struct {
654 }1529 }
655};1530};
6561531
657pub const GotIndex = enum(u32) {1532const GotIndex = enum(u32) {
658 none = std.math.maxInt(u32),1533 none = std.math.maxInt(u32),
659 _,1534 _,
6601535
...@@ -671,12 +1546,12 @@ pub const GotIndex = enum(u32) {...@@ -671,12 +1546,12 @@ pub const GotIndex = enum(u32) {
671 }1546 }
672};1547};
6731548
674pub const Reloc = extern struct {1549const Reloc = extern struct {
675 type: Reloc.Type,1550 type: Reloc.Type,
676 prev: Reloc.Index,1551 prev: Reloc.Index,
677 next: Reloc.Index,1552 next: Reloc.Index,
678 loc: Symbol.Index,1553 node: MappedFile.Node.Index,
679 target: Symbol.Index,1554 target: Symbol.Id,
680 index: Section.RelIndex,1555 index: Section.RelIndex,
681 offset: u64,1556 offset: u64,
682 addend: i64,1557 addend: i64,
...@@ -745,85 +1620,86 @@ pub const Reloc = extern struct {...@@ -745,85 +1620,86 @@ pub const Reloc = extern struct {
7451620
746 pub fn apply(reloc: *const Reloc, elf: *Elf) void {1621 pub fn apply(reloc: *const Reloc, elf: *Elf) void {
747 assert(elf.ehdrField(.type) != .REL);1622 assert(elf.ehdrField(.type) != .REL);
748 const loc_ni = reloc.loc.get(elf).ni;1623 assert(reloc.node != .none);
749 switch (loc_ni) {1624 if (reloc.node.hasMoved(&elf.mf) or reloc.target.hasMoved(elf)) {
750 .none => return,1625 // There's no point applying the relocation now, because it will be re-applied by
751 else => |ni| if (ni.hasMoved(&elf.mf)) return,1626 // `flushMoved` at some point anyway.
752 }1627 return;
753 switch (reloc.target.get(elf).ni) {
754 .none => {},
755 else => |ni| if (ni.hasMoved(&elf.mf)) return,
756 }1628 }
757 const loc_slice = loc_ni.slice(&elf.mf)[@intCast(reloc.offset)..];1629 const node_vaddr: u64 = switch (elf.getNode(reloc.node)) {
1630 .file => unreachable,
1631 .ehdr => unreachable,
1632 .shdr => unreachable,
1633 .segment => unreachable,
1634 .section => |shndx| shndx.vaddr(elf),
1635 .input_section => |isi| isi.ptrConst(elf).vaddr,
1636 inline .nav,
1637 .uav,
1638 .lazy_code,
1639 .lazy_const_data,
1640 => |i| Symbol.Id.local(i.symbol(elf)).value(elf),
1641 };
1642 const dest_vaddr = node_vaddr + reloc.offset;
1643 const dest_slice = reloc.node.slice(&elf.mf)[@intCast(reloc.offset)..];
758 const target_endian = elf.targetEndian();1644 const target_endian = elf.targetEndian();
759 switch (elf.symtabSlice()) {1645 switch (elf.symPtr(reloc.target.index(elf))) {
760 inline else => |symtab, class| {1646 inline else => |target_sym, class| {
761 const loc_sym = &symtab[@intFromEnum(reloc.loc)];1647 const target_value = elf.targetLoad(&target_sym.value) +% @as(u64, @bitCast(reloc.addend));
762 const loc_shndx = elf.targetLoad(&loc_sym.shndx);
763 assert(loc_shndx != std.elf.SHN_UNDEF);
764 const target_sym = &symtab[@intFromEnum(reloc.target)];
765 const target_value =
766 elf.targetLoad(&target_sym.value) +% @as(u64, @bitCast(reloc.addend));
767 switch (elf.ehdrField(.machine)) {1648 switch (elf.ehdrField(.machine)) {
768 else => |machine| @panic(@tagName(machine)),1649 else => |machine| @panic(@tagName(machine)),
769 .X86_64 => switch (reloc.type.X86_64) {1650 .X86_64 => switch (reloc.type.X86_64) {
770 else => |kind| @panic(@tagName(kind)),1651 else => |kind| @panic(@tagName(kind)),
771 .@"64" => std.mem.writeInt(1652 .@"64" => std.mem.writeInt(
772 u64,1653 u64,
773 loc_slice[0..8],1654 dest_slice[0..8],
774 target_value,1655 target_value,
775 target_endian,1656 target_endian,
776 ),1657 ),
777 .PC32 => std.mem.writeInt(1658 .PC32 => std.mem.writeInt(
778 i32,1659 i32,
779 loc_slice[0..4],1660 dest_slice[0..4],
780 @intCast(@as(i64, @bitCast(target_value -%1661 @intCast(@as(i64, @bitCast(target_value -% dest_vaddr))),
781 (elf.targetLoad(&loc_sym.value) + reloc.offset)))),
782 target_endian,1662 target_endian,
783 ),1663 ),
784 .PLT32 => std.mem.writeInt(1664 .PLT32 => std.mem.writeInt(
785 i32,1665 i32,
786 loc_slice[0..4],1666 dest_slice[0..4],
787 @intCast(@as(i64, @bitCast(1667 @intCast(@as(i64, @bitCast(if (elf.got.plt.getIndex(reloc.target)) |plt_index|
788 if (elf.got.plt.getIndex(reloc.target)) |plt_index|1668 elf.targetLoad(&@field(
789 elf.targetLoad(&@field(1669 elf.shdrPtr(elf.shndx.plt_sec),
790 elf.shdrPtr(elf.si.plt_sec.shndx(elf)),1670 @tagName(class),
791 @tagName(class),1671 ).addr) +% 16 * plt_index +%
792 ).addr) +% 16 * plt_index +%1672 @as(u64, @bitCast(reloc.addend)) -% dest_vaddr
793 @as(u64, @bitCast(reloc.addend)) -%1673 else
794 (elf.targetLoad(&loc_sym.value) + reloc.offset)1674 target_value -% dest_vaddr))),
795 else
796 target_value -%
797 (elf.targetLoad(&loc_sym.value) + reloc.offset),
798 ))),
799 target_endian,1675 target_endian,
800 ),1676 ),
801 .@"32" => std.mem.writeInt(1677 .@"32" => std.mem.writeInt(
802 u32,1678 u32,
803 loc_slice[0..4],1679 dest_slice[0..4],
804 @intCast(target_value),1680 @intCast(target_value),
805 target_endian,1681 target_endian,
806 ),1682 ),
807 .@"32S" => std.mem.writeInt(1683 .@"32S" => std.mem.writeInt(
808 i32,1684 i32,
809 loc_slice[0..4],1685 dest_slice[0..4],
810 @intCast(@as(i64, @bitCast(target_value))),1686 @intCast(@as(i64, @bitCast(target_value))),
811 target_endian,1687 target_endian,
812 ),1688 ),
813 .TLSLD => std.mem.writeInt(1689 .TLSLD => std.mem.writeInt(
814 i32,1690 i32,
815 loc_slice[0..4],1691 dest_slice[0..4],
816 @intCast(@as(i64, @bitCast(1692 @intCast(@as(i64, @bitCast(
817 elf.targetLoad(&symtab[@intFromEnum(elf.si.got)].value) +%1693 elf.shndx.got.vaddr(elf) +%
818 @as(u64, @bitCast(reloc.addend)) +%1694 @as(u64, @bitCast(reloc.addend)) +%
819 @as(u64, 8) * elf.got.tlsld.unwrap().? -%1695 @as(u64, 8) * elf.got.tlsld.unwrap().? -%
820 (elf.targetLoad(&loc_sym.value) + reloc.offset),1696 dest_vaddr,
821 ))),1697 ))),
822 target_endian,1698 target_endian,
823 ),1699 ),
824 .DTPOFF32 => std.mem.writeInt(1700 .DTPOFF32 => std.mem.writeInt(
825 i32,1701 i32,
826 loc_slice[0..4],1702 dest_slice[0..4],
827 @intCast(@as(i64, @bitCast(target_value))),1703 @intCast(@as(i64, @bitCast(target_value))),
828 target_endian,1704 target_endian,
829 ),1705 ),
...@@ -833,14 +1709,14 @@ pub const Reloc = extern struct {...@@ -833,14 +1709,14 @@ pub const Reloc = extern struct {
833 assert(elf.targetLoad(&ph.type) == .TLS);1709 assert(elf.targetLoad(&ph.type) == .TLS);
834 std.mem.writeInt(1710 std.mem.writeInt(
835 i32,1711 i32,
836 loc_slice[0..4],1712 dest_slice[0..4],
837 @intCast(@as(i64, @bitCast(target_value -% elf.targetLoad(&ph.memsz)))),1713 @intCast(@as(i64, @bitCast(target_value -% elf.targetLoad(&ph.memsz)))),
838 target_endian,1714 target_endian,
839 );1715 );
840 },1716 },
841 .SIZE32 => std.mem.writeInt(1717 .SIZE32 => std.mem.writeInt(
842 u32,1718 u32,
843 loc_slice[0..4],1719 dest_slice[0..4],
844 @intCast(1720 @intCast(
845 elf.targetLoad(&target_sym.size) +% @as(u64, @bitCast(reloc.addend)),1721 elf.targetLoad(&target_sym.size) +% @as(u64, @bitCast(reloc.addend)),
846 ),1722 ),
...@@ -848,7 +1724,7 @@ pub const Reloc = extern struct {...@@ -848,7 +1724,7 @@ pub const Reloc = extern struct {
848 ),1724 ),
849 .SIZE64 => std.mem.writeInt(1725 .SIZE64 => std.mem.writeInt(
850 u64,1726 u64,
851 loc_slice[0..8],1727 dest_slice[0..8],
852 elf.targetLoad(&target_sym.size) +% @as(u64, @bitCast(reloc.addend)),1728 elf.targetLoad(&target_sym.size) +% @as(u64, @bitCast(reloc.addend)),
853 target_endian,1729 target_endian,
854 ),1730 ),
...@@ -861,9 +1737,9 @@ pub const Reloc = extern struct {...@@ -861,9 +1737,9 @@ pub const Reloc = extern struct {
861 pub fn delete(reloc: *Reloc, elf: *Elf) void {1737 pub fn delete(reloc: *Reloc, elf: *Elf) void {
862 switch (reloc.prev) {1738 switch (reloc.prev) {
863 .none => {1739 .none => {
864 const target = reloc.target.get(elf);1740 const target_ptr = reloc.target.index(elf).ptr(elf);
865 assert(target.target_relocs.get(elf) == reloc);1741 assert(target_ptr.first_target_reloc.get(elf) == reloc);
866 target.target_relocs = reloc.next;1742 target_ptr.first_target_reloc = reloc.next;
867 },1743 },
868 else => |prev| prev.get(elf).next = reloc.next,1744 else => |prev| prev.get(elf).next = reloc.next,
869 }1745 }
...@@ -874,13 +1750,13 @@ pub const Reloc = extern struct {...@@ -874,13 +1750,13 @@ pub const Reloc = extern struct {
874 switch (elf.ehdrField(.type)) {1750 switch (elf.ehdrField(.type)) {
875 .NONE, .CORE, _ => unreachable,1751 .NONE, .CORE, _ => unreachable,
876 .REL => {1752 .REL => {
877 const sh = reloc.loc.shndx(elf).get(elf);1753 const sh = elf.getNodeShndx(reloc.node).get(elf);
878 switch (elf.shdrPtr(sh.rela_si.shndx(elf))) {1754 switch (elf.shdrPtr(sh.rela_shndx)) {
879 inline else => |shdr, class| {1755 inline else => |shdr, class| {
880 const Rela = class.ElfN().Rela;1756 const Rela = class.ElfN().Rela;
881 const ent_size = elf.targetLoad(&shdr.entsize);1757 const ent_size = elf.targetLoad(&shdr.entsize);
882 const start = ent_size * reloc.index.unwrap().?;1758 const start = ent_size * reloc.index.unwrap().?;
883 const rela_slice = sh.rela_si.node(elf).slice(&elf.mf);1759 const rela_slice = sh.rela_shndx.get(elf).ni.slice(&elf.mf);
884 const rela: *Rela = @ptrCast(@alignCast(1760 const rela: *Rela = @ptrCast(@alignCast(
885 rela_slice[@intCast(start)..][0..@intCast(ent_size)],1761 rela_slice[@intCast(start)..][0..@intCast(ent_size)],
886 ));1762 ));
...@@ -901,6 +1777,38 @@ pub const Reloc = extern struct {...@@ -901,6 +1777,38 @@ pub const Reloc = extern struct {
901 reloc.* = undefined;1777 reloc.* = undefined;
902 }1778 }
9031779
1780 fn updateTargetIndex(reloc: *const Reloc, elf: *Elf) void {
1781 assert(elf.ehdrField(.type) == .REL);
1782 const sh = elf.getNodeShndx(reloc.node).get(elf);
1783 switch (elf.shdrPtr(sh.rela_shndx)) {
1784 inline else => |shdr, class| {
1785 assert(elf.targetLoad(&shdr.entsize) == @sizeOf(class.ElfN().Rela));
1786 const size = elf.targetLoad(&shdr.size);
1787 const raw_rela_slice = sh.rela_shndx.get(elf).ni.slice(&elf.mf);
1788 const rela_slice: []class.ElfN().Rela = @ptrCast(@alignCast(raw_rela_slice[0..@intCast(size)]));
1789 elf.targetStore(&rela_slice[reloc.index.unwrap().?].info, .{
1790 .type = @intCast(reloc.type.unwrap(elf)),
1791 .sym = @intCast(@intFromEnum(reloc.target.index(elf))),
1792 });
1793 },
1794 }
1795 }
1796
1797 fn updateNodeOffset(reloc: *const Reloc, elf: *Elf, node_offset: u64) void {
1798 assert(elf.ehdrField(.type) == .REL);
1799 const total_offset = node_offset + reloc.offset;
1800 const sh = elf.getNodeShndx(reloc.node).get(elf);
1801 switch (elf.shdrPtr(sh.rela_shndx)) {
1802 inline else => |shdr, class| {
1803 assert(elf.targetLoad(&shdr.entsize) == @sizeOf(class.ElfN().Rela));
1804 const size = elf.targetLoad(&shdr.size);
1805 const raw_rela_slice = sh.rela_shndx.get(elf).ni.slice(&elf.mf);
1806 const rela_slice: []class.ElfN().Rela = @ptrCast(@alignCast(raw_rela_slice[0..@intCast(size)]));
1807 elf.targetStore(&rela_slice[reloc.index.unwrap().?].offset, @intCast(total_offset));
1808 },
1809 }
1810 }
1811
904 comptime {1812 comptime {
905 if (!std.debug.runtime_safety) std.debug.assert(@sizeOf(Reloc) == 40);1813 if (!std.debug.runtime_safety) std.debug.assert(@sizeOf(Reloc) == 40);
906 }1814 }
...@@ -1001,34 +1909,38 @@ fn create(...@@ -1001,34 +1909,38 @@ fn create(
1001 .nodes = .empty,1909 .nodes = .empty,
1002 .shdrs = .empty,1910 .shdrs = .empty,
1003 .phdrs = .empty,1911 .phdrs = .empty,
1004 .si = .{1912 .shndx = .{
1005 .dynsym = .null,1913 .got = .UNDEF,
1006 .dynstr = .null,1914 .got_plt = .UNDEF,
1007 .dynamic = .null,1915 .plt = .UNDEF,
1008 .tdata = .null,1916 .plt_sec = .UNDEF,
1009 .entry = .null,1917 .dynsym = .UNDEF,
1918 .dynstr = .UNDEF,
1919 .dynamic = .UNDEF,
1920 .tdata = .UNDEF,
1010 },1921 },
1011 .symtab = .empty,1922 .symtab = .empty,
1012 .shstrtab = .{1923 .globals = .{
1013 .map = .empty,1924 .strong_def = .empty,
1014 },1925 .weak_def = .empty,
1015 .strtab = .{1926 .strong_undef = .empty,
1016 .map = .empty,1927 .weak_undef = .empty,
1017 },
1018 .dynsym = .empty,
1019 .dynstr = .{
1020 .map = .empty,
1021 },1928 },
1929 .node_global_symbols = .empty,
1930 .shstrtab = .{ .map = .empty },
1931 .strtab = .{ .map = .empty },
1932 .dynstr = .{ .map = .empty },
1022 .got = .{1933 .got = .{
1023 .len = 0,1934 .len = 0,
1024 .tlsld = .none,1935 .tlsld = .none,
1025 .plt = .empty,1936 .plt = .empty,
1026 },1937 },
1938 .first_plt_reloc = .none,
1939 .first_dynamic_reloc = .none,
1027 .needed = .empty,1940 .needed = .empty,
1028 .inputs = .empty,1941 .inputs = .empty,
1029 .input_sections = .empty,1942 .input_sections = .empty,
1030 .input_section_pending_index = 0,1943 .input_section_pending_index = 0,
1031 .globals = .empty,
1032 .navs = .empty,1944 .navs = .empty,
1033 .uavs = .empty,1945 .uavs = .empty,
1034 .lazy = comptime .initFill(.{1946 .lazy = comptime .initFill(.{
...@@ -1037,6 +1949,7 @@ fn create(...@@ -1037,6 +1949,7 @@ fn create(
1037 }),1949 }),
1038 .pending_uavs = .empty,1950 .pending_uavs = .empty,
1039 .relocs = .empty,1951 .relocs = .empty,
1952 .changed_symtab_index = .empty,
1040 .const_prog_node = .none,1953 .const_prog_node = .none,
1041 .synth_prog_node = .none,1954 .synth_prog_node = .none,
1042 .input_prog_node = .none,1955 .input_prog_node = .none,
...@@ -1054,21 +1967,25 @@ pub fn deinit(elf: *Elf) void {...@@ -1054,21 +1967,25 @@ pub fn deinit(elf: *Elf) void {
1054 elf.shdrs.deinit(gpa);1967 elf.shdrs.deinit(gpa);
1055 elf.phdrs.deinit(gpa);1968 elf.phdrs.deinit(gpa);
1056 elf.symtab.deinit(gpa);1969 elf.symtab.deinit(gpa);
1970 elf.globals.strong_def.deinit(gpa);
1971 elf.globals.weak_def.deinit(gpa);
1972 elf.globals.strong_undef.deinit(gpa);
1973 elf.globals.weak_undef.deinit(gpa);
1974 elf.node_global_symbols.deinit(gpa);
1057 elf.shstrtab.map.deinit(gpa);1975 elf.shstrtab.map.deinit(gpa);
1058 elf.strtab.map.deinit(gpa);1976 elf.strtab.map.deinit(gpa);
1059 elf.dynsym.deinit(gpa);
1060 elf.dynstr.map.deinit(gpa);1977 elf.dynstr.map.deinit(gpa);
1061 elf.got.plt.deinit(gpa);1978 elf.got.plt.deinit(gpa);
1062 elf.needed.deinit(gpa);1979 elf.needed.deinit(gpa);
1063 for (elf.inputs.items) |input| if (input.member) |m| gpa.free(m);1980 for (elf.inputs.items) |input| if (input.member) |m| gpa.free(m);
1064 elf.inputs.deinit(gpa);1981 elf.inputs.deinit(gpa);
1065 elf.input_sections.deinit(gpa);1982 elf.input_sections.deinit(gpa);
1066 elf.globals.deinit(gpa);
1067 elf.navs.deinit(gpa);1983 elf.navs.deinit(gpa);
1068 elf.uavs.deinit(gpa);1984 elf.uavs.deinit(gpa);
1069 for (&elf.lazy.values) |*lazy| lazy.map.deinit(gpa);1985 for (&elf.lazy.values) |*lazy| lazy.map.deinit(gpa);
1070 elf.pending_uavs.deinit(gpa);1986 elf.pending_uavs.deinit(gpa);
1071 elf.relocs.deinit(gpa);1987 elf.relocs.deinit(gpa);
1988 elf.changed_symtab_index.deinit(gpa);
1072 elf.* = undefined;1989 elf.* = undefined;
1073}1990}
10741991
...@@ -1123,19 +2040,18 @@ fn initHeaders(...@@ -1123,19 +2040,18 @@ fn initHeaders(
1123 const expected_nodes_len = expected_nodes_len: switch (@"type") {2040 const expected_nodes_len = expected_nodes_len: switch (@"type") {
1124 .NONE, .CORE, _ => unreachable,2041 .NONE, .CORE, _ => unreachable,
1125 .REL => {2042 .REL => {
2043 // Each phdr is actually going to be an shdr.
1126 defer phnum = 0;2044 defer phnum = 0;
1127 break :expected_nodes_len 5 + phnum;2045 break :expected_nodes_len 5 + phnum;
1128 },2046 },
1129 .EXEC, .DYN => break :expected_nodes_len 8 + phnum * 2 +2047 .EXEC, .DYN => break :expected_nodes_len 10 +
1130 @intFromBool(maybe_interp != null) +2048 phnum * 2 - 1 + // each phdr also has a matching shdr, except for the PT_PHDR phdr
1131 @as(usize, 4) * @intFromBool(have_dynamic_section) +2049 @as(usize, 4) * @intFromBool(have_dynamic_section), // .dynstr, .dynsym, .rela.dyn, .rela.plt
1132 @intFromBool(comp.config.any_non_single_threaded),
1133 };2050 };
1134 try elf.nodes.ensureTotalCapacity(gpa, expected_nodes_len);2051 try elf.nodes.ensureTotalCapacity(gpa, expected_nodes_len);
1135 try elf.shdrs.ensureTotalCapacity(gpa, shnum);2052 try elf.shdrs.ensureTotalCapacity(gpa, shnum);
1136 try elf.phdrs.resize(gpa, phnum);2053 try elf.phdrs.resize(gpa, phnum);
1137 try elf.symtab.ensureTotalCapacity(gpa, 1);2054 try elf.symtab.ensureTotalCapacity(gpa, 1);
1138 if (have_dynamic_section) try elf.dynsym.ensureTotalCapacity(gpa, 1);
1139 elf.nodes.appendAssumeCapacity(.file);2055 elf.nodes.appendAssumeCapacity(.file);
11402056
1141 switch (class) {2057 switch (class) {
...@@ -1150,14 +2066,13 @@ fn initHeaders(...@@ -1150,14 +2066,13 @@ fn initHeaders(
1150 elf.nodes.appendAssumeCapacity(.ehdr);2066 elf.nodes.appendAssumeCapacity(.ehdr);
11512067
1152 const ehdr: *ElfN.Ehdr = @ptrCast(@alignCast(elf.ni.ehdr.slice(&elf.mf)));2068 const ehdr: *ElfN.Ehdr = @ptrCast(@alignCast(elf.ni.ehdr.slice(&elf.mf)));
1153 const EI = std.elf.EI;2069 ehdr.ident = .{
1154 @memcpy(ehdr.ident[0..std.elf.MAGIC.len], std.elf.MAGIC);2070 .class = class,
1155 ehdr.ident[EI.CLASS] = @intFromEnum(class);2071 .data = data,
1156 ehdr.ident[EI.DATA] = @intFromEnum(data);2072 .version = 1,
1157 ehdr.ident[EI.VERSION] = 1;2073 .osabi = osabi,
1158 ehdr.ident[EI.OSABI] = @intFromEnum(osabi);2074 .abiversion = 0,
1159 ehdr.ident[EI.ABIVERSION] = 0;2075 };
1160 @memset(ehdr.ident[EI.PAD..], 0);
1161 ehdr.type = @"type";2076 ehdr.type = @"type";
1162 ehdr.machine = machine;2077 ehdr.machine = machine;
1163 ehdr.version = 1;2078 ehdr.version = 1;
...@@ -1176,7 +2091,7 @@ fn initHeaders(...@@ -1176,7 +2091,7 @@ fn initHeaders(
1176 }2091 }
11772092
1178 assert(elf.ni.shdr == try elf.mf.addLastChildNode(gpa, elf.ni.file, .{2093 assert(elf.ni.shdr == try elf.mf.addLastChildNode(gpa, elf.ni.file, .{
1179 .size = elf.ehdrField(.shentsize) * elf.ehdrField(.shnum),2094 .size = @as(u64, elf.ehdrField(.shentsize)) * @as(u64, elf.ehdrField(.shnum)),
1180 .alignment = elf.mf.flags.block_size,2095 .alignment = elf.mf.flags.block_size,
1181 .moved = true,2096 .moved = true,
1182 .resized = true,2097 .resized = true,
...@@ -1366,7 +2281,7 @@ fn initHeaders(...@@ -1366,7 +2281,7 @@ fn initHeaders(
13662281
1367 const sh_undef: *ElfN.Shdr = @ptrCast(@alignCast(elf.ni.shdr.slice(&elf.mf)));2282 const sh_undef: *ElfN.Shdr = @ptrCast(@alignCast(elf.ni.shdr.slice(&elf.mf)));
1368 sh_undef.* = .{2283 sh_undef.* = .{
1369 .name = try elf.string(.shstrtab, ""),2284 .name = @intFromEnum(String(.shstrtab).empty),
1370 .type = .NULL,2285 .type = .NULL,
1371 .flags = .{ .shf = .{} },2286 .flags = .{ .shf = .{} },
1372 .addr = 0,2287 .addr = 0,
...@@ -1378,24 +2293,23 @@ fn initHeaders(...@@ -1378,24 +2293,23 @@ fn initHeaders(
1378 .entsize = 0,2293 .entsize = 0,
1379 };2294 };
1380 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Shdr, sh_undef);2295 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Shdr, sh_undef);
1381 elf.shdrs.appendAssumeCapacity(.{ .si = .null, .rela_si = .null, .rela_free = .none });2296 elf.shdrs.appendAssumeCapacity(.{ .lsi = .null, .ni = .none, .rela_shndx = .UNDEF, .rela_free = .none });
13822297
1383 elf.symtab.addOneAssumeCapacity().* = .{2298 elf.symtab.addOneAssumeCapacity().* = .{
1384 .ni = .none,2299 .node = .none,
1385 .loc_relocs = .none,2300 .first_target_reloc = .none,
1386 .target_relocs = .none,
1387 .unused = 0,
1388 };2301 };
1389 assert(elf.si.symtab == try elf.addSection(elf.ni.file, .{2302 assert(.symtab == try elf.addSection(elf.ni.file, .{
1390 .type = .SYMTAB,2303 .type = .SYMTAB,
1391 .size = @sizeOf(ElfN.Sym) * 1,2304 .size = @sizeOf(ElfN.Sym) * 1,
1392 .addralign = addr_align,2305 .addralign = addr_align,
1393 .entsize = @sizeOf(ElfN.Sym),2306 .entsize = @sizeOf(ElfN.Sym),
1394 .node_align = elf.mf.flags.block_size,2307 .node_align = elf.mf.flags.block_size,
2308 .info = 1, // index of first non-local symbol
1395 }));2309 }));
1396 const symtab_null = @field(elf.symPtr(.null), @tagName(ct_class));2310 const symtab_null = @field(elf.symPtr(.null), @tagName(ct_class));
1397 symtab_null.* = .{2311 symtab_null.* = .{
1398 .name = try elf.string(.strtab, ""),2312 .name = @intFromEnum(String(.strtab).empty),
1399 .value = 0,2313 .value = 0,
1400 .size = 0,2314 .size = 0,
1401 .info = .{ .type = .NOTYPE, .bind = .LOCAL },2315 .info = .{ .type = .NOTYPE, .bind = .LOCAL },
...@@ -1408,55 +2322,56 @@ fn initHeaders(...@@ -1408,55 +2322,56 @@ fn initHeaders(
1408 ehdr.shstrndx = ehdr.shnum;2322 ehdr.shstrndx = ehdr.shnum;
1409 },2323 },
1410 }2324 }
1411 assert(elf.si.shstrtab == try elf.addSection(elf.ni.file, .{2325 assert(.shstrtab == try elf.addSection(elf.ni.file, .{
1412 .type = .STRTAB,2326 .type = .STRTAB,
1413 .size = 1,2327 .size = 1,
1414 .entsize = 1,2328 .entsize = 1,
1415 .node_align = elf.mf.flags.block_size,2329 .node_align = elf.mf.flags.block_size,
1416 }));2330 }));
1417 try elf.renameSection(.symtab, ".symtab");2331 Section.Index.get(.shstrtab, elf).ni.slice(&elf.mf)[0] = 0;
1418 try elf.renameSection(.shstrtab, ".shstrtab");
1419 elf.si.shstrtab.node(elf).slice(&elf.mf)[0] = 0;
14202332
1421 assert(elf.si.strtab == try elf.addSection(elf.ni.file, .{2333 try Section.Index.symtab.rename(elf, ".symtab");
2334 try Section.Index.shstrtab.rename(elf, ".shstrtab");
2335
2336 assert(.strtab == try elf.addSection(elf.ni.file, .{
1422 .name = ".strtab",2337 .name = ".strtab",
1423 .type = .STRTAB,2338 .type = .STRTAB,
1424 .size = 1,2339 .size = 1,
1425 .entsize = 1,2340 .entsize = 1,
1426 .node_align = elf.mf.flags.block_size,2341 .node_align = elf.mf.flags.block_size,
1427 }));2342 }));
1428 switch (elf.shdrPtr(elf.si.symtab.shndx(elf))) {2343 Section.Index.get(.strtab, elf).ni.slice(&elf.mf)[0] = 0;
1429 inline else => |shdr| elf.targetStore(&shdr.link, @intFromEnum(elf.si.strtab.shndx(elf))),2344 switch (elf.shdrPtr(.symtab)) {
2345 inline else => |shdr| elf.targetStore(&shdr.link, @intFromEnum(Section.Index.strtab)),
1430 }2346 }
1431 elf.si.strtab.node(elf).slice(&elf.mf)[0] = 0;
14322347
1433 assert(elf.si.rodata == try elf.addSection(elf.ni.rodata, .{2348 assert(.rodata == try elf.addSection(elf.ni.rodata, .{
1434 .name = ".rodata",2349 .name = ".rodata",
1435 .flags = .{ .ALLOC = true },2350 .flags = .{ .ALLOC = true },
1436 .addralign = elf.mf.flags.block_size,2351 .addralign = elf.mf.flags.block_size,
1437 }));2352 }));
1438 assert(elf.si.text == try elf.addSection(elf.ni.text, .{2353 assert(.text == try elf.addSection(elf.ni.text, .{
1439 .name = ".text",2354 .name = ".text",
1440 .flags = .{ .ALLOC = true, .EXECINSTR = true },2355 .flags = .{ .ALLOC = true, .EXECINSTR = true },
1441 .addralign = elf.mf.flags.block_size,2356 .addralign = elf.mf.flags.block_size,
1442 }));2357 }));
1443 assert(elf.si.data == try elf.addSection(elf.ni.data, .{2358 assert(.data == try elf.addSection(elf.ni.data, .{
1444 .name = ".data",2359 .name = ".data",
1445 .flags = .{ .WRITE = true, .ALLOC = true },2360 .flags = .{ .WRITE = true, .ALLOC = true },
1446 .addralign = elf.mf.flags.block_size,2361 .addralign = elf.mf.flags.block_size,
1447 }));2362 }));
1448 assert(elf.si.data_rel_ro == try elf.addSection(elf.ni.data_rel_ro, .{2363 assert(.data_rel_ro == try elf.addSection(elf.ni.data_rel_ro, .{
1449 .name = ".data.rel.ro",2364 .name = ".data.rel.ro",
1450 .flags = .{ .WRITE = true, .ALLOC = true },2365 .flags = .{ .WRITE = true, .ALLOC = true },
1451 .addralign = elf.mf.flags.block_size,2366 .addralign = elf.mf.flags.block_size,
1452 }));2367 }));
1453 if (@"type" != .REL) {2368 if (@"type" != .REL) {
1454 assert(elf.si.got == try elf.addSection(elf.ni.data_rel_ro, .{2369 elf.shndx.got = try elf.addSection(elf.ni.data_rel_ro, .{
1455 .name = ".got",2370 .name = ".got",
1456 .flags = .{ .WRITE = true, .ALLOC = true },2371 .flags = .{ .WRITE = true, .ALLOC = true },
1457 .addralign = addr_align,2372 .addralign = addr_align,
1458 }));2373 });
1459 assert(elf.si.got_plt == try elf.addSection(2374 elf.shndx.got_plt = try elf.addSection(
1460 if (elf.options.z_now) elf.ni.data_rel_ro else elf.ni.data,2375 if (elf.options.z_now) elf.ni.data_rel_ro else elf.ni.data,
1461 .{2376 .{
1462 .name = ".got.plt",2377 .name = ".got.plt",
...@@ -1469,26 +2384,26 @@ fn initHeaders(...@@ -1469,26 +2384,26 @@ fn initHeaders(
1469 },2384 },
1470 .addralign = addr_align,2385 .addralign = addr_align,
1471 },2386 },
1472 ));2387 );
1473 const plt_size: std.elf.Xword, const plt_align: std.mem.Alignment, const plt_sec =2388 const plt_size: std.elf.Xword, const plt_align: std.mem.Alignment, const plt_sec =
1474 switch (machine) {2389 switch (machine) {
1475 else => @panic(@tagName(machine)),2390 else => @panic(@tagName(machine)),
1476 .X86_64 => .{ 16, .@"16", true },2391 .X86_64 => .{ 16, .@"16", true },
1477 };2392 };
1478 assert(elf.si.plt == try elf.addSection(elf.ni.text, .{2393 elf.shndx.plt = try elf.addSection(elf.ni.text, .{
1479 .name = ".plt",2394 .name = ".plt",
1480 .type = .PROGBITS,2395 .type = .PROGBITS,
1481 .flags = .{ .ALLOC = true, .EXECINSTR = true },2396 .flags = .{ .ALLOC = true, .EXECINSTR = true },
1482 .size = plt_size,2397 .size = plt_size,
1483 .addralign = plt_align,2398 .addralign = plt_align,
1484 .node_align = elf.mf.flags.block_size,2399 .node_align = elf.mf.flags.block_size,
1485 }));2400 });
1486 if (plt_sec) assert(elf.si.plt_sec == try elf.addSection(elf.ni.text, .{2401 if (plt_sec) elf.shndx.plt_sec = try elf.addSection(elf.ni.text, .{
1487 .name = ".plt.sec",2402 .name = ".plt.sec",
1488 .flags = .{ .ALLOC = true, .EXECINSTR = true },2403 .flags = .{ .ALLOC = true, .EXECINSTR = true },
1489 .addralign = plt_align,2404 .addralign = plt_align,
1490 .node_align = elf.mf.flags.block_size,2405 .node_align = elf.mf.flags.block_size,
1491 }));2406 });
1492 if (maybe_interp) |interp| {2407 if (maybe_interp) |interp| {
1493 const interp_ni = try elf.mf.addLastChildNode(gpa, elf.ni.rodata, .{2408 const interp_ni = try elf.mf.addLastChildNode(gpa, elf.ni.rodata, .{
1494 .size = interp.len + 1,2409 .size = interp.len + 1,
...@@ -1499,13 +2414,13 @@ fn initHeaders(...@@ -1499,13 +2414,13 @@ fn initHeaders(
1499 elf.nodes.appendAssumeCapacity(.{ .segment = interp_phndx });2414 elf.nodes.appendAssumeCapacity(.{ .segment = interp_phndx });
1500 elf.phdrs.items[interp_phndx] = interp_ni;2415 elf.phdrs.items[interp_phndx] = interp_ni;
15012416
1502 const sec_interp_si = try elf.addSection(interp_ni, .{2417 const sec_interp_shndx = try elf.addSection(interp_ni, .{
1503 .name = ".interp",2418 .name = ".interp",
1504 .type = .PROGBITS,2419 .type = .PROGBITS,
1505 .flags = .{ .ALLOC = true },2420 .flags = .{ .ALLOC = true },
1506 .size = @intCast(interp.len + 1),2421 .size = @intCast(interp.len + 1),
1507 });2422 });
1508 const sec_interp = sec_interp_si.node(elf).slice(&elf.mf);2423 const sec_interp = sec_interp_shndx.get(elf).ni.slice(&elf.mf);
1509 @memcpy(sec_interp[0..interp.len], interp);2424 @memcpy(sec_interp[0..interp.len], interp);
1510 sec_interp[interp.len] = 0;2425 sec_interp[interp.len] = 0;
1511 }2426 }
...@@ -1518,7 +2433,7 @@ fn initHeaders(...@@ -1518,7 +2433,7 @@ fn initHeaders(
1518 elf.nodes.appendAssumeCapacity(.{ .segment = dynamic_phndx });2433 elf.nodes.appendAssumeCapacity(.{ .segment = dynamic_phndx });
1519 elf.phdrs.items[dynamic_phndx] = dynamic_ni;2434 elf.phdrs.items[dynamic_phndx] = dynamic_ni;
15202435
1521 elf.si.dynstr = try elf.addSection(elf.ni.rodata, .{2436 const dynstr_shndx = try elf.addSection(elf.ni.rodata, .{
1522 .name = ".dynstr",2437 .name = ".dynstr",
1523 .type = .STRTAB,2438 .type = .STRTAB,
1524 .flags = .{ .ALLOC = true },2439 .flags = .{ .ALLOC = true },
...@@ -1526,26 +2441,27 @@ fn initHeaders(...@@ -1526,26 +2441,27 @@ fn initHeaders(
1526 .entsize = 1,2441 .entsize = 1,
1527 .node_align = elf.mf.flags.block_size,2442 .node_align = elf.mf.flags.block_size,
1528 });2443 });
1529 const dynstr_shndx = elf.si.dynstr.shndx(elf);2444 dynstr_shndx.get(elf).ni.slice(&elf.mf)[0] = 0;
1530 elf.dynsym.putAssumeCapacityNoClobber(.null, {});2445 elf.shndx.dynstr = dynstr_shndx;
2446
1531 switch (class) {2447 switch (class) {
1532 .NONE, _ => unreachable,2448 .NONE, _ => unreachable,
1533 inline else => |ct_class| {2449 inline else => |ct_class| {
1534 const Sym = ct_class.ElfN().Sym;2450 const Sym = ct_class.ElfN().Sym;
1535 elf.si.dynsym = try elf.addSection(elf.ni.rodata, .{2451 elf.shndx.dynsym = try elf.addSection(elf.ni.rodata, .{
1536 .name = ".dynsym",2452 .name = ".dynsym",
1537 .type = .DYNSYM,2453 .type = .DYNSYM,
1538 .flags = .{ .ALLOC = true },2454 .flags = .{ .ALLOC = true },
1539 .size = @sizeOf(Sym) * 1,2455 .size = @sizeOf(Sym) * 1,
1540 .link = @intFromEnum(dynstr_shndx),2456 .link = dynstr_shndx.toSection().?,
1541 .info = 1,2457 .info = 1,
1542 .addralign = addr_align,2458 .addralign = addr_align,
1543 .entsize = @sizeOf(Sym),2459 .entsize = @sizeOf(Sym),
1544 .node_align = elf.mf.flags.block_size,2460 .node_align = elf.mf.flags.block_size,
1545 });2461 });
1546 const dynsym_null = &@field(elf.dynsymSlice(), @tagName(ct_class))[0];2462 const dynsym_null = @field(elf.dynsymPtr(0), @tagName(ct_class));
1547 dynsym_null.* = .{2463 dynsym_null.* = .{
1548 .name = try elf.string(.dynstr, ""),2464 .name = @intFromEnum(String(.dynstr).empty),
1549 .value = 0,2465 .value = 0,
1550 .size = 0,2466 .size = 0,
1551 .info = .{ .type = .NOTYPE, .bind = .LOCAL },2467 .info = .{ .type = .NOTYPE, .bind = .LOCAL },
...@@ -1562,57 +2478,57 @@ fn initHeaders(...@@ -1562,57 +2478,57 @@ fn initHeaders(
1562 .NONE, _ => unreachable,2478 .NONE, _ => unreachable,
1563 inline else => |ct_class| @sizeOf(ct_class.ElfN().Rela),2479 inline else => |ct_class| @sizeOf(ct_class.ElfN().Rela),
1564 };2480 };
1565 elf.si.got.shndx(elf).get(elf).rela_si = try elf.addSection(elf.ni.rodata, .{2481 elf.shndx.got.get(elf).rela_shndx = try elf.addSection(elf.ni.rodata, .{
1566 .name = ".rela.dyn",2482 .name = ".rela.dyn",
1567 .type = .RELA,2483 .type = .RELA,
1568 .flags = .{ .ALLOC = true },2484 .flags = .{ .ALLOC = true },
1569 .link = @intFromEnum(elf.si.dynsym.shndx(elf)),2485 .link = elf.shndx.dynsym.toSection().?,
1570 .addralign = addr_align,2486 .addralign = addr_align,
1571 .entsize = rela_size,2487 .entsize = rela_size,
1572 .node_align = elf.mf.flags.block_size,2488 .node_align = elf.mf.flags.block_size,
1573 });2489 });
1574 const got_plt_shndx = elf.si.got_plt.shndx(elf);2490 const got_plt_shndx = elf.shndx.got_plt;
1575 got_plt_shndx.get(elf).rela_si = try elf.addSection(elf.ni.rodata, .{2491 got_plt_shndx.get(elf).rela_shndx = try elf.addSection(elf.ni.rodata, .{
1576 .name = ".rela.plt",2492 .name = ".rela.plt",
1577 .type = .RELA,2493 .type = .RELA,
1578 .flags = .{ .ALLOC = true, .INFO_LINK = true },2494 .flags = .{ .ALLOC = true, .INFO_LINK = true },
1579 .link = @intFromEnum(elf.si.dynsym.shndx(elf)),2495 .link = elf.shndx.dynsym.toSection().?,
1580 .info = @intFromEnum(got_plt_shndx),2496 .info = got_plt_shndx.toSection().?,
1581 .addralign = addr_align,2497 .addralign = addr_align,
1582 .entsize = rela_size,2498 .entsize = rela_size,
1583 .node_align = elf.mf.flags.block_size,2499 .node_align = elf.mf.flags.block_size,
1584 });2500 });
1585 elf.si.dynamic = try elf.addSection(dynamic_ni, .{2501 elf.shndx.dynamic = try elf.addSection(dynamic_ni, .{
1586 .name = ".dynamic",2502 .name = ".dynamic",
1587 .type = .DYNAMIC,2503 .type = .DYNAMIC,
1588 .flags = .{ .ALLOC = true, .WRITE = true },2504 .flags = .{ .ALLOC = true, .WRITE = true },
1589 .link = @intFromEnum(dynstr_shndx),2505 .link = dynstr_shndx.toSection().?,
1590 .entsize = @intCast(addr_align.toByteUnits() * 2),2506 .entsize = @intCast(addr_align.toByteUnits() * 2),
1591 .node_align = addr_align,2507 .node_align = addr_align,
1592 });2508 });
1593 switch (machine) {2509 switch (machine) {
1594 else => @panic(@tagName(machine)),2510 else => @panic(@tagName(machine)),
1595 .X86_64 => {2511 .X86_64 => {
1596 @memcpy(elf.si.plt.node(elf).slice(&elf.mf)[0..16], &[16]u8{2512 const plt_ni = elf.shndx.plt.get(elf).ni;
2513 const got_plt_sym: Symbol.Id = .local(elf.shndx.got_plt.get(elf).lsi);
2514 @memcpy(plt_ni.slice(&elf.mf)[0..16], &[16]u8{
1597 0xff, 0x35, 0x00, 0x00, 0x00, 0x00, // push 0x0(%rip)2515 0xff, 0x35, 0x00, 0x00, 0x00, 0x00, // push 0x0(%rip)
1598 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *0x0(%rip)2516 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *0x0(%rip)
1599 0x0f, 0x1f, 0x40, 0x00, // nopl 0x0(%rax)2517 0x0f, 0x1f, 0x40, 0x00, // nopl 0x0(%rax)
1600 });2518 });
1601 const plt_sym = elf.si.plt.get(elf);2519 elf.first_plt_reloc = @enumFromInt(elf.relocs.items.len);
1602 assert(plt_sym.loc_relocs == .none);2520 try elf.ensureUnusedRelocCapacity(plt_ni, 2);
1603 plt_sym.loc_relocs = @enumFromInt(elf.relocs.items.len);
1604 try elf.ensureUnusedRelocCapacity(elf.si.plt, 2);
1605 elf.addRelocAssumeCapacity(2521 elf.addRelocAssumeCapacity(
1606 elf.si.plt,2522 plt_ni,
1607 2,2523 2,
1608 elf.si.got_plt,2524 got_plt_sym,
1609 8 * 1 - 4,2525 8 * 1 - 4,
1610 .{ .X86_64 = .PC32 },2526 .{ .X86_64 = .PC32 },
1611 );2527 );
1612 elf.addRelocAssumeCapacity(2528 elf.addRelocAssumeCapacity(
1613 elf.si.plt,2529 plt_ni,
1614 8,2530 8,
1615 elf.si.got_plt,2531 got_plt_sym,
1616 8 * 2 - 4,2532 8 * 2 - 4,
1617 .{ .X86_64 = .PC32 },2533 .{ .X86_64 = .PC32 },
1618 );2534 );
...@@ -1632,7 +2548,7 @@ fn initHeaders(...@@ -1632,7 +2548,7 @@ fn initHeaders(
1632 assert(maybe_interp == null);2548 assert(maybe_interp == null);
1633 assert(!have_dynamic_section);2549 assert(!have_dynamic_section);
1634 }2550 }
1635 if (comp.config.any_non_single_threaded) elf.si.tdata = try elf.addSection(elf.ni.tls, .{2551 if (comp.config.any_non_single_threaded) elf.shndx.tdata = try elf.addSection(elf.ni.tls, .{
1636 .name = ".tdata",2552 .name = ".tdata",
1637 .flags = .{ .WRITE = true, .ALLOC = true, .TLS = true },2553 .flags = .{ .WRITE = true, .ALLOC = true, .TLS = true },
1638 .addralign = elf.mf.flags.block_size,2554 .addralign = elf.mf.flags.block_size,
...@@ -1642,7 +2558,7 @@ fn initHeaders(...@@ -1642,7 +2558,7 @@ fn initHeaders(
16422558
1643pub fn startProgress(elf: *Elf, prog_node: std.Progress.Node) void {2559pub fn startProgress(elf: *Elf, prog_node: std.Progress.Node) void {
1644 prog_node.increaseEstimatedTotalItems(4);2560 prog_node.increaseEstimatedTotalItems(4);
1645 elf.const_prog_node = prog_node.start("Constants", elf.pending_uavs.count());2561 elf.const_prog_node = prog_node.start("Constants", elf.pending_uavs.items.len);
1646 elf.synth_prog_node = prog_node.start("Synthetics", count: {2562 elf.synth_prog_node = prog_node.start("Synthetics", count: {
1647 var count: usize = 0;2563 var count: usize = 0;
1648 for (&elf.lazy.values) |*lazy| count += lazy.map.count() - lazy.pending_index;2564 for (&elf.lazy.values) |*lazy| count += lazy.map.count() - lazy.pending_index;
...@@ -1669,35 +2585,105 @@ pub fn endProgress(elf: *Elf) void {...@@ -1669,35 +2585,105 @@ pub fn endProgress(elf: *Elf) void {
1669fn getNode(elf: *const Elf, ni: MappedFile.Node.Index) Node {2585fn getNode(elf: *const Elf, ni: MappedFile.Node.Index) Node {
1670 return elf.nodes.get(@intFromEnum(ni));2586 return elf.nodes.get(@intFromEnum(ni));
1671}2587}
2588/// Asserts that `ni` is a section, input section, NAV, UAV, or lazy code/data.
2589fn getNodeShndx(elf: *Elf, ni: MappedFile.Node.Index) Section.Index {
2590 return switch (elf.getNode(ni)) {
2591 .file => unreachable,
2592 .ehdr => unreachable,
2593 .shdr => unreachable,
2594 .segment => unreachable,
2595
2596 .section => |shndx| shndx,
2597
2598 .input_section,
2599 .nav,
2600 .uav,
2601 .lazy_code,
2602 .lazy_const_data,
2603 => elf.getNode(ni.parent(&elf.mf)).section,
2604 };
2605}
1672fn computeNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 {2606fn computeNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 {
1673 const parent_vaddr = parent_vaddr: {2607 const parent_vaddr = switch (elf.getNode(ni.parent(&elf.mf))) {
1674 const parent_ni = ni.parent(&elf.mf);2608 .file => return 0,
1675 const parent_si = switch (elf.getNode(parent_ni)) {2609 .ehdr, .shdr => unreachable,
1676 .file => return 0,2610 .segment => |phndx| switch (elf.phdrSlice()) {
1677 .ehdr, .shdr => unreachable,2611 inline else => |phdr| elf.targetLoad(&phdr[phndx].vaddr),
1678 .segment => |phndx| break :parent_vaddr switch (elf.phdrSlice()) {2612 },
1679 inline else => |phdr| elf.targetLoad(&phdr[phndx].vaddr),2613 .section => |shndx| if (shndx == elf.shndx.tdata) 0 else shndx.vaddr(elf),
1680 },2614 .input_section => unreachable,
1681 .section => |si| si,2615 inline .nav, .uav, .lazy_code, .lazy_const_data => |i| Symbol.Id.local(i.symbol(elf)).value(elf),
1682 .input_section => unreachable,
1683 inline .nav, .uav, .lazy_code, .lazy_const_data => |mi| mi.symbol(elf),
1684 };
1685 break :parent_vaddr if (parent_si == elf.si.tdata) 0 else switch (elf.symPtr(parent_si)) {
1686 inline else => |sym| elf.targetLoad(&sym.value),
1687 };
1688 };2616 };
1689 const offset, _ = ni.location(&elf.mf).resolve(&elf.mf);2617 const offset, _ = ni.location(&elf.mf).resolve(&elf.mf);
1690 return parent_vaddr + offset;2618 return parent_vaddr + offset;
1691}2619}
16922620
1693pub fn identClass(elf: *const Elf) std.elf.CLASS {2621/// Deletes any existing relocations in the given node, and marks the start of the node's contiguous
2622/// sequence of relocations, so that the caller may append the node's updated relocations.
2623///
2624/// Asserts that `ni` must be a node which supports relocations (see `Elf.Node`). Does not support
2625/// the special-case sections '.plt' and '.dynamic'.
2626fn resetNodeRelocs(elf: *Elf, ni: MappedFile.Node.Index) void {
2627 const first_reloc_ptr: *Reloc.Index = switch (elf.getNode(ni)) {
2628 .file => unreachable, // cannot contain relocs
2629 .ehdr => unreachable, // cannot contain relocs
2630 .shdr => unreachable, // cannot contain relocs
2631 .segment => unreachable, // cannot contain relocs
2632 .section => unreachable, // cannot contain relocs (.plt and .dynamic unsupported)
2633 .input_section => |isi| &elf.input_sections.items[@intFromEnum(isi)].first_reloc,
2634 .nav => |nmi| &elf.navs.values()[@intFromEnum(nmi)].first_reloc,
2635 .uav => |umi| &elf.uavs.values()[@intFromEnum(umi)].first_reloc,
2636 inline .lazy_code, .lazy_const_data => |lmi| &elf.lazy.getPtr(lmi.ref().kind).map.values()[lmi.ref().index].first_reloc,
2637 };
2638 if (first_reloc_ptr.* != .none) {
2639 for (elf.relocs.items[@intFromEnum(first_reloc_ptr.*)..]) |*reloc| {
2640 if (reloc.node != ni) break;
2641 reloc.delete(elf);
2642 }
2643 }
2644 first_reloc_ptr.* = @enumFromInt(elf.relocs.items.len);
2645}
2646
2647/// Given that `node` has moved, updates all relocations in `node` (starting from `first_reloc`) as
2648/// needed. In relocatables, this means updating the offsets of those relocations. In ELF modules,
2649/// this means applying the relocations.
2650fn flushMovedNodeRelocs(
2651 elf: *Elf,
2652 node: MappedFile.Node.Index,
2653 node_vaddr: u64,
2654 first_reloc: Reloc.Index,
2655) void {
2656 if (first_reloc == .none) return;
2657 switch (elf.ehdrField(.type)) {
2658 .NONE, .CORE, _ => unreachable,
2659 .REL => {
2660 // In a relocatable, we're not actually applying any relocations ourselves, but we need
2661 // to update the offsets of the relocation entries since the node they're in has moved.
2662 for (elf.relocs.items[@intFromEnum(first_reloc)..]) |*reloc| {
2663 if (reloc.node != node) break;
2664 reloc.updateNodeOffset(elf, node_vaddr);
2665 }
2666 },
2667 .EXEC, .DYN => {
2668 // For an ELF module, we just need to apply relocations.
2669 for (elf.relocs.items[@intFromEnum(first_reloc)..]) |*reloc| {
2670 if (reloc.node != node) break;
2671 reloc.apply(elf);
2672 }
2673 // TODO: once we're emitting runtime relocation entries, we need to update their offsets
2674 // too, like the logic for relocatables above.
2675 },
2676 }
2677}
2678
2679fn identClass(elf: *const Elf) std.elf.CLASS {
1694 return @enumFromInt(elf.mf.memory_map.memory[std.elf.EI.CLASS]);2680 return @enumFromInt(elf.mf.memory_map.memory[std.elf.EI.CLASS]);
1695}2681}
1696pub fn identData(elf: *const Elf) std.elf.DATA {2682fn identData(elf: *const Elf) std.elf.DATA {
1697 return @enumFromInt(elf.mf.memory_map.memory[std.elf.EI.DATA]);2683 return @enumFromInt(elf.mf.memory_map.memory[std.elf.EI.DATA]);
1698}2684}
16992685
1700pub fn targetEndian(elf: *const Elf) std.lang.Endian {2686fn targetEndian(elf: *const Elf) std.lang.Endian {
1701 return switch (elf.identData()) {2687 return switch (elf.identData()) {
1702 .NONE, _ => unreachable,2688 .NONE, _ => unreachable,
1703 .@"2LSB" => .little,2689 .@"2LSB" => .little,
...@@ -1731,12 +2717,12 @@ fn targetStore(elf: *const Elf, ptr: anytype, val: @typeInfo(@TypeOf(ptr)).point...@@ -1731,12 +2717,12 @@ fn targetStore(elf: *const Elf, ptr: anytype, val: @typeInfo(@TypeOf(ptr)).point
1731 };2717 };
1732}2718}
17332719
1734pub const EhdrPtr = union(std.elf.CLASS) {2720const EhdrPtr = union(std.elf.CLASS) {
1735 NONE: noreturn,2721 NONE: noreturn,
1736 @"32": *std.elf.Elf32.Ehdr,2722 @"32": *std.elf.Elf32.Ehdr,
1737 @"64": *std.elf.Elf64.Ehdr,2723 @"64": *std.elf.Elf64.Ehdr,
1738};2724};
1739pub fn ehdrPtr(elf: *Elf) EhdrPtr {2725fn ehdrPtr(elf: *Elf) EhdrPtr {
1740 const slice = elf.ni.ehdr.slice(&elf.mf);2726 const slice = elf.ni.ehdr.slice(&elf.mf);
1741 return switch (elf.identClass()) {2727 return switch (elf.identClass()) {
1742 .NONE, _ => unreachable,2728 .NONE, _ => unreachable,
...@@ -1747,7 +2733,7 @@ pub fn ehdrPtr(elf: *Elf) EhdrPtr {...@@ -1747,7 +2733,7 @@ pub fn ehdrPtr(elf: *Elf) EhdrPtr {
1747 ),2733 ),
1748 };2734 };
1749}2735}
1750pub fn ehdrField(2736fn ehdrField(
1751 elf: *Elf,2737 elf: *Elf,
1752 comptime field: std.meta.FieldEnum(std.elf.Elf64.Ehdr),2738 comptime field: std.meta.FieldEnum(std.elf.Elf64.Ehdr),
1753) @FieldType(std.elf.Elf64.Ehdr, @tagName(field)) {2739) @FieldType(std.elf.Elf64.Ehdr, @tagName(field)) {
...@@ -1756,12 +2742,12 @@ pub fn ehdrField(...@@ -1756,12 +2742,12 @@ pub fn ehdrField(
1756 };2742 };
1757}2743}
17582744
1759pub const PhdrSlice = union(std.elf.CLASS) {2745const PhdrSlice = union(std.elf.CLASS) {
1760 NONE: noreturn,2746 NONE: noreturn,
1761 @"32": []std.elf.Elf32.Phdr,2747 @"32": []std.elf.Elf32.Phdr,
1762 @"64": []std.elf.Elf64.Phdr,2748 @"64": []std.elf.Elf64.Phdr,
1763};2749};
1764pub fn phdrSlice(elf: *Elf) PhdrSlice {2750fn phdrSlice(elf: *Elf) PhdrSlice {
1765 assert(elf.ehdrField(.type) != .REL);2751 assert(elf.ehdrField(.type) != .REL);
1766 const slice = elf.ni.phdr.slice(&elf.mf);2752 const slice = elf.ni.phdr.slice(&elf.mf);
1767 return switch (elf.identClass()) {2753 return switch (elf.identClass()) {
...@@ -1774,104 +2760,47 @@ pub fn phdrSlice(elf: *Elf) PhdrSlice {...@@ -1774,104 +2760,47 @@ pub fn phdrSlice(elf: *Elf) PhdrSlice {
1774 };2760 };
1775}2761}
17762762
1777pub const ShdrSlice = union(std.elf.CLASS) {2763const ShdrPtr = union(std.elf.CLASS) {
1778 NONE: noreturn,
1779 @"32": []std.elf.Elf32.Shdr,
1780 @"64": []std.elf.Elf64.Shdr,
1781};
1782pub fn shdrSlice(elf: *Elf) ShdrSlice {
1783 const slice = elf.ni.shdr.slice(&elf.mf);
1784 return switch (elf.identClass()) {
1785 .NONE, _ => unreachable,
1786 inline else => |class| @unionInit(
1787 ShdrSlice,
1788 @tagName(class),
1789 @ptrCast(@alignCast(slice)),
1790 ),
1791 };
1792}
1793
1794pub const ShdrPtr = union(std.elf.CLASS) {
1795 NONE: noreturn,2764 NONE: noreturn,
1796 @"32": *std.elf.Elf32.Shdr,2765 @"32": *std.elf.Elf32.Shdr,
1797 @"64": *std.elf.Elf64.Shdr,2766 @"64": *std.elf.Elf64.Shdr,
1798};2767};
1799pub fn shdrPtr(elf: *Elf, shndx: Symbol.Index.Shndx) ShdrPtr {2768fn shdrPtr(elf: *Elf, shndx: Section.Index) ShdrPtr {
1800 return switch (elf.shdrSlice()) {2769 const raw_slice = elf.ni.shdr.slice(&elf.mf);
1801 inline else => |shdrs, class| @unionInit(ShdrPtr, @tagName(class), &shdrs[@intFromEnum(shndx)]),2770 switch (elf.identClass()) {
1802 };
1803}
1804
1805pub const SymtabSlice = union(std.elf.CLASS) {
1806 NONE: noreturn,
1807 @"32": []std.elf.Elf32.Sym,
1808 @"64": []std.elf.Elf64.Sym,
1809};
1810pub fn symtabSlice(elf: *Elf) SymtabSlice {
1811 const slice = elf.si.symtab.node(elf).slice(&elf.mf);
1812 return switch (elf.identClass()) {
1813 .NONE, _ => unreachable,2771 .NONE, _ => unreachable,
1814 inline else => |class| @unionInit(SymtabSlice, @tagName(class), @ptrCast(@alignCast(2772 inline else => |class| {
1815 slice[0..std.mem.alignBackwardAnyAlign(usize, slice.len, @sizeOf(class.ElfN().Sym))],2773 const shdr_slice: []class.ElfN().Shdr = @ptrCast(@alignCast(raw_slice));
1816 ))),2774 const shdr_ptr = &shdr_slice[@intFromEnum(shndx)];
1817 };2775 return @unionInit(ShdrPtr, @tagName(class), shdr_ptr);
2776 },
2777 }
1818}2778}
18192779
1820pub const SymPtr = union(std.elf.CLASS) {2780const SymPtr = union(std.elf.CLASS) {
1821 NONE: noreturn,2781 NONE: noreturn,
1822 @"32": *std.elf.Elf32.Sym,2782 @"32": *std.elf.Elf32.Sym,
1823 @"64": *std.elf.Elf64.Sym,2783 @"64": *std.elf.Elf64.Sym,
1824};2784};
1825pub fn symPtr(elf: *Elf, si: Symbol.Index) SymPtr {2785fn symPtr(elf: *Elf, index: Symbol.Index) SymPtr {
1826 return switch (elf.symtabSlice()) {2786 const raw_slice = Section.Index.symtab.get(elf).ni.slice(&elf.mf);
1827 inline else => |syms, class| @unionInit(SymPtr, @tagName(class), &syms[@intFromEnum(si)]),2787 switch (elf.shdrPtr(.symtab)) {
1828 };2788 inline else => |shdr, class| {
1829}2789 const size = elf.targetLoad(&shdr.size);
18302790 const slice: []class.ElfN().Sym = @ptrCast(@alignCast(raw_slice[0..@intCast(size)]));
1831pub fn dynsymSlice(elf: *Elf) SymtabSlice {2791 return @unionInit(SymPtr, @tagName(class), &slice[@intFromEnum(index)]);
1832 const slice = elf.si.dynsym.node(elf).slice(&elf.mf);2792 },
1833 return switch (elf.identClass()) {2793 }
1834 .NONE, _ => unreachable,2794}
1835 inline else => |class| @unionInit(SymtabSlice, @tagName(class), @ptrCast(@alignCast(2795fn dynsymPtr(elf: *Elf, index: u32) SymPtr {
1836 slice[0..std.mem.alignBackwardAnyAlign(usize, slice.len, @sizeOf(class.ElfN().Sym))],2796 const raw_slice = elf.shndx.dynsym.get(elf).ni.slice(&elf.mf);
1837 ))),2797 switch (elf.shdrPtr(elf.shndx.dynsym)) {
1838 };2798 inline else => |shdr, class| {
1839}2799 const size = elf.targetLoad(&shdr.size);
18402800 const slice: []class.ElfN().Sym = @ptrCast(@alignCast(raw_slice[0..@intCast(size)]));
1841fn addSymbolAssumeCapacity(elf: *Elf) Symbol.Index {2801 return @unionInit(SymPtr, @tagName(class), &slice[index]);
1842 defer elf.symtab.addOneAssumeCapacity().* = .{2802 },
1843 .ni = .none,2803 }
1844 .loc_relocs = .none,
1845 .target_relocs = .none,
1846 .unused = 0,
1847 };
1848 return @enumFromInt(elf.symtab.items.len);
1849}
1850
1851fn initSymbolAssumeCapacity(elf: *Elf, opts: Symbol.Index.InitOptions) !Symbol.Index {
1852 const si = elf.addSymbolAssumeCapacity();
1853 try si.init(elf, opts);
1854 return si;
1855}
1856
1857pub fn globalSymbol(elf: *Elf, opts: struct {
1858 name: []const u8,
1859 lib_name: ?[]const u8 = null,
1860 type: std.elf.STT,
1861 bind: std.elf.STB = .GLOBAL,
1862 visibility: std.elf.STV = .DEFAULT,
1863}) !Symbol.Index {
1864 const gpa = elf.base.comp.gpa;
1865 try elf.symtab.ensureUnusedCapacity(gpa, 1);
1866 const global_gop = try elf.globals.getOrPut(gpa, try elf.string(.strtab, opts.name));
1867 if (!global_gop.found_existing) global_gop.value_ptr.* = try elf.initSymbolAssumeCapacity(.{
1868 .name = opts.name,
1869 .lib_name = opts.lib_name,
1870 .type = opts.type,
1871 .bind = opts.bind,
1872 .visibility = opts.visibility,
1873 });
1874 return global_gop.value_ptr.*;
1875}2804}
18762805
1877fn navType(2806fn navType(
...@@ -1886,97 +2815,135 @@ fn navType(...@@ -1886,97 +2815,135 @@ fn navType(
1886 else2815 else
1887 .OBJECT;2816 .OBJECT;
1888}2817}
1889fn namedSection(elf: *const Elf, name: []const u8) ?Symbol.Index {2818fn namedSection(elf: *const Elf, name: []const u8) ?Section.Index {
1890 if (std.mem.eql(u8, name, ".rodata") or2819 if (std.mem.eql(u8, name, ".rodata") or
1891 std.mem.startsWith(u8, name, ".rodata.")) return elf.si.rodata;2820 std.mem.startsWith(u8, name, ".rodata.")) return .rodata;
1892 if (std.mem.eql(u8, name, ".text") or2821 if (std.mem.eql(u8, name, ".text") or
1893 std.mem.startsWith(u8, name, ".text.")) return elf.si.text;2822 std.mem.startsWith(u8, name, ".text.")) return .text;
1894 if (std.mem.eql(u8, name, ".data") or2823 if (std.mem.eql(u8, name, ".data") or
1895 std.mem.startsWith(u8, name, ".data.")) return elf.si.data;2824 std.mem.startsWith(u8, name, ".data.")) return .data;
1896 if (std.mem.eql(u8, name, ".tdata") or2825 if (std.mem.eql(u8, name, ".tdata") or
1897 std.mem.startsWith(u8, name, ".tdata.")) return elf.si.tdata;2826 std.mem.startsWith(u8, name, ".tdata.")) return elf.shndx.tdata;
1898 return null;2827 return null;
1899}2828}
1900fn navSection(
1901 elf: *Elf,
1902 ip: *const InternPool,
1903 nav_resolved: @typeInfo(@FieldType(InternPool.Nav, "resolved")).optional.child,
1904) Symbol.Index {
1905 if (nav_resolved.@"linksection".toSlice(ip)) |@"linksection"|
1906 if (elf.namedSection(@"linksection")) |si| return si;
1907 return switch (navType(
1908 ip,
1909 nav_resolved,
1910 elf.base.comp.config.any_non_single_threaded,
1911 )) {
1912 else => unreachable,
1913 .FUNC => elf.si.text,
1914 .OBJECT => elf.si.data,
1915 .TLS => elf.si.tdata,
1916 };
1917}
1918fn navMapIndex(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Node.NavMapIndex {2829fn navMapIndex(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Node.NavMapIndex {
1919 const gpa = zcu.gpa;2830 const gpa = zcu.gpa;
1920 const ip = &zcu.intern_pool;2831 const ip = &zcu.intern_pool;
1921 const nav = ip.getNav(nav_index);2832 const nav = ip.getNav(nav_index);
1922 try elf.symtab.ensureUnusedCapacity(gpa, 1);
1923 const nav_gop = try elf.navs.getOrPut(gpa, nav_index);
1924 if (!nav_gop.found_existing) nav_gop.value_ptr.* = try elf.initSymbolAssumeCapacity(.{
1925 .name = nav.fqn.toSlice(ip),
1926 .type = navType(ip, nav.resolved.?, elf.base.comp.config.any_non_single_threaded),
1927 });
1928 return @enumFromInt(nav_gop.index);
1929}
1930pub fn navSymbol(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Symbol.Index {
1931 const ip = &zcu.intern_pool;
1932 const nav = ip.getNav(nav_index);
1933 if (nav.getExtern(ip)) |@"extern"| return elf.globalSymbol(.{
1934 .name = @"extern".name.toSlice(ip),
1935 .lib_name = @"extern".lib_name.toSlice(ip),
1936 .type = navType(ip, nav.resolved.?, elf.base.comp.config.any_non_single_threaded),
1937 .bind = switch (@"extern".linkage) {
1938 .internal => .LOCAL,
1939 .strong => .GLOBAL,
1940 .weak => .WEAK,
1941 .link_once => return error.LinkOnceUnsupported,
1942 },
1943 .visibility = switch (@"extern".visibility) {
1944 .default => .DEFAULT,
1945 .hidden => .HIDDEN,
1946 .protected => .PROTECTED,
1947 },
1948 });
1949 const nmi = try elf.navMapIndex(zcu, nav_index);
1950 return nmi.symbol(elf);
1951}
19522833
1953fn uavMapIndex(elf: *Elf, uav_val: InternPool.Index) !Node.UavMapIndex {2834 try elf.ensureUnusedSymbolCapacity(1, .all_local);
1954 const gpa = elf.base.comp.gpa;2835 try elf.nodes.ensureUnusedCapacity(gpa, 1);
1955 try elf.symtab.ensureUnusedCapacity(gpa, 1);2836 try elf.navs.ensureUnusedCapacity(gpa, 1);
1956 const uav_gop = try elf.uavs.getOrPut(gpa, uav_val);2837
1957 if (!uav_gop.found_existing)2838 const nav_gop = elf.navs.getOrPutAssumeCapacity(nav_index);
1958 uav_gop.value_ptr.* = try elf.initSymbolAssumeCapacity(.{ .type = .OBJECT });2839 const nmi: Node.NavMapIndex = @enumFromInt(nav_gop.index);
1959 return @enumFromInt(uav_gop.index);2840 if (!nav_gop.found_existing) {
1960}2841 const sym_type = navType(ip, nav.resolved.?, elf.base.comp.config.any_non_single_threaded);
1961pub fn uavSymbol(elf: *Elf, uav_val: InternPool.Index) !Symbol.Index {2842 const shndx: Section.Index = section: {
1962 const umi = try elf.uavMapIndex(uav_val);2843 if (nav.resolved.?.@"linksection".toSlice(ip)) |@"linksection"| {
1963 return umi.symbol(elf);2844 if (elf.namedSection(@"linksection")) |shndx| break :section shndx;
2845 }
2846 break :section switch (sym_type) {
2847 else => unreachable,
2848 .FUNC => .text,
2849 .OBJECT => .data,
2850 .TLS => elf.shndx.tdata,
2851 };
2852 };
2853 const alignment: InternPool.Alignment = switch (Type.fromInterned(nav.resolved.?.type).zigTypeTag(zcu)) {
2854 .@"fn" => a: {
2855 const mod = zcu.navFileScope(nav_index).mod.?;
2856 const target = &mod.resolved_target.result;
2857 const min = target_util.minFunctionAlignment(target);
2858 break :a switch (nav.resolved.?.@"align") {
2859 else => |a| a.maxStrict(min),
2860 .none => switch (mod.optimize_mode) {
2861 .Debug,
2862 .ReleaseSafe,
2863 .ReleaseFast,
2864 => target_util.defaultFunctionAlignment(target),
2865 .ReleaseSmall => min,
2866 },
2867 };
2868 },
2869 else => switch (nav.resolved.?.@"align") {
2870 .none => Type.fromInterned(nav.resolved.?.type).abiAlignment(zcu),
2871 else => |a| a,
2872 },
2873 };
2874 const node = try elf.mf.addLastChildNode(gpa, shndx.get(elf).ni, .{
2875 .alignment = alignment.toStdMem(),
2876 });
2877 nav_gop.value_ptr.* = .{
2878 .lsi = elf.addLocalSymbolAssumeCapacity(.{
2879 .node = node,
2880 .name = try elf.string(.strtab, nav.fqn.toSlice(ip)),
2881 .value = 0,
2882 .size = 0,
2883 .type = sym_type,
2884 .shndx = shndx,
2885 }),
2886 .first_reloc = .none,
2887 };
2888 elf.nodes.appendAssumeCapacity(.{ .nav = nmi });
2889 }
2890 return nmi;
1964}2891}
19652892
1966pub fn lazySymbol(elf: *Elf, lazy: link.File.LazySymbol) !Symbol.Index {2893fn uavMapIndex(
2894 elf: *Elf,
2895 uav_val: InternPool.Index,
2896 uav_align: InternPool.Alignment,
2897) !Node.UavMapIndex {
1967 const gpa = elf.base.comp.gpa;2898 const gpa = elf.base.comp.gpa;
1968 try elf.symtab.ensureUnusedCapacity(gpa, 1);2899 const zcu = elf.base.comp.zcu.?;
1969 const lazy_gop = try elf.lazy.getPtr(lazy.kind).map.getOrPut(gpa, lazy.ty);2900
1970 if (!lazy_gop.found_existing) {2901 try elf.ensureUnusedSymbolCapacity(1, .all_local);
1971 lazy_gop.value_ptr.* = try elf.initSymbolAssumeCapacity(.{2902 try elf.nodes.ensureUnusedCapacity(gpa, 1);
1972 .type = switch (lazy.kind) {2903 try elf.uavs.ensureUnusedCapacity(gpa, 1);
1973 .code => .FUNC,2904 try elf.pending_uavs.ensureUnusedCapacity(gpa, 1);
1974 .const_data => .OBJECT,2905
1975 },2906 const abi_align = Value.fromInterned(uav_val).typeOf(zcu).abiAlignment(zcu);
2907 const resolved_align: InternPool.Alignment = switch (uav_align) {
2908 .none => abi_align,
2909 else => |a| a.minStrict(abi_align),
2910 };
2911
2912 const uav_gop = elf.uavs.getOrPutAssumeCapacity(uav_val);
2913 const umi: Node.UavMapIndex = @enumFromInt(uav_gop.index);
2914 if (!uav_gop.found_existing) {
2915 const shndx: Section.Index = .data;
2916 const node = try elf.mf.addLastChildNode(gpa, shndx.get(elf).ni, .{
2917 .moved = true, // see assert at end of `flushUav`
2918 .alignment = resolved_align.toStdMem(),
1976 });2919 });
1977 elf.synth_prog_node.increaseEstimatedTotalItems(1);2920 var name_buf: [32]u8 = undefined;
2921 const name = std.fmt.bufPrint(
2922 &name_buf,
2923 "__anon_{d}",
2924 .{@intFromEnum(uav_val)},
2925 ) catch unreachable;
2926 uav_gop.value_ptr.* = .{
2927 .lsi = elf.addLocalSymbolAssumeCapacity(.{
2928 .node = node,
2929 .name = try elf.string(.strtab, name),
2930 .value = 0,
2931 .size = 0,
2932 .type = .OBJECT,
2933 .shndx = shndx,
2934 }),
2935 .first_reloc = .none,
2936 };
2937 elf.nodes.appendAssumeCapacity(.{ .uav = umi });
2938 elf.const_prog_node.increaseEstimatedTotalItems(1);
2939 elf.pending_uavs.appendAssumeCapacity(umi);
2940 } else {
2941 const node = uav_gop.value_ptr.lsi.index().ptr(elf).node;
2942 if (resolved_align.toStdMem().order(node.alignment(&elf.mf)).compare(.gt)) {
2943 node.realign(&elf.mf, resolved_align.toStdMem());
2944 }
1978 }2945 }
1979 return lazy_gop.value_ptr.*;2946 return umi;
1980}2947}
19812948
1982pub fn loadInput(elf: *Elf, input: link.Input) (Io.File.Reader.SizeError ||2949pub fn loadInput(elf: *Elf, input: link.Input) (Io.File.Reader.SizeError ||
...@@ -2081,22 +3048,23 @@ fn loadObject(...@@ -2081,22 +3048,23 @@ fn loadObject(
2081 const diags = &comp.link_diags;3048 const diags = &comp.link_diags;
2082 const r = &fr.interface;3049 const r = &fr.interface;
20833050
2084 const ii: Node.InputIndex = @enumFromInt(elf.inputs.items.len);3051 const input_index: Node.InputIndex = @enumFromInt(elf.inputs.items.len);
2085 log.debug("loadObject({f}{f})", .{ path.fmtEscapeString(), fmtMemberString(member) });3052 log.debug("loadObject({f}{f})", .{ path.fmtEscapeString(), fmtMemberString(member) });
2086 const ident = try r.peek(std.elf.EI.OSABI);3053 try elf.checkInputIdent(path, r);
2087 if (!std.mem.eql(u8, ident[0..std.elf.MAGIC.len], std.elf.MAGIC)) return error.BadMagic;3054 try elf.ensureUnusedSymbolCapacity(1, .all_local);
2088 if (!std.mem.eql(u8, ident[std.elf.MAGIC.len..], elf.mf.memory_map.memory[std.elf.MAGIC.len..ident.len]))
2089 return diags.failParse(path, "bad ident", .{});
2090 try elf.symtab.ensureUnusedCapacity(gpa, 1);
2091 try elf.inputs.ensureUnusedCapacity(gpa, 1);3055 try elf.inputs.ensureUnusedCapacity(gpa, 1);
3056 const file_symbol = elf.addLocalSymbolAssumeCapacity(.{
3057 .node = .none,
3058 .name = try elf.string(.strtab, std.fs.path.stem(member orelse path.sub_path)),
3059 .value = 0,
3060 .size = 0,
3061 .type = .FILE,
3062 .shndx = .ABS,
3063 });
2092 elf.inputs.addOneAssumeCapacity().* = .{3064 elf.inputs.addOneAssumeCapacity().* = .{
2093 .path = path,3065 .path = path,
2094 .member = if (member) |m| try gpa.dupe(u8, m) else null,3066 .member = if (member) |m| try gpa.dupe(u8, m) else null,
2095 .si = try elf.initSymbolAssumeCapacity(.{3067 .file_symbol = file_symbol,
2096 .name = std.fs.path.stem(member orelse path.sub_path),
2097 .type = .FILE,
2098 .shndx = .ABS,
2099 }),
2100 };3068 };
2101 const target_endian = elf.targetEndian();3069 const target_endian = elf.targetEndian();
2102 switch (elf.identClass()) {3070 switch (elf.identClass()) {
...@@ -2108,17 +3076,17 @@ fn loadObject(...@@ -2108,17 +3076,17 @@ fn loadObject(
2108 if (ehdr.machine != elf.ehdrField(.machine))3076 if (ehdr.machine != elf.ehdrField(.machine))
2109 return diags.failParse(path, "bad machine", .{});3077 return diags.failParse(path, "bad machine", .{});
2110 if (ehdr.shoff == 0 or ehdr.shnum <= 1) return;3078 if (ehdr.shoff == 0 or ehdr.shnum <= 1) return;
2111 if (ehdr.shoff + ehdr.shentsize * ehdr.shnum > fl.size)3079 if (ehdr.shoff + @as(u64, ehdr.shentsize) * @as(u64, ehdr.shnum) > fl.size)
2112 return diags.failParse(path, "bad section header location", .{});3080 return diags.failParse(path, "bad section header location", .{});
2113 if (ehdr.shentsize < @sizeOf(ElfN.Shdr))3081 if (ehdr.shentsize < @sizeOf(ElfN.Shdr))
2114 return diags.failParse(path, "unsupported shentsize", .{});3082 return diags.failParse(path, "unsupported shentsize", .{});
2115 const sections = try gpa.alloc(struct { shdr: ElfN.Shdr, si: Symbol.Index }, ehdr.shnum);3083 const sections = try gpa.alloc(struct { shdr: ElfN.Shdr, isi: ?InputSection.Index }, ehdr.shnum);
2116 defer gpa.free(sections);3084 defer gpa.free(sections);
2117 try fr.seekTo(fl.offset + ehdr.shoff);3085 try fr.seekTo(fl.offset + ehdr.shoff);
2118 for (sections) |*section| {3086 for (sections) |*section| {
2119 section.* = .{3087 section.* = .{
2120 .shdr = try r.peekStruct(ElfN.Shdr, target_endian),3088 .shdr = try r.peekStruct(ElfN.Shdr, target_endian),
2121 .si = .null,3089 .isi = null,
2122 };3090 };
2123 try r.discardAll(ehdr.shentsize);3091 try r.discardAll(ehdr.shentsize);
2124 switch (section.shdr.type) {3092 switch (section.shdr.type) {
...@@ -2140,42 +3108,49 @@ fn loadObject(...@@ -2140,42 +3108,49 @@ fn loadObject(
2140 };3108 };
2141 defer gpa.free(shstrtab);3109 defer gpa.free(shstrtab);
2142 try elf.nodes.ensureUnusedCapacity(gpa, ehdr.shnum - 1);3110 try elf.nodes.ensureUnusedCapacity(gpa, ehdr.shnum - 1);
2143 try elf.symtab.ensureUnusedCapacity(gpa, ehdr.shnum - 1);
2144 try elf.input_sections.ensureUnusedCapacity(gpa, ehdr.shnum - 1);3111 try elf.input_sections.ensureUnusedCapacity(gpa, ehdr.shnum - 1);
2145 for (sections[1..]) |*section| switch (section.shdr.type) {3112 for (sections[1..]) |*section| switch (section.shdr.type) {
2146 else => {},3113 else => {},
2147 .PROGBITS, .NOBITS => {3114 .PROGBITS, .NOBITS => {
2148 if (section.shdr.name >= shstrtab.len) continue;3115 if (section.shdr.name >= shstrtab.len) continue;
2149 const name = std.mem.sliceTo(shstrtab[section.shdr.name..], 0);3116 const name = std.mem.sliceTo(shstrtab[section.shdr.name..], 0);
2150 const parent_si = elf.namedSection(name) orelse continue;3117 const shndx: Section.Index = elf.namedSection(name) orelse shndx: {
2151 const ni = try elf.mf.addLastChildNode(gpa, parent_si.node(elf), .{3118 // TODO: actually generate a .bss section. For now, just throw it into `.data`.
3119 if (std.mem.eql(u8, name, ".bss") or
3120 std.mem.startsWith(u8, name, ".bss.")) break :shndx .data;
3121 if (std.mem.eql(u8, name, ".tbss") or
3122 std.mem.startsWith(u8, name, ".tbss.")) break :shndx elf.shndx.tdata;
3123 break :shndx .UNDEF;
3124 };
3125 if (shndx == .UNDEF) continue;
3126 const ni = try elf.mf.addLastChildNode(gpa, shndx.get(elf).ni, .{
2152 .size = section.shdr.size,3127 .size = section.shdr.size,
2153 .alignment = .fromByteUnits(std.math.ceilPowerOfTwoAssert(3128 .alignment = .fromByteUnits(std.math.ceilPowerOfTwoAssert(
2154 usize,3129 usize,
2155 @intCast(@max(section.shdr.addralign, 1)),3130 @intCast(@max(section.shdr.addralign, 1)),
2156 )),3131 )),
2157 .moved = true,3132 .moved = true, // see assert at end of `flushInputSection`
2158 });3133 });
2159 elf.nodes.appendAssumeCapacity(.{3134 elf.nodes.appendAssumeCapacity(.{
2160 .input_section = @enumFromInt(elf.input_sections.items.len),3135 .input_section = @enumFromInt(elf.input_sections.items.len),
2161 });3136 });
2162 section.si = try elf.initSymbolAssumeCapacity(.{3137 section.isi = @enumFromInt(elf.input_sections.items.len);
2163 .type = .SECTION,
2164 .shndx = parent_si.shndx(elf),
2165 });
2166 section.si.get(elf).ni = ni;
2167 elf.input_sections.addOneAssumeCapacity().* = .{3138 elf.input_sections.addOneAssumeCapacity().* = .{
2168 .ii = ii,3139 .input = input_index,
2169 .si = section.si,
2170 .file_location = .{3140 .file_location = .{
2171 .offset = fl.offset + section.shdr.offset,3141 .offset = fl.offset + section.shdr.offset,
2172 .size = section.shdr.size,3142 .size = if (section.shdr.type == .NOBITS) 0 else section.shdr.size,
2173 },3143 },
3144 // The section vaddr is initially 0, because the symbol addresses are
3145 // zero-based. This will eventually be updated by `flushMoved`.
3146 .vaddr = 0,
3147 .node = ni,
3148 .first_reloc = .none,
2174 };3149 };
2175 elf.synth_prog_node.increaseEstimatedTotalItems(1);3150 elf.synth_prog_node.increaseEstimatedTotalItems(1);
2176 },3151 },
2177 };3152 };
2178 var symmap: std.ArrayList(Symbol.Index) = .empty;3153 var symmap: std.ArrayList(Symbol.Id) = .empty;
2179 defer symmap.deinit(gpa);3154 defer symmap.deinit(gpa);
2180 for (sections[1..], 1..) |*symtab, symtab_shndx| switch (symtab.shdr.type) {3155 for (sections[1..], 1..) |*symtab, symtab_shndx| switch (symtab.shdr.type) {
2181 else => {},3156 else => {},
...@@ -2206,105 +3181,132 @@ fn loadObject(...@@ -2206,105 +3181,132 @@ fn loadObject(
2206 ), 1) catch continue;3181 ), 1) catch continue;
2207 symmap.clearRetainingCapacity();3182 symmap.clearRetainingCapacity();
2208 try symmap.resize(gpa, symnum);3183 try symmap.resize(gpa, symnum);
2209 try elf.symtab.ensureUnusedCapacity(gpa, symnum);3184 try elf.ensureUnusedSymbolCapacity(symnum, .maybe_global);
2210 try elf.globals.ensureUnusedCapacity(gpa, symnum);
2211 try fr.seekTo(fl.offset + symtab.shdr.offset + symtab.shdr.entsize);3185 try fr.seekTo(fl.offset + symtab.shdr.offset + symtab.shdr.entsize);
2212 for (symmap.items) |*si| {3186 for (symmap.items) |*si| {
2213 si.* = .null;3187 si.* = .null;
2214 const input_sym = try r.peekStruct(ElfN.Sym, target_endian);3188 const input_sym = try r.peekStruct(ElfN.Sym, target_endian);
2215 try r.discardAll64(symtab.shdr.entsize);3189 try r.discardAll64(symtab.shdr.entsize);
2216 if (input_sym.name >= strtab.len or input_sym.shndx == std.elf.SHN_UNDEF or3190 if (input_sym.name >= strtab.len or input_sym.shndx >= ehdr.shnum) continue;
2217 input_sym.shndx >= ehdr.shnum) continue;3191
2218 switch (input_sym.info.type) {3192 const name = std.mem.sliceTo(strtab[input_sym.name..], 0);
2219 .NOTYPE, .OBJECT, .FUNC => {},3193
2220 .SECTION => {3194 const sym_type: std.elf.STT = switch (input_sym.info.type) {
2221 const section = &sections[input_sym.shndx];3195 .NOTYPE, .OBJECT, .FUNC, .TLS => |t| t,
2222 if (input_sym.value == section.shdr.addr) si.* = section.si;3196 .SECTION => .NOTYPE,
3197 .FILE, .COMMON, _ => continue,
3198 };
3199
3200 if (input_sym.shndx == std.elf.SHN_UNDEF) switch (input_sym.info.bind) {
3201 _ => |bind| return diags.failParse(
3202 path,
3203 "symbol '{s}' has unsupported binding (0x{x})",
3204 .{ name, bind },
3205 ),
3206 .LOCAL => continue,
3207 .GLOBAL, .WEAK => |bind| {
3208 si.* = elf.addGlobalSymbolAssumeCapacity(.{
3209 .node = .none,
3210 .name = try .string(elf, name),
3211 .value = input_sym.value,
3212 .size = input_sym.size,
3213 .type = sym_type,
3214 .bind = if (bind == .WEAK) .weak else .strong,
3215 .visibility = input_sym.other.visibility,
3216 .shndx = .UNDEF,
3217 }) catch |err| switch (err) {
3218 error.MultipleDefinitions => unreachable, // shndx is .UNDEF
3219 };
2223 continue;3220 continue;
2224 },3221 },
2225 else => continue,3222 };
2226 }3223
2227 const name = std.mem.sliceTo(strtab[input_sym.name..], 0);3224 const input_section_node = (sections[input_sym.shndx].isi orelse continue).node(elf);
2228 const parent_si = sections[input_sym.shndx].si;3225
2229 si.* = try elf.initSymbolAssumeCapacity(.{
2230 .name = name,
2231 .value = input_sym.value,
2232 .size = input_sym.size,
2233 .type = input_sym.info.type,
2234 .bind = input_sym.info.bind,
2235 .visibility = input_sym.other.visibility,
2236 .shndx = parent_si.shndx(elf),
2237 });
2238 si.get(elf).ni = parent_si.get(elf).ni;
2239 switch (input_sym.info.bind) {3226 switch (input_sym.info.bind) {
2240 else => {},3227 _ => |bind| return diags.failParse(
2241 .GLOBAL => {3228 path,
2242 const gop = elf.globals.getOrPutAssumeCapacity(elf.targetLoad(3229 "symbol '{s}' has unsupported binding (0x{x})",
2243 &@field(elf.symPtr(si.*), @tagName(class)).name,3230 .{ name, bind },
2244 ));3231 ),
2245 if (gop.found_existing) switch (elf.targetLoad(3232 .LOCAL => {
2246 switch (elf.symPtr(gop.value_ptr.*)) {3233 const lsi = elf.addLocalSymbolAssumeCapacity(.{
2247 inline else => |sym| &sym.info,3234 .node = input_section_node,
2248 },3235 .name = try elf.string(.strtab, name),
2249 ).bind) {3236 .value = input_sym.value,
2250 else => unreachable,3237 .size = input_sym.size,
2251 .GLOBAL => return diags.failParse(3238 .type = sym_type,
3239 .shndx = elf.getNodeShndx(input_section_node),
3240 });
3241 si.* = .local(lsi);
3242 },
3243 .GLOBAL, .WEAK => |bind| {
3244 si.* = elf.addGlobalSymbolAssumeCapacity(.{
3245 .node = input_section_node,
3246 .name = try .string(elf, name),
3247 .value = input_sym.value,
3248 .size = input_sym.size,
3249 .type = sym_type,
3250 .bind = if (bind == .WEAK) .weak else .strong,
3251 .visibility = input_sym.other.visibility,
3252 .shndx = elf.getNodeShndx(input_section_node),
3253 }) catch |err| switch (err) {
3254 error.MultipleDefinitions => return diags.failParse(
2252 path,3255 path,
2253 "multiple definitions of '{s}'",3256 "multiple definitions of '{s}'",
2254 .{name},3257 .{name},
2255 ),3258 ),
2256 .WEAK => {},
2257 };3259 };
2258 gop.value_ptr.* = si.*;
2259 },
2260 .WEAK => {
2261 const gop = elf.globals.getOrPutAssumeCapacity(elf.targetLoad(
2262 &@field(elf.symPtr(si.*), @tagName(class)).name,
2263 ));
2264 if (!gop.found_existing) gop.value_ptr.* = si.*;
2265 },3260 },
2266 }3261 }
2267 }3262 }
2268 for (sections[1..]) |*rels| switch (rels.shdr.type) {3263 for (sections[1..]) |*rel_sec| switch (rel_sec.shdr.type) {
2269 else => {},3264 else => {},
2270 inline .REL, .RELA => |sht| {3265 inline .REL, .RELA => |sht| {
2271 if (rels.shdr.link != symtab_shndx or rels.shdr.info == std.elf.SHN_UNDEF or3266 if (rel_sec.shdr.link != symtab_shndx or rel_sec.shdr.info == std.elf.SHN_UNDEF or
2272 rels.shdr.info >= ehdr.shnum) continue;3267 rel_sec.shdr.info >= ehdr.shnum) continue;
2273 const Rel = switch (sht) {3268 const Rel = switch (sht) {
2274 else => comptime unreachable,3269 else => comptime unreachable,
2275 .REL => ElfN.Rel,3270 .REL => ElfN.Rel,
2276 .RELA => ElfN.Rela,3271 .RELA => ElfN.Rela,
2277 };3272 };
2278 if (rels.shdr.entsize < @sizeOf(Rel))3273 if (rel_sec.shdr.entsize < @sizeOf(Rel))
2279 return diags.failParse(path, "unsupported rel entsize", .{});3274 return diags.failParse(path, "unsupported rel entsize", .{});
22803275
2281 const loc_sec = &sections[rels.shdr.info];3276 const loc_sec = &sections[rel_sec.shdr.info];
2282 if (loc_sec.si == .null) continue;3277 const loc_node = (loc_sec.isi orelse continue).node(elf);
2283 const loc_sym = loc_sec.si.get(elf);3278 elf.resetNodeRelocs(loc_node);
2284 assert(loc_sym.loc_relocs == .none);
2285 loc_sym.loc_relocs = @enumFromInt(elf.relocs.items.len);
22863279
2287 const relnum = std.math.divExact(3280 const relnum = std.math.divExact(
2288 u32,3281 u32,
2289 @intCast(rels.shdr.size),3282 @intCast(rel_sec.shdr.size),
2290 @intCast(rels.shdr.entsize),3283 @intCast(rel_sec.shdr.entsize),
2291 ) catch return diags.failParse(3284 ) catch return diags.failParse(
2292 path,3285 path,
2293 "relocation section size (0x{x}) is not a multiple of entsize (0x{x})",3286 "relocation section size (0x{x}) is not a multiple of entsize (0x{x})",
2294 .{ rels.shdr.size, rels.shdr.entsize },3287 .{ rel_sec.shdr.size, rel_sec.shdr.entsize },
2295 );3288 );
2296 try elf.ensureUnusedRelocCapacity(loc_sec.si, relnum);3289 try elf.ensureUnusedRelocCapacity(loc_node, relnum);
2297 try fr.seekTo(fl.offset + rels.shdr.offset);3290 try fr.seekTo(fl.offset + rel_sec.shdr.offset);
2298 for (0..relnum) |_| {3291 for (0..relnum) |_| {
2299 const rel = try r.peekStruct(Rel, target_endian);3292 const rel = try r.peekStruct(Rel, target_endian);
2300 try r.discardAll64(rels.shdr.entsize);3293 try r.discardAll64(rel_sec.shdr.entsize);
2301 if (rel.info.sym == 0 or rel.info.sym > symnum) continue;3294 if (rel.info.sym == 0) continue;
2302 const target_si = symmap.items[rel.info.sym - 1];3295 if (rel.info.sym > symnum) return diags.failParse(
2303 if (target_si == .null) continue;3296 path,
3297 "relocation target symbol index {d} exceeds symtab size",
3298 .{rel.info.sym},
3299 );
3300 const target = symmap.items[rel.info.sym - 1];
3301 if (target == Symbol.Id.null) return diags.failParse(
3302 path,
3303 "unsupported symbol at index {d} required for relocation",
3304 .{rel.info.sym},
3305 );
2304 elf.addRelocAssumeCapacity(3306 elf.addRelocAssumeCapacity(
2305 loc_sec.si,3307 loc_node,
2306 rel.offset - loc_sec.shdr.addr,3308 rel.offset - loc_sec.shdr.addr,
2307 target_si,3309 target,
2308 rel.addend,3310 rel.addend,
2309 .wrap(rel.info.type, elf),3311 .wrap(rel.info.type, elf),
2310 );3312 );
...@@ -2322,10 +3324,7 @@ fn loadDso(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) !void {...@@ -2322,10 +3324,7 @@ fn loadDso(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) !void {
2322 const r = &fr.interface;3324 const r = &fr.interface;
23233325
2324 log.debug("loadDso({f})", .{path.fmtEscapeString()});3326 log.debug("loadDso({f})", .{path.fmtEscapeString()});
2325 const ident = try r.peek(std.elf.EI.NIDENT);3327 try elf.checkInputIdent(path, r);
2326 if (!std.mem.eql(u8, ident[0..std.elf.MAGIC.len], std.elf.MAGIC)) return error.BadMagic;
2327 if (!std.mem.eql(u8, ident[std.elf.MAGIC.len..], elf.mf.memory_map.memory[std.elf.MAGIC.len..ident.len]))
2328 return diags.failParse(path, "bad ident", .{});
2329 const target_endian = elf.targetEndian();3328 const target_endian = elf.targetEndian();
2330 switch (elf.identClass()) {3329 switch (elf.identClass()) {
2331 .NONE, _ => unreachable,3330 .NONE, _ => unreachable,
...@@ -2393,7 +3392,62 @@ fn loadDso(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) !void {...@@ -2393,7 +3392,62 @@ fn loadDso(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) !void {
2393}3392}
2394fn loadDsoExact(elf: *Elf, name: []const u8) !void {3393fn loadDsoExact(elf: *Elf, name: []const u8) !void {
2395 log.debug("loadDsoExact({f})", .{std.zig.fmtString(name)});3394 log.debug("loadDsoExact({f})", .{std.zig.fmtString(name)});
2396 try elf.needed.put(elf.base.comp.gpa, try elf.string(.dynstr, name), {});3395 if (elf.shndx.dynamic != .UNDEF) {
3396 try elf.needed.put(elf.base.comp.gpa, try elf.string(.dynstr, name), {});
3397 }
3398}
3399
3400/// Validates that the `std.elf.Ident` present at the start of `r` is a compatible link input.
3401///
3402/// Returns an error if it is incompatible, or if the ident is broken or missing.
3403///
3404/// Does not advance the position of `r`. Requires `r` to have a 16-byte buffer.
3405fn checkInputIdent(
3406 elf: *const Elf,
3407 path: std.Build.Cache.Path,
3408 r: *Io.Reader,
3409) !void {
3410 const diags = &elf.base.comp.link_diags;
3411
3412 const ident = try r.peekStructPointer(std.elf.Ident);
3413 const target: *const std.elf.Ident = @ptrCast(elf.mf.memory_map.memory[0..@sizeOf(std.elf.Ident)]);
3414
3415 if (!std.mem.eql(u8, &ident.magic, std.elf.MAGIC)) {
3416 return error.BadMagic;
3417 }
3418
3419 if (ident.class != target.class) return diags.failParse(
3420 path,
3421 "bad ELF class ({?s})",
3422 .{std.enums.tagName(std.elf.CLASS, ident.class)},
3423 );
3424 if (ident.data != target.data) return diags.failParse(
3425 path,
3426 "bad ELF data encoding ({?s})",
3427 .{std.enums.tagName(std.elf.DATA, ident.data)},
3428 );
3429 if (ident.version != target.version) return diags.failParse(
3430 path,
3431 "bad ELF version ({d})",
3432 .{ident.version},
3433 );
3434
3435 // OSABI is a bit more complex. On Linux, `.NONE` and `.GNU` are both valid and both common.
3436 // It sounds reasonable to allow the value we chose *and* allow `.NONE`.
3437 const expect_abiversion: u8 = abiver: {
3438 if (ident.osabi == .NONE) break :abiver 0;
3439 if (ident.osabi == target.osabi) break :abiver target.abiversion;
3440 return diags.failParse(
3441 path,
3442 "bad ELF OS/ABI ({?s})",
3443 .{std.enums.tagName(std.elf.OSABI, ident.osabi)},
3444 );
3445 };
3446 if (ident.abiversion != expect_abiversion) return diags.failParse(
3447 path,
3448 "bad ELF ABI version ({d})",
3449 .{ident.abiversion},
3450 );
2397}3451}
23983452
2399pub fn prelink(elf: *Elf, prog_node: std.Progress.Node) !void {3453pub fn prelink(elf: *Elf, prog_node: std.Progress.Node) !void {
...@@ -2406,20 +3460,27 @@ pub fn prelink(elf: *Elf, prog_node: std.Progress.Node) !void {...@@ -2406,20 +3460,27 @@ pub fn prelink(elf: *Elf, prog_node: std.Progress.Node) !void {
2406fn prelinkInner(elf: *Elf) !void {3460fn prelinkInner(elf: *Elf) !void {
2407 const comp = elf.base.comp;3461 const comp = elf.base.comp;
2408 const gpa = comp.gpa;3462 const gpa = comp.gpa;
2409 try elf.symtab.ensureUnusedCapacity(gpa, 1);3463 try elf.ensureUnusedSymbolCapacity(1, .all_local);
2410 try elf.inputs.ensureUnusedCapacity(gpa, 1);3464 try elf.inputs.ensureUnusedCapacity(gpa, 1);
2411 const zcu_name = try std.fmt.allocPrint(gpa, "{s}_zcu", .{3465 const zcu_name = try std.fmt.allocPrint(gpa, "{s}_zcu", .{
2412 std.fs.path.stem(elf.base.emit.sub_path),3466 std.fs.path.stem(elf.base.emit.sub_path),
2413 });3467 });
2414 defer gpa.free(zcu_name);3468 defer gpa.free(zcu_name);
2415 const si = try elf.initSymbolAssumeCapacity(.{ .name = zcu_name, .type = .FILE, .shndx = .ABS });3469 const zcu_file_symbol = elf.addLocalSymbolAssumeCapacity(.{
3470 .node = .none,
3471 .name = try elf.string(.strtab, zcu_name),
3472 .value = 0,
3473 .size = 0,
3474 .type = .FILE,
3475 .shndx = .ABS,
3476 });
2416 elf.inputs.addOneAssumeCapacity().* = .{3477 elf.inputs.addOneAssumeCapacity().* = .{
2417 .path = elf.base.emit,3478 .path = elf.base.emit,
2418 .member = null,3479 .member = null,
2419 .si = si,3480 .file_symbol = zcu_file_symbol,
2420 };3481 };
24213482
2422 if (elf.si.dynamic != .null) switch (elf.identClass()) {3483 if (elf.shndx.dynamic != .UNDEF) switch (elf.identClass()) {
2423 .NONE, _ => unreachable,3484 .NONE, _ => unreachable,
2424 inline else => |ct_class| {3485 inline else => |ct_class| {
2425 const ElfN = ct_class.ElfN();3486 const ElfN = ct_class.ElfN();
...@@ -2430,9 +3491,9 @@ fn prelinkInner(elf: *Elf) !void {...@@ -2430,9 +3491,9 @@ fn prelinkInner(elf: *Elf) !void {
2430 @intFromBool(flags != 0) + @intFromBool(flags_1 != 0) +3491 @intFromBool(flags != 0) + @intFromBool(flags_1 != 0) +
2431 @intFromBool(comp.config.output_mode == .Exe) + 12;3492 @intFromBool(comp.config.output_mode == .Exe) + 12;
2432 const dynamic_size: u32 = @intCast(@sizeOf(ElfN.Addr) * 2 * dynamic_len);3493 const dynamic_size: u32 = @intCast(@sizeOf(ElfN.Addr) * 2 * dynamic_len);
2433 const dynamic_ni = elf.si.dynamic.node(elf);3494 const dynamic_ni = elf.shndx.dynamic.get(elf).ni;
2434 try dynamic_ni.resize(&elf.mf, gpa, dynamic_size);3495 try dynamic_ni.resize(&elf.mf, gpa, dynamic_size);
2435 switch (elf.shdrPtr(elf.si.dynamic.shndx(elf))) {3496 switch (elf.shdrPtr(elf.shndx.dynamic)) {
2436 inline else => |shdr| elf.targetStore(&shdr.size, dynamic_size),3497 inline else => |shdr| elf.targetStore(&shdr.size, dynamic_size),
2437 }3498 }
2438 const sec_dynamic = dynamic_ni.slice(&elf.mf);3499 const sec_dynamic = dynamic_ni.slice(&elf.mf);
...@@ -2441,10 +3502,10 @@ fn prelinkInner(elf: *Elf) !void {...@@ -2441,10 +3502,10 @@ fn prelinkInner(elf: *Elf) !void {
2441 for (3502 for (
2442 dynamic_entries[dynamic_index..][0..needed_len],3503 dynamic_entries[dynamic_index..][0..needed_len],
2443 elf.needed.keys(),3504 elf.needed.keys(),
2444 ) |*dynamic_entry, needed| dynamic_entry.* = .{ std.elf.DT_NEEDED, needed };3505 ) |*dynamic_entry, needed| dynamic_entry.* = .{ std.elf.DT_NEEDED, @intFromEnum(needed) };
2445 dynamic_index += needed_len;3506 dynamic_index += needed_len;
2446 if (elf.options.soname) |soname| {3507 if (elf.options.soname) |soname| {
2447 dynamic_entries[dynamic_index] = .{ std.elf.DT_SONAME, try elf.string(.dynstr, soname) };3508 dynamic_entries[dynamic_index] = .{ std.elf.DT_SONAME, @intFromEnum(try elf.string(.dynstr, soname)) };
2448 dynamic_index += 1;3509 dynamic_index += 1;
2449 }3510 }
2450 if (flags != 0) {3511 if (flags != 0) {
...@@ -2459,25 +3520,25 @@ fn prelinkInner(elf: *Elf) !void {...@@ -2459,25 +3520,25 @@ fn prelinkInner(elf: *Elf) !void {
2459 dynamic_entries[dynamic_index] = .{ std.elf.DT_DEBUG, 0 };3520 dynamic_entries[dynamic_index] = .{ std.elf.DT_DEBUG, 0 };
2460 dynamic_index += 1;3521 dynamic_index += 1;
2461 }3522 }
2462 const rela_dyn_si = elf.si.got.shndx(elf).get(elf).rela_si;3523 const rela_dyn_shndx = elf.shndx.got.get(elf).rela_shndx;
2463 const rela_plt_si = elf.si.got_plt.shndx(elf).get(elf).rela_si;3524 const rela_plt_shndx = elf.shndx.got_plt.get(elf).rela_shndx;
2464 dynamic_entries[dynamic_index..][0..12].* = .{3525 dynamic_entries[dynamic_index..][0..12].* = .{
2465 .{ std.elf.DT_RELA, @intCast(elf.computeNodeVAddr(rela_dyn_si.node(elf))) },3526 .{ std.elf.DT_RELA, @intCast(elf.computeNodeVAddr(rela_dyn_shndx.get(elf).ni)) },
2466 .{ std.elf.DT_RELASZ, elf.targetLoad(3527 .{ std.elf.DT_RELASZ, elf.targetLoad(
2467 &@field(elf.shdrPtr(rela_dyn_si.shndx(elf)), @tagName(ct_class)).size,3528 &@field(elf.shdrPtr(rela_dyn_shndx), @tagName(ct_class)).size,
2468 ) },3529 ) },
2469 .{ std.elf.DT_RELAENT, @sizeOf(ElfN.Rela) },3530 .{ std.elf.DT_RELAENT, @sizeOf(ElfN.Rela) },
2470 .{ std.elf.DT_JMPREL, @intCast(elf.computeNodeVAddr(rela_plt_si.node(elf))) },3531 .{ std.elf.DT_JMPREL, @intCast(elf.computeNodeVAddr(rela_plt_shndx.get(elf).ni)) },
2471 .{ std.elf.DT_PLTRELSZ, elf.targetLoad(3532 .{ std.elf.DT_PLTRELSZ, elf.targetLoad(
2472 &@field(elf.shdrPtr(rela_plt_si.shndx(elf)), @tagName(ct_class)).size,3533 &@field(elf.shdrPtr(rela_plt_shndx), @tagName(ct_class)).size,
2473 ) },3534 ) },
2474 .{ std.elf.DT_PLTGOT, @intCast(elf.computeNodeVAddr(elf.si.got_plt.node(elf))) },3535 .{ std.elf.DT_PLTGOT, @intCast(elf.computeNodeVAddr(elf.shndx.got_plt.get(elf).ni)) },
2475 .{ std.elf.DT_PLTREL, std.elf.DT_RELA },3536 .{ std.elf.DT_PLTREL, std.elf.DT_RELA },
2476 .{ std.elf.DT_SYMTAB, @intCast(elf.computeNodeVAddr(elf.si.dynsym.node(elf))) },3537 .{ std.elf.DT_SYMTAB, @intCast(elf.computeNodeVAddr(elf.shndx.dynsym.get(elf).ni)) },
2477 .{ std.elf.DT_SYMENT, @sizeOf(ElfN.Sym) },3538 .{ std.elf.DT_SYMENT, @sizeOf(ElfN.Sym) },
2478 .{ std.elf.DT_STRTAB, @intCast(elf.computeNodeVAddr(elf.si.dynstr.node(elf))) },3539 .{ std.elf.DT_STRTAB, @intCast(elf.computeNodeVAddr(elf.shndx.dynstr.get(elf).ni)) },
2479 .{ std.elf.DT_STRSZ, elf.targetLoad(3540 .{ std.elf.DT_STRSZ, elf.targetLoad(
2480 &@field(elf.shdrPtr(elf.si.dynstr.shndx(elf)), @tagName(ct_class)).size,3541 &@field(elf.shdrPtr(elf.shndx.dynstr), @tagName(ct_class)).size,
2481 ) },3542 ) },
2482 .{ std.elf.DT_NULL, 0 },3543 .{ std.elf.DT_NULL, 0 },
2483 };3544 };
...@@ -2486,42 +3547,40 @@ fn prelinkInner(elf: *Elf) !void {...@@ -2486,42 +3547,40 @@ fn prelinkInner(elf: *Elf) !void {
2486 if (elf.targetEndian() != native_endian) for (dynamic_entries) |*dynamic_entry|3547 if (elf.targetEndian() != native_endian) for (dynamic_entries) |*dynamic_entry|
2487 std.mem.byteSwapAllFields(@TypeOf(dynamic_entry.*), dynamic_entry);3548 std.mem.byteSwapAllFields(@TypeOf(dynamic_entry.*), dynamic_entry);
24883549
2489 const dynamic_sym = elf.si.dynamic.get(elf);3550 elf.first_dynamic_reloc = @enumFromInt(elf.relocs.items.len);
2490 assert(dynamic_sym.loc_relocs == .none);3551 try elf.ensureUnusedRelocCapacity(dynamic_ni, 5);
2491 dynamic_sym.loc_relocs = @enumFromInt(elf.relocs.items.len);
2492 try elf.ensureUnusedRelocCapacity(elf.si.dynamic, 5);
2493 elf.addRelocAssumeCapacity(3552 elf.addRelocAssumeCapacity(
2494 elf.si.dynamic,3553 dynamic_ni,
2495 @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 12) + 1),3554 @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 12) + 1),
2496 rela_dyn_si,3555 .local(rela_dyn_shndx.get(elf).lsi),
2497 0,3556 0,
2498 .absAddr(elf),3557 .absAddr(elf),
2499 );3558 );
2500 elf.addRelocAssumeCapacity(3559 elf.addRelocAssumeCapacity(
2501 elf.si.dynamic,3560 dynamic_ni,
2502 @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 9) + 1),3561 @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 9) + 1),
2503 rela_plt_si,3562 .local(rela_plt_shndx.get(elf).lsi),
2504 0,3563 0,
2505 .absAddr(elf),3564 .absAddr(elf),
2506 );3565 );
2507 elf.addRelocAssumeCapacity(3566 elf.addRelocAssumeCapacity(
2508 elf.si.dynamic,3567 dynamic_ni,
2509 @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 7) + 1),3568 @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 7) + 1),
2510 elf.si.got_plt,3569 .local(elf.shndx.got_plt.get(elf).lsi),
2511 0,3570 0,
2512 .absAddr(elf),3571 .absAddr(elf),
2513 );3572 );
2514 elf.addRelocAssumeCapacity(3573 elf.addRelocAssumeCapacity(
2515 elf.si.dynamic,3574 dynamic_ni,
2516 @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 5) + 1),3575 @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 5) + 1),
2517 elf.si.dynsym,3576 .local(elf.shndx.dynsym.get(elf).lsi),
2518 0,3577 0,
2519 .absAddr(elf),3578 .absAddr(elf),
2520 );3579 );
2521 elf.addRelocAssumeCapacity(3580 elf.addRelocAssumeCapacity(
2522 elf.si.dynamic,3581 dynamic_ni,
2523 @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 3) + 1),3582 @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 3) + 1),
2524 elf.si.dynstr,3583 .local(elf.shndx.dynstr.get(elf).lsi),
2525 0,3584 0,
2526 .absAddr(elf),3585 .absAddr(elf),
2527 );3586 );
...@@ -2529,36 +3588,6 @@ fn prelinkInner(elf: *Elf) !void {...@@ -2529,36 +3588,6 @@ fn prelinkInner(elf: *Elf) !void {
2529 };3588 };
2530}3589}
25313590
2532pub fn getNavVAddr(
2533 elf: *Elf,
2534 pt: Zcu.PerThread,
2535 nav: InternPool.Nav.Index,
2536 reloc_info: link.File.RelocInfo,
2537) !u64 {
2538 return elf.getVAddr(reloc_info, try elf.navSymbol(pt.zcu, nav));
2539}
2540
2541pub fn getUavVAddr(
2542 elf: *Elf,
2543 uav: InternPool.Index,
2544 reloc_info: link.File.RelocInfo,
2545) !u64 {
2546 return elf.getVAddr(reloc_info, try elf.uavSymbol(uav));
2547}
2548
2549pub fn getVAddr(elf: *Elf, reloc_info: link.File.RelocInfo, target_si: Symbol.Index) !u64 {
2550 try elf.addReloc(
2551 @enumFromInt(reloc_info.parent.atom_index),
2552 reloc_info.offset,
2553 target_si,
2554 reloc_info.addend,
2555 .absAddr(elf),
2556 );
2557 return switch (elf.symPtr(target_si)) {
2558 inline else => |sym| elf.targetLoad(&sym.value),
2559 };
2560}
2561
2562fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {3591fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
2563 name: []const u8 = "",3592 name: []const u8 = "",
2564 type: std.elf.SHT = .NULL,3593 type: std.elf.SHT = .NULL,
...@@ -2570,19 +3599,22 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {...@@ -2570,19 +3599,22 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
2570 entsize: std.elf.Word = 0,3599 entsize: std.elf.Word = 0,
2571 node_align: std.mem.Alignment = .@"1",3600 node_align: std.mem.Alignment = .@"1",
2572 fixed: bool = false,3601 fixed: bool = false,
2573}) !Symbol.Index {3602}) !Section.Index {
2574 switch (opts.type) {3603 switch (opts.type) {
2575 .NULL => assert(opts.size == 0),3604 .NULL => assert(opts.size == 0),
2576 .PROGBITS => assert(opts.size > 0),3605 .PROGBITS => assert(opts.size > 0),
2577 else => {},3606 else => {},
2578 }3607 }
3608 if (opts.flags.ALLOC and elf.ehdrField(.type) != .REL) {
3609 assert(elf.getNode(segment_ni) == .segment);
3610 }
2579 const gpa = elf.base.comp.gpa;3611 const gpa = elf.base.comp.gpa;
2580 try elf.nodes.ensureUnusedCapacity(gpa, 1);3612 try elf.nodes.ensureUnusedCapacity(gpa, 1);
2581 try elf.shdrs.ensureUnusedCapacity(gpa, 1);3613 try elf.shdrs.ensureUnusedCapacity(gpa, 1);
2582 try elf.symtab.ensureUnusedCapacity(gpa, 1);3614 if (opts.flags.ALLOC) try elf.ensureUnusedSymbolCapacity(1, .all_local);
25833615
2584 const shstrtab_entry = try elf.string(.shstrtab, opts.name);3616 const shstrtab_entry = try elf.string(.shstrtab, opts.name);
2585 const shndx: Symbol.Index.Shndx, const new_shdr_size = shndx: switch (elf.ehdrPtr()) {3617 const shndx: Section.Index, const new_shdr_size = shndx: switch (elf.ehdrPtr()) {
2586 inline else => |ehdr, class| {3618 inline else => |ehdr, class| {
2587 const shndx, const shnum = alloc_shndx: switch (elf.targetLoad(&ehdr.shnum)) {3619 const shndx, const shnum = alloc_shndx: switch (elf.targetLoad(&ehdr.shnum)) {
2588 1...std.elf.SHN_LORESERVE - 2 => |shndx| {3620 1...std.elf.SHN_LORESERVE - 2 => |shndx| {
...@@ -2605,8 +3637,8 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {...@@ -2605,8 +3637,8 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
2605 break :alloc_shndx .{ shndx, shnum };3637 break :alloc_shndx .{ shndx, shnum };
2606 },3638 },
2607 };3639 };
2608 assert(shndx < @intFromEnum(Symbol.Index.Shndx.LORESERVE));3640 assert(shndx < @intFromEnum(Section.Index.LORESERVE));
2609 break :shndx .{ @enumFromInt(shndx), elf.targetLoad(&ehdr.shentsize) * shnum };3641 break :shndx .{ @enumFromInt(shndx), @as(u64, elf.targetLoad(&ehdr.shentsize)) * @as(u64, shnum) };
2610 },3642 },
2611 };3643 };
2612 _, const shdr_node_size = elf.ni.shdr.location(&elf.mf).resolve(&elf.mf);3644 _, const shdr_node_size = elf.ni.shdr.location(&elf.mf).resolve(&elf.mf);
...@@ -2622,17 +3654,22 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {...@@ -2622,17 +3654,22 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
2622 .fixed = opts.fixed,3654 .fixed = opts.fixed,
2623 .resized = opts.size > 0,3655 .resized = opts.size > 0,
2624 });3656 });
2625 const si = elf.addSymbolAssumeCapacity();
2626 elf.nodes.appendAssumeCapacity(.{ .section = si });
2627 elf.shdrs.appendAssumeCapacity(.{ .si = si, .rela_si = .null, .rela_free = .none });
2628 si.get(elf).ni = ni;
2629 const addr = elf.computeNodeVAddr(ni);3657 const addr = elf.computeNodeVAddr(ni);
3658 const lsi: Symbol.LocalIndex = if (opts.flags.ALLOC) elf.addLocalSymbolAssumeCapacity(.{
3659 .node = ni,
3660 .name = .empty,
3661 .value = addr,
3662 .size = 0,
3663 .type = .SECTION,
3664 .shndx = shndx,
3665 }) else .null;
3666 elf.shdrs.appendAssumeCapacity(.{ .lsi = lsi, .ni = ni, .rela_shndx = .UNDEF, .rela_free = .none });
3667 elf.nodes.appendAssumeCapacity(.{ .section = shndx });
2630 const offset = ni.fileLocation(&elf.mf, false).offset;3668 const offset = ni.fileLocation(&elf.mf, false).offset;
2631 try si.init(elf, .{ .value = addr, .type = .SECTION, .shndx = shndx });
2632 switch (elf.shdrPtr(shndx)) {3669 switch (elf.shdrPtr(shndx)) {
2633 inline else => |shdr, class| {3670 inline else => |shdr, class| {
2634 shdr.* = .{3671 shdr.* = .{
2635 .name = shstrtab_entry,3672 .name = @intFromEnum(shstrtab_entry),
2636 .type = opts.type,3673 .type = opts.type,
2637 .flags = .{ .shf = opts.flags },3674 .flags = .{ .shf = opts.flags },
2638 .addr = @intCast(addr),3675 .addr = @intCast(addr),
...@@ -2646,63 +3683,31 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {...@@ -2646,63 +3683,31 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
2646 if (elf.targetEndian() != native_endian) std.mem.byteSwapAllFields(class.ElfN().Shdr, shdr);3683 if (elf.targetEndian() != native_endian) std.mem.byteSwapAllFields(class.ElfN().Shdr, shdr);
2647 },3684 },
2648 }3685 }
2649 return si;3686 return shndx;
2650}
2651
2652fn renameSection(elf: *Elf, si: Symbol.Index, name: []const u8) !void {
2653 const shstrtab_entry = try elf.string(.shstrtab, name);
2654 switch (elf.shdrPtr(si.shndx(elf))) {
2655 inline else => |shdr| elf.targetStore(&shdr.name, shstrtab_entry),
2656 }
2657}
2658
2659fn sectionName(elf: *Elf, si: Symbol.Index) [:0]const u8 {
2660 const name = elf.si.shstrtab.node(elf).slice(&elf.mf)[switch (elf.shdrPtr(si.shndx(elf))) {
2661 inline else => |shdr| elf.targetLoad(&shdr.name),
2662 }..];
2663 return name[0..std.mem.indexOfScalar(u8, name, 0).? :0];
2664}
2665
2666fn string(elf: *Elf, comptime section: enum { shstrtab, strtab, dynstr }, key: []const u8) !u32 {
2667 if (key.len == 0) return 0;
2668 return @field(elf, @tagName(section)).get(elf, @field(elf.si, @tagName(section)), key);
2669}3687}
26703688
2671pub fn addReloc(3689fn ensureUnusedRelocCapacity(elf: *Elf, node: MappedFile.Node.Index, len: usize) !void {
2672 elf: *Elf,
2673 loc_si: Symbol.Index,
2674 offset: u64,
2675 target_si: Symbol.Index,
2676 addend: i64,
2677 @"type": Reloc.Type,
2678) !void {
2679 try elf.ensureUnusedRelocCapacity(loc_si, 1);
2680 elf.addRelocAssumeCapacity(loc_si, offset, target_si, addend, @"type");
2681}
2682pub fn ensureUnusedRelocCapacity(elf: *Elf, loc_si: Symbol.Index, len: usize) !void {
2683 if (len == 0) return;3690 if (len == 0) return;
2684 const gpa = elf.base.comp.gpa;3691 const gpa = elf.base.comp.gpa;
2685 try elf.relocs.ensureUnusedCapacity(gpa, len);3692 try elf.relocs.ensureUnusedCapacity(gpa, len);
2686 const class = elf.identClass();3693 const class = elf.identClass();
2687 const rela_si, const rela_len = rela: switch (elf.ehdrField(.type)) {3694 const rela_shndx, const rela_len = rela: switch (elf.ehdrField(.type)) {
2688 .NONE, .CORE, _ => unreachable,3695 .NONE, .CORE, _ => unreachable,
2689 .REL => {3696 .REL => {
2690 const shndx = loc_si.shndx(elf);3697 const shndx = elf.getNodeShndx(node);
2691 const sh = shndx.get(elf);3698 if (shndx.get(elf).rela_shndx == .UNDEF) {
2692 if (sh.rela_si == .null) {
2693 var bfa_buf: [32]u8 = undefined;3699 var bfa_buf: [32]u8 = undefined;
2694 var bfa: std.heap.BufferFirstAllocator = .init(&bfa_buf, gpa);3700 var bfa: std.heap.BufferFirstAllocator = .init(&bfa_buf, gpa);
2695 const allocator = bfa.allocator();3701 const allocator = bfa.allocator();
26963702
2697 const rela_name =3703 const rela_name = try std.fmt.allocPrint(allocator, ".rela{s}", .{shndx.name(elf)});
2698 try std.fmt.allocPrint(allocator, ".rela{s}", .{elf.sectionName(sh.si)});
2699 defer allocator.free(rela_name);3704 defer allocator.free(rela_name);
27003705
2701 sh.rela_si = try elf.addSection(.none, .{3706 const rela_shndx = try elf.addSection(.none, .{
2702 .name = rela_name,3707 .name = rela_name,
2703 .type = .RELA,3708 .type = .RELA,
2704 .link = @intFromEnum(elf.si.symtab.shndx(elf)),3709 .link = @intFromEnum(Section.Index.symtab),
2705 .info = @intFromEnum(shndx),3710 .info = shndx.toSection().?,
2706 .addralign = switch (class) {3711 .addralign = switch (class) {
2707 .NONE, _ => unreachable,3712 .NONE, _ => unreachable,
2708 .@"32" => .@"4",3713 .@"32" => .@"4",
...@@ -2714,14 +3719,15 @@ pub fn ensureUnusedRelocCapacity(elf: *Elf, loc_si: Symbol.Index, len: usize) !v...@@ -2714,14 +3719,15 @@ pub fn ensureUnusedRelocCapacity(elf: *Elf, loc_si: Symbol.Index, len: usize) !v
2714 },3719 },
2715 .node_align = elf.mf.flags.block_size,3720 .node_align = elf.mf.flags.block_size,
2716 });3721 });
3722 shndx.get(elf).rela_shndx = rela_shndx;
2717 }3723 }
2718 break :rela .{ sh.rela_si, len };3724 break :rela .{ shndx.get(elf).rela_shndx, len };
2719 },3725 },
2720 .EXEC, .DYN => switch (elf.got.tlsld) {3726 .EXEC, .DYN => switch (elf.got.tlsld) {
2721 _ => return,3727 _ => return,
2722 .none => if (elf.si.dynamic != .null) {3728 .none => if (elf.shndx.dynamic != .UNDEF) {
2723 try elf.mf.updates.ensureUnusedCapacity(gpa, 1);3729 try elf.mf.updates.ensureUnusedCapacity(gpa, 1);
2724 const got_ni = elf.si.got.node(elf);3730 const got_ni = elf.shndx.got.get(elf).ni;
2725 _, const got_node_size = got_ni.location(&elf.mf).resolve(&elf.mf);3731 _, const got_node_size = got_ni.location(&elf.mf).resolve(&elf.mf);
2726 const got_size = switch (class) {3732 const got_size = switch (class) {
2727 .NONE, _ => unreachable,3733 .NONE, _ => unreachable,
...@@ -2729,43 +3735,52 @@ pub fn ensureUnusedRelocCapacity(elf: *Elf, loc_si: Symbol.Index, len: usize) !v...@@ -2729,43 +3735,52 @@ pub fn ensureUnusedRelocCapacity(elf: *Elf, loc_si: Symbol.Index, len: usize) !v
2729 };3735 };
2730 if (got_size > got_node_size)3736 if (got_size > got_node_size)
2731 try got_ni.resize(&elf.mf, gpa, got_size +| got_size / MappedFile.growth_factor);3737 try got_ni.resize(&elf.mf, gpa, got_size +| got_size / MappedFile.growth_factor);
2732 break :rela .{ elf.si.got.shndx(elf).get(elf).rela_si, 1 };3738 break :rela .{ elf.shndx.got.get(elf).rela_shndx, 1 };
2733 } else return,3739 } else return,
2734 },3740 },
2735 };3741 };
2736 const rela_ni = rela_si.node(elf);3742 const rela_ni = rela_shndx.get(elf).ni;
2737 _, const rela_node_size = rela_ni.location(&elf.mf).resolve(&elf.mf);3743 _, const rela_node_size = rela_ni.location(&elf.mf).resolve(&elf.mf);
2738 const rela_size = switch (elf.shdrPtr(rela_si.shndx(elf))) {3744 const rela_size = switch (elf.shdrPtr(rela_shndx)) {
2739 inline else => |shdr| elf.targetLoad(&shdr.size) + elf.targetLoad(&shdr.entsize) * rela_len,3745 inline else => |shdr| elf.targetLoad(&shdr.size) + elf.targetLoad(&shdr.entsize) * rela_len,
2740 };3746 };
2741 if (rela_size > rela_node_size)3747 if (rela_size > rela_node_size)
2742 try rela_ni.resize(&elf.mf, gpa, rela_size +| rela_size / MappedFile.growth_factor);3748 try rela_ni.resize(&elf.mf, gpa, rela_size +| rela_size / MappedFile.growth_factor);
2743}3749}
2744pub fn addRelocAssumeCapacity(3750fn addRelocAssumeCapacity(
2745 elf: *Elf,3751 elf: *Elf,
2746 loc_si: Symbol.Index,3752 node: MappedFile.Node.Index,
2747 offset: u64,3753 offset: u64,
2748 target_si: Symbol.Index,3754 target: Symbol.Id,
2749 addend: i64,3755 addend: i64,
2750 @"type": Reloc.Type,3756 @"type": Reloc.Type,
2751) void {3757) void {
2752 const target = target_si.get(elf);3758 assert(node != .none);
2753 const ri: Reloc.Index = @enumFromInt(elf.relocs.items.len);3759 const ri: Reloc.Index = @enumFromInt(elf.relocs.items.len);
3760 const next: Reloc.Index = next: {
3761 const target_ptr = target.index(elf).ptr(elf);
3762 const next = target_ptr.first_target_reloc;
3763 target_ptr.first_target_reloc = ri;
3764 break :next next;
3765 };
3766 if (next != .none) {
3767 next.get(elf).prev = ri;
3768 }
2754 elf.relocs.addOneAssumeCapacity().* = .{3769 elf.relocs.addOneAssumeCapacity().* = .{
2755 .type = @"type",3770 .type = @"type",
2756 .prev = .none,3771 .prev = .none,
2757 .next = target.target_relocs,3772 .next = next,
2758 .loc = loc_si,3773 .node = node,
2759 .target = target_si,3774 .target = target,
2760 .index = index: switch (elf.ehdrField(.type)) {3775 .index = index: switch (elf.ehdrField(.type)) {
2761 .NONE, .CORE, _ => unreachable,3776 .NONE, .CORE, _ => unreachable,
2762 .REL => {3777 .REL => {
2763 const sh = loc_si.shndx(elf).get(elf);3778 const sh = elf.getNodeShndx(node).get(elf);
2764 switch (elf.shdrPtr(sh.rela_si.shndx(elf))) {3779 switch (elf.shdrPtr(sh.rela_shndx)) {
2765 inline else => |shdr, class| {3780 inline else => |shdr, class| {
2766 const Rela = class.ElfN().Rela;3781 const Rela = class.ElfN().Rela;
2767 const ent_size = elf.targetLoad(&shdr.entsize);3782 const ent_size = elf.targetLoad(&shdr.entsize);
2768 const rela_slice = sh.rela_si.node(elf).slice(&elf.mf);3783 const rela_slice = sh.rela_shndx.get(elf).ni.slice(&elf.mf);
2769 const index: u32 = if (sh.rela_free.unwrap()) |index| alloc_index: {3784 const index: u32 = if (sh.rela_free.unwrap()) |index| alloc_index: {
2770 const rela: *Rela = @ptrCast(@alignCast(3785 const rela: *Rela = @ptrCast(@alignCast(
2771 rela_slice[@intCast(ent_size * index)..][0..@intCast(ent_size)],3786 rela_slice[@intCast(ent_size * index)..][0..@intCast(ent_size)],
...@@ -2781,11 +3796,15 @@ pub fn addRelocAssumeCapacity(...@@ -2781,11 +3796,15 @@ pub fn addRelocAssumeCapacity(
2781 const rela: *Rela = @ptrCast(@alignCast(3796 const rela: *Rela = @ptrCast(@alignCast(
2782 rela_slice[@intCast(ent_size * index)..][0..@intCast(ent_size)],3797 rela_slice[@intCast(ent_size * index)..][0..@intCast(ent_size)],
2783 ));3798 ));
3799 // The `offset` field here needs to equal the offset into the section, which
3800 // is *not* the same as our `offset` which is the offset into `node`. We
3801 // could calculate it now, but there's no point since `flushMovedNodeRelocs`
3802 // will eventually do that for us anyway. So for now, just set offset to 0.
2784 rela.* = .{3803 rela.* = .{
2785 .offset = @intCast(offset),3804 .offset = 0,
2786 .info = .{3805 .info = .{
2787 .type = @intCast(@"type".unwrap(elf)),3806 .type = @intCast(@"type".unwrap(elf)),
2788 .sym = @intCast(@intFromEnum(target_si)),3807 .sym = @intCast(@intFromEnum(target.index(elf))),
2789 },3808 },
2790 .addend = @intCast(addend),3809 .addend = @intCast(addend),
2791 };3810 };
...@@ -2802,25 +3821,25 @@ pub fn addRelocAssumeCapacity(...@@ -2802,25 +3821,25 @@ pub fn addRelocAssumeCapacity(
2802 else => {},3821 else => {},
2803 .TLSLD => switch (elf.got.tlsld) {3822 .TLSLD => switch (elf.got.tlsld) {
2804 _ => {},3823 _ => {},
2805 .none => if (elf.si.dynamic != .null) {3824 .none => if (elf.shndx.dynamic != .UNDEF) {
2806 const tlsld_index = elf.got.len;3825 const tlsld_index = elf.got.len;
2807 elf.got.tlsld = .wrap(tlsld_index);3826 elf.got.tlsld = .wrap(tlsld_index);
2808 elf.got.len = tlsld_index + 2;3827 elf.got.len = tlsld_index + 2;
2809 const got_addr = got_addr: switch (elf.shdrPtr(elf.si.got.shndx(elf))) {3828 const got_addr = got_addr: switch (elf.shdrPtr(elf.shndx.got)) {
2810 inline else => |shdr, class| {3829 inline else => |shdr, class| {
2811 const addr_size = @sizeOf(class.ElfN().Addr);3830 const addr_size = @sizeOf(class.ElfN().Addr);
2812 const old_size = addr_size * tlsld_index;3831 const old_size = addr_size * tlsld_index;
2813 const new_size = old_size + addr_size * 2;3832 const new_size = old_size + addr_size * 2;
2814 @memset(3833 @memset(
2815 elf.si.got.node(elf).slice(&elf.mf)[old_size..new_size],3834 elf.shndx.got.get(elf).ni.slice(&elf.mf)[old_size..new_size],
2816 0,3835 0,
2817 );3836 );
2818 break :got_addr elf.targetLoad(&shdr.addr) + old_size;3837 break :got_addr elf.targetLoad(&shdr.addr) + old_size;
2819 },3838 },
2820 };3839 };
2821 const rela_dyn_si = elf.si.got.shndx(elf).get(elf).rela_si;3840 const rela_dyn_shndx = elf.shndx.got.get(elf).rela_shndx;
2822 const rela_dyn_ni = rela_dyn_si.node(elf);3841 const rela_dyn_ni = rela_dyn_shndx.get(elf).ni;
2823 switch (elf.shdrPtr(rela_dyn_si.shndx(elf))) {3842 switch (elf.shdrPtr(rela_dyn_shndx)) {
2824 inline else => |shdr, class| {3843 inline else => |shdr, class| {
2825 const Rela = class.ElfN().Rela;3844 const Rela = class.ElfN().Rela;
2826 const old_size = elf.targetLoad(&shdr.size);3845 const old_size = elf.targetLoad(&shdr.size);
...@@ -2851,11 +3870,6 @@ pub fn addRelocAssumeCapacity(...@@ -2851,11 +3870,6 @@ pub fn addRelocAssumeCapacity(
2851 .offset = offset,3870 .offset = offset,
2852 .addend = addend,3871 .addend = addend,
2853 };3872 };
2854 switch (target.target_relocs) {
2855 .none => {},
2856 else => |target_ri| target_ri.get(elf).prev = ri,
2857 }
2858 target.target_relocs = ri;
2859}3873}
28603874
2861pub fn updateNav(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !void {3875pub fn updateNav(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !void {
...@@ -2877,30 +3891,12 @@ fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index)...@@ -2877,30 +3891,12 @@ fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index)
2877 if (!Type.fromInterned(nav.resolved.?.type).hasRuntimeBits(zcu)) return;3891 if (!Type.fromInterned(nav.resolved.?.type).hasRuntimeBits(zcu)) return;
28783892
2879 const nmi = try elf.navMapIndex(zcu, nav_index);3893 const nmi = try elf.navMapIndex(zcu, nav_index);
2880 const si = nmi.symbol(elf);3894 const ni = nmi.symbol(elf).index().ptr(elf).node;
2881 const ni = ni: {3895 elf.resetNodeRelocs(ni);
2882 const sym = si.get(elf);3896
2883 switch (sym.ni) {3897 // Ensure the NAV is marked as moved so that once we're done, `flushMoved` will eventually be
2884 .none => {3898 // called to apply the NAV's new relocations.
2885 try elf.nodes.ensureUnusedCapacity(gpa, 1);3899 try ni.moved(gpa, &elf.mf);
2886 const sec_si = elf.navSection(ip, nav.resolved.?);
2887 const ni = try elf.mf.addLastChildNode(gpa, sec_si.node(elf), .{
2888 .alignment = zcu.navAlignment(nav_index).toStdMem(),
2889 .moved = true,
2890 });
2891 elf.nodes.appendAssumeCapacity(.{ .nav = nmi });
2892 sym.ni = ni;
2893 switch (elf.symPtr(si)) {
2894 inline else => |sym_ptr, class| sym_ptr.shndx =
2895 @field(elf.symPtr(sec_si), @tagName(class)).shndx,
2896 }
2897 },
2898 else => si.deleteLocationRelocs(elf),
2899 }
2900 assert(sym.loc_relocs == .none);
2901 sym.loc_relocs = @enumFromInt(elf.relocs.items.len);
2902 break :ni sym.ni;
2903 };
29043900
2905 var nw: MappedFile.Node.Writer = undefined;3901 var nw: MappedFile.Node.Writer = undefined;
2906 ni.writer(&elf.mf, gpa, &nw);3902 ni.writer(&elf.mf, gpa, &nw);
...@@ -2911,54 +3907,14 @@ fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index)...@@ -2911,54 +3907,14 @@ fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index)
2911 zcu.navSrcLoc(nav_index),3907 zcu.navSrcLoc(nav_index),
2912 .fromInterned(nav.resolved.?.value),3908 .fromInterned(nav.resolved.?.value),
2913 &nw.interface,3909 &nw.interface,
2914 .{ .atom_index = @intFromEnum(si) },3910 .{ .atom_index = Node.toAtom(ni) },
2915 ) catch |err| switch (err) {3911 ) catch |err| switch (err) {
2916 error.WriteFailed => return error.OutOfMemory,3912 error.WriteFailed => return error.OutOfMemory,
2917 else => |e| return e,3913 else => |e| return e,
2918 };3914 };
2919 switch (elf.symPtr(si)) {3915 switch (elf.symPtr(nmi.symbol(elf).index())) {
2920 inline else => |sym| elf.targetStore(&sym.size, @intCast(nw.interface.end)),3916 inline else => |sym| elf.targetStore(&sym.size, @intCast(nw.interface.end)),
2921 }3917 }
2922 si.applyLocationRelocs(elf);
2923}
2924
2925pub fn lowerUav(
2926 elf: *Elf,
2927 pt: Zcu.PerThread,
2928 uav_val: InternPool.Index,
2929 uav_align: InternPool.Alignment,
2930 src_loc: Zcu.LazySrcLoc,
2931) !codegen.SymbolResult {
2932 const zcu = pt.zcu;
2933 const gpa = zcu.gpa;
2934
2935 try elf.pending_uavs.ensureUnusedCapacity(gpa, 1);
2936 const umi = elf.uavMapIndex(uav_val) catch |err| switch (err) {
2937 error.OutOfMemory => |e| return e,
2938 else => |e| return .{ .fail = try Zcu.ErrorMsg.create(
2939 gpa,
2940 src_loc,
2941 "linker failed to update constant: {s}",
2942 .{@errorName(e)},
2943 ) },
2944 };
2945 const si = umi.symbol(elf);
2946 if (switch (si.get(elf).ni) {
2947 .none => true,
2948 else => |ni| uav_align.toStdMem().order(ni.alignment(&elf.mf)).compare(.gt),
2949 }) {
2950 const gop = elf.pending_uavs.getOrPutAssumeCapacity(umi);
2951 if (gop.found_existing) {
2952 gop.value_ptr.alignment = gop.value_ptr.alignment.max(uav_align);
2953 } else {
2954 gop.value_ptr.* = .{
2955 .alignment = uav_align,
2956 .src_loc = src_loc,
2957 };
2958 elf.const_prog_node.increaseEstimatedTotalItems(1);
2959 }
2960 }
2961 return .{ .sym_index = @intFromEnum(si) };
2962}3918}
29633919
2964pub fn updateFunc(3920pub fn updateFunc(
...@@ -2993,42 +3949,13 @@ fn updateFuncInner(...@@ -2993,42 +3949,13 @@ fn updateFuncInner(
2993 const nav = ip.getNav(func.owner_nav);3949 const nav = ip.getNav(func.owner_nav);
29943950
2995 const nmi = try elf.navMapIndex(zcu, func.owner_nav);3951 const nmi = try elf.navMapIndex(zcu, func.owner_nav);
2996 const si = nmi.symbol(elf);3952 log.debug("updateFunc({f}) = {d}", .{ nav.fqn.fmt(ip), nmi.symbol(elf) });
2997 log.debug("updateFunc({f}) = {d}", .{ nav.fqn.fmt(ip), si });3953 const ni = nmi.symbol(elf).index().ptr(elf).node;
2998 const ni = ni: {3954 elf.resetNodeRelocs(ni);
2999 const sym = si.get(elf);3955
3000 switch (sym.ni) {3956 // Ensure the NAV is marked as moved so that once we're done, `flushMoved` will eventually be
3001 .none => {3957 // called to apply the NAV's new relocations.
3002 try elf.nodes.ensureUnusedCapacity(gpa, 1);3958 try ni.moved(gpa, &elf.mf);
3003 const sec_si = elf.navSection(ip, nav.resolved.?);
3004 const mod = zcu.navFileScope(func.owner_nav).mod.?;
3005 const target = &mod.resolved_target.result;
3006 const ni = try elf.mf.addLastChildNode(gpa, sec_si.node(elf), .{
3007 .alignment = switch (nav.resolved.?.@"align") {
3008 .none => switch (mod.optimize_mode) {
3009 .Debug,
3010 .ReleaseSafe,
3011 .ReleaseFast,
3012 => target_util.defaultFunctionAlignment(target),
3013 .ReleaseSmall => target_util.minFunctionAlignment(target),
3014 },
3015 else => |a| a.maxStrict(target_util.minFunctionAlignment(target)),
3016 }.toStdMem(),
3017 .moved = true,
3018 });
3019 elf.nodes.appendAssumeCapacity(.{ .nav = nmi });
3020 sym.ni = ni;
3021 switch (elf.symPtr(si)) {
3022 inline else => |sym_ptr, class| sym_ptr.shndx =
3023 @field(elf.symPtr(sec_si), @tagName(class)).shndx,
3024 }
3025 },
3026 else => si.deleteLocationRelocs(elf),
3027 }
3028 assert(sym.loc_relocs == .none);
3029 sym.loc_relocs = @enumFromInt(elf.relocs.items.len);
3030 break :ni sym.ni;
3031 };
30323959
3033 var nw: MappedFile.Node.Writer = undefined;3960 var nw: MappedFile.Node.Writer = undefined;
3034 ni.writer(&elf.mf, gpa, &nw);3961 ni.writer(&elf.mf, gpa, &nw);
...@@ -3038,7 +3965,7 @@ fn updateFuncInner(...@@ -3038,7 +3965,7 @@ fn updateFuncInner(
3038 pt,3965 pt,
3039 zcu.navSrcLoc(func.owner_nav),3966 zcu.navSrcLoc(func.owner_nav),
3040 func_index,3967 func_index,
3041 @intFromEnum(si),3968 Node.toAtom(ni),
3042 mir,3969 mir,
3043 &nw.interface,3970 &nw.interface,
3044 .none,3971 .none,
...@@ -3046,10 +3973,9 @@ fn updateFuncInner(...@@ -3046,10 +3973,9 @@ fn updateFuncInner(
3046 error.WriteFailed => return nw.err.?,3973 error.WriteFailed => return nw.err.?,
3047 else => |e| return e,3974 else => |e| return e,
3048 };3975 };
3049 switch (elf.symPtr(si)) {3976 switch (elf.symPtr(nmi.symbol(elf).index())) {
3050 inline else => |sym| elf.targetStore(&sym.size, @intCast(nw.interface.end)),3977 inline else => |sym| elf.targetStore(&sym.size, @intCast(nw.interface.end)),
3051 }3978 }
3052 si.applyLocationRelocs(elf);
3053}3979}
30543980
3055pub fn updateErrorData(elf: *Elf, pt: Zcu.PerThread) !void {3981pub fn updateErrorData(elf: *Elf, pt: Zcu.PerThread) !void {
...@@ -3072,7 +3998,42 @@ pub fn flush(...@@ -3072,7 +3998,42 @@ pub fn flush(
3072 const comp = elf.base.comp;3998 const comp = elf.base.comp;
3073 _ = arena;3999 _ = arena;
3074 _ = prog_node;4000 _ = prog_node;
4001
4002 if (elf.ehdrField(.type) != .REL and
4003 elf.shndx.dynamic == .UNDEF and
4004 elf.globals.strong_undef.count() > 0)
4005 {
4006 for (elf.globals.strong_undef.keys()) |name| {
4007 comp.link_diags.addError("undefined global symbol '{s}'", .{name.slice(elf)});
4008 }
4009 return error.LinkFailure;
4010 }
4011
3075 while (try elf.idle(tid)) {}4012 while (try elf.idle(tid)) {}
4013
4014 const entry_addr: u64 = entry: {
4015 const sym_name_slice: []const u8 = name: switch (elf.options.entry) {
4016 .default => switch (comp.config.output_mode) {
4017 .Exe => continue :name .enabled,
4018 .Lib, .Obj => continue :name .disabled,
4019 },
4020 .disabled => break :entry 0,
4021 .enabled => "_start",
4022 .named => |named| named,
4023 };
4024 const sym_name_strtab = elf.string(.strtab, sym_name_slice) catch |err| switch (err) {
4025 error.Canceled => |e| return e,
4026 else => |e| return comp.link_diags.fail("flush write failed: {t}", .{e}),
4027 };
4028 const global = elf.globalByName(sym_name_strtab) orelse break :entry 0;
4029 switch (elf.symPtr(global.symtab_index)) {
4030 inline else => |sym| break :entry elf.targetLoad(&sym.value),
4031 }
4032 };
4033 switch (elf.ehdrPtr()) {
4034 inline else => |ehdr| elf.targetStore(&ehdr.entry, @intCast(entry_addr)),
4035 }
4036
3076 elf.mf.flush() catch |err| switch (err) {4037 elf.mf.flush() catch |err| switch (err) {
3077 error.Canceled => |e| return e,4038 error.Canceled => |e| return e,
3078 else => |e| return comp.link_diags.fail("flush write failed: {t}", .{e}),4039 else => |e| return comp.link_diags.fail("flush write failed: {t}", .{e}),
...@@ -3082,15 +4043,10 @@ pub fn flush(...@@ -3082,15 +4043,10 @@ pub fn flush(
3082pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool {4043pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool {
3083 const comp = elf.base.comp;4044 const comp = elf.base.comp;
3084 task: {4045 task: {
3085 while (elf.pending_uavs.pop()) |pending_uav| {4046 while (elf.pending_uavs.pop()) |umi| {
3086 const sub_prog_node = elf.idleProgNode(tid, elf.const_prog_node, .{ .uav = pending_uav.key });4047 const sub_prog_node = elf.idleProgNode(tid, elf.const_prog_node, .{ .uav = umi });
3087 defer sub_prog_node.end();4048 defer sub_prog_node.end();
3088 elf.flushUav(4049 elf.flushUav(.{ .zcu = comp.zcu.?, .tid = tid }, umi) catch |err| switch (err) {
3089 .{ .zcu = comp.zcu.?, .tid = tid },
3090 pending_uav.key,
3091 pending_uav.value.alignment,
3092 pending_uav.value.src_loc,
3093 ) catch |err| switch (err) {
3094 error.OutOfMemory => |e| return e,4050 error.OutOfMemory => |e| return e,
3095 else => |e| return comp.link_diags.fail(4051 else => |e| return comp.link_diags.fail(
3096 "linker failed to lower constant: {t}",4052 "linker failed to lower constant: {t}",
...@@ -3127,9 +4083,9 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool {...@@ -3127,9 +4083,9 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool {
3127 break :task;4083 break :task;
3128 };4084 };
3129 if (elf.input_section_pending_index < elf.input_sections.items.len) {4085 if (elf.input_section_pending_index < elf.input_sections.items.len) {
3130 const isi: Node.InputSectionIndex = @enumFromInt(elf.input_section_pending_index);4086 const isi: InputSection.Index = @enumFromInt(elf.input_section_pending_index);
3131 elf.input_section_pending_index += 1;4087 elf.input_section_pending_index += 1;
3132 const sub_prog_node = elf.idleProgNode(tid, elf.input_prog_node, elf.getNode(isi.symbol(elf).node(elf)));4088 const sub_prog_node = elf.idleProgNode(tid, elf.input_prog_node, elf.getNode(isi.node(elf)));
3133 defer sub_prog_node.end();4089 defer sub_prog_node.end();
3134 elf.flushInputSection(isi) catch |err| switch (err) {4090 elf.flushInputSection(isi) catch |err| switch (err) {
3135 else => |e| {4091 else => |e| {
...@@ -3137,9 +4093,7 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool {...@@ -3137,9 +4093,7 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool {
3137 return comp.link_diags.fail(4093 return comp.link_diags.fail(
3138 "linker failed to read input section '{s}' from \"{f}{f}\": {t}",4094 "linker failed to read input section '{s}' from \"{f}{f}\": {t}",
3139 .{4095 .{
3140 elf.sectionName(4096 elf.getNode(isi.node(elf).parent(&elf.mf)).section.name(elf),
3141 elf.getNode(isi.symbol(elf).node(elf).parent(&elf.mf)).section,
3142 ),
3143 ii.path(elf).fmtEscapeString(),4097 ii.path(elf).fmtEscapeString(),
3144 fmtMemberString(ii.member(elf)),4098 fmtMemberString(ii.member(elf)),
3145 e,4099 e,
...@@ -3149,6 +4103,20 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool {...@@ -3149,6 +4103,20 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool {
3149 };4103 };
3150 break :task;4104 break :task;
3151 }4105 }
4106 if (elf.changed_symtab_index.pop()) |kv| {
4107 if (elf.ehdrField(.type) == .REL) {
4108 const sub_prog_node = elf.mf.update_prog_node.start(kv.key.slice(elf), 0);
4109 defer sub_prog_node.end();
4110 const sym = elf.globalByName(kv.key).?.symtab_index.ptr(elf);
4111 var ri = sym.first_target_reloc;
4112 while (ri != .none) {
4113 const reloc = ri.get(elf);
4114 reloc.updateTargetIndex(elf);
4115 ri = reloc.next;
4116 }
4117 break :task;
4118 }
4119 }
3152 while (elf.mf.updates.pop()) |ni| {4120 while (elf.mf.updates.pop()) |ni| {
3153 const clean_moved = ni.cleanMoved(&elf.mf);4121 const clean_moved = ni.cleanMoved(&elf.mf);
3154 const clean_resized = ni.cleanResized(&elf.mf);4122 const clean_resized = ni.cleanResized(&elf.mf);
...@@ -3161,9 +4129,10 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool {...@@ -3161,9 +4129,10 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool {
3161 } else elf.mf.update_prog_node.completeOne();4129 } else elf.mf.update_prog_node.completeOne();
3162 }4130 }
3163 }4131 }
3164 if (elf.pending_uavs.count() > 0) return true;4132 if (elf.pending_uavs.items.len > 0) return true;
3165 for (&elf.lazy.values) |lazy| if (lazy.map.count() > lazy.pending_index) return true;4133 for (&elf.lazy.values) |lazy| if (lazy.map.count() > lazy.pending_index) return true;
3166 if (elf.input_sections.items.len > elf.input_section_pending_index) return true;4134 if (elf.input_sections.items.len > elf.input_section_pending_index) return true;
4135 if (elf.changed_symtab_index.count() > 0) return true;
3167 if (elf.mf.updates.items.len > 0) return true;4136 if (elf.mf.updates.items.len > 0) return true;
3168 return false;4137 return false;
3169}4138}
...@@ -3177,13 +4146,13 @@ fn idleProgNode(...@@ -3177,13 +4146,13 @@ fn idleProgNode(
3177 var name: [std.Progress.Node.max_name_len]u8 = undefined;4146 var name: [std.Progress.Node.max_name_len]u8 = undefined;
3178 return prog_node.start(name: switch (node) {4147 return prog_node.start(name: switch (node) {
3179 else => |tag| @tagName(tag),4148 else => |tag| @tagName(tag),
3180 .section => |si| elf.sectionName(si),4149 .section => |shndx| shndx.name(elf),
3181 .input_section => |isi| {4150 .input_section => |isi| {
3182 const ii = isi.input(elf);4151 const ii = isi.input(elf);
3183 break :name std.fmt.bufPrint(&name, "{f}{f} {s}", .{4152 break :name std.fmt.bufPrint(&name, "{f}{f} {s}", .{
3184 ii.path(elf).fmtEscapeString(),4153 ii.path(elf).fmtEscapeString(),
3185 fmtMemberString(ii.member(elf)),4154 fmtMemberString(ii.member(elf)),
3186 elf.sectionName(elf.getNode(isi.symbol(elf).node(elf).parent(&elf.mf)).section),4155 elf.getNode(isi.node(elf).parent(&elf.mf)).section.name(elf),
3187 }) catch &name;4156 }) catch &name;
3188 },4157 },
3189 .nav => |nmi| {4158 .nav => |nmi| {
...@@ -3200,59 +4169,43 @@ fn flushUav(...@@ -3200,59 +4169,43 @@ fn flushUav(
3200 elf: *Elf,4169 elf: *Elf,
3201 pt: Zcu.PerThread,4170 pt: Zcu.PerThread,
3202 umi: Node.UavMapIndex,4171 umi: Node.UavMapIndex,
3203 uav_align: InternPool.Alignment,
3204 src_loc: Zcu.LazySrcLoc,
3205) !void {4172) !void {
4173 const comp = elf.base.comp;
4174 const gpa = comp.gpa;
3206 const zcu = pt.zcu;4175 const zcu = pt.zcu;
3207 const gpa = zcu.gpa;
32084176
3209 const uav_val = umi.uavValue(elf);4177 const uav_val = umi.uavValue(elf);
3210 const si = umi.symbol(elf);4178 const ni = umi.symbol(elf).index().ptr(elf).node;
3211 const ni = ni: {4179 elf.resetNodeRelocs(ni);
3212 const sym = si.get(elf);
3213 switch (sym.ni) {
3214 .none => {
3215 try elf.nodes.ensureUnusedCapacity(gpa, 1);
3216 const sec_si = elf.si.data;
3217 const ni = try elf.mf.addLastChildNode(gpa, sec_si.node(elf), .{
3218 .alignment = uav_align.toStdMem(),
3219 .moved = true,
3220 });
3221 elf.nodes.appendAssumeCapacity(.{ .uav = umi });
3222 sym.ni = ni;
3223 switch (elf.symPtr(si)) {
3224 inline else => |sym_ptr, class| sym_ptr.shndx =
3225 @field(elf.symPtr(sec_si), @tagName(class)).shndx,
3226 }
3227 },
3228 else => {
3229 if (sym.ni.alignment(&elf.mf).order(uav_align.toStdMem()).compare(.gte)) return;
3230 si.deleteLocationRelocs(elf);
3231 },
3232 }
3233 assert(sym.loc_relocs == .none);
3234 sym.loc_relocs = @enumFromInt(elf.relocs.items.len);
3235 break :ni sym.ni;
3236 };
32374180
3238 var nw: MappedFile.Node.Writer = undefined;4181 var nw: MappedFile.Node.Writer = undefined;
3239 ni.writer(&elf.mf, gpa, &nw);4182 ni.writer(&elf.mf, gpa, &nw);
3240 defer nw.deinit();4183 defer nw.deinit();
4184 // TODO: UAV lowering should never require source locations.
4185 const dummy_src_loc: Zcu.LazySrcLoc = .{
4186 .base_node_inst = try zcu.intern_pool.trackZir(gpa, comp.io, pt.tid, .{
4187 .file = zcu.module_roots.get(zcu.std_mod).?.unwrap().?,
4188 .inst = .main_struct_inst,
4189 }),
4190 .offset = .{ .byte_abs = 0 },
4191 };
3241 codegen.generateSymbol(4192 codegen.generateSymbol(
3242 &elf.base,4193 &elf.base,
3243 pt,4194 pt,
3244 src_loc,4195 dummy_src_loc,
3245 .fromInterned(uav_val),4196 .fromInterned(uav_val),
3246 &nw.interface,4197 &nw.interface,
3247 .{ .atom_index = @intFromEnum(si) },4198 .{ .atom_index = Node.toAtom(ni) },
3248 ) catch |err| switch (err) {4199 ) catch |err| switch (err) {
3249 error.WriteFailed => return error.OutOfMemory,4200 error.WriteFailed => return error.OutOfMemory,
3250 else => |e| return e,4201 else => |e| return e,
3251 };4202 };
3252 switch (elf.symPtr(si)) {4203 switch (elf.symPtr(umi.symbol(elf).index())) {
3253 inline else => |sym| elf.targetStore(&sym.size, @intCast(nw.interface.end)),4204 inline else => |sym| elf.targetStore(&sym.size, @intCast(nw.interface.end)),
3254 }4205 }
3255 si.applyLocationRelocs(elf);4206 // The UAV should already be considered to have moved, because it is created as moved and
4207 // pending calls to `flushUav` always happen before pending calls to `flushMoved`.
4208 assert(ni.hasMoved(&elf.mf));
3256}4209}
32574210
3258fn flushLazy(elf: *Elf, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void {4211fn flushLazy(elf: *Elf, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void {
...@@ -3260,33 +4213,12 @@ fn flushLazy(elf: *Elf, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void {...@@ -3260,33 +4213,12 @@ fn flushLazy(elf: *Elf, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void {
3260 const gpa = zcu.gpa;4213 const gpa = zcu.gpa;
32614214
3262 const lazy = lmr.lazySymbol(elf);4215 const lazy = lmr.lazySymbol(elf);
3263 const si = lmr.symbol(elf);4216 const ni = lmr.symbol(elf).index().ptr(elf).node;
3264 const ni = ni: {4217 elf.resetNodeRelocs(ni);
3265 const sym = si.get(elf);4218
3266 switch (sym.ni) {4219 // Ensure the lazy node is marked as moved so that once we're done, `flushMoved` will eventually
3267 .none => {4220 // be called to apply the lazy node's new relocations.
3268 try elf.nodes.ensureUnusedCapacity(gpa, 1);4221 try ni.moved(gpa, &elf.mf);
3269 const sec_si: Symbol.Index = switch (lazy.kind) {
3270 .code => .text,
3271 .const_data => .rodata,
3272 };
3273 const ni = try elf.mf.addLastChildNode(gpa, sec_si.node(elf), .{ .moved = true });
3274 elf.nodes.appendAssumeCapacity(switch (lazy.kind) {
3275 .code => .{ .lazy_code = @enumFromInt(lmr.index) },
3276 .const_data => .{ .lazy_const_data = @enumFromInt(lmr.index) },
3277 });
3278 sym.ni = ni;
3279 switch (elf.symPtr(si)) {
3280 inline else => |sym_ptr, class| sym_ptr.shndx =
3281 @field(elf.symPtr(sec_si), @tagName(class)).shndx,
3282 }
3283 },
3284 else => si.deleteLocationRelocs(elf),
3285 }
3286 assert(sym.loc_relocs == .none);
3287 sym.loc_relocs = @enumFromInt(elf.relocs.items.len);
3288 break :ni sym.ni;
3289 };
32904222
3291 var required_alignment: InternPool.Alignment = .none;4223 var required_alignment: InternPool.Alignment = .none;
3292 var nw: MappedFile.Node.Writer = undefined;4224 var nw: MappedFile.Node.Writer = undefined;
...@@ -3300,15 +4232,14 @@ fn flushLazy(elf: *Elf, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void {...@@ -3300,15 +4232,14 @@ fn flushLazy(elf: *Elf, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void {
3300 &required_alignment,4232 &required_alignment,
3301 &nw.interface,4233 &nw.interface,
3302 .none,4234 .none,
3303 .{ .atom_index = @intFromEnum(si) },4235 .{ .atom_index = Node.toAtom(ni) },
3304 );4236 );
3305 switch (elf.symPtr(si)) {4237 switch (elf.symPtr(lmr.symbol(elf).index())) {
3306 inline else => |sym| elf.targetStore(&sym.size, @intCast(nw.interface.end)),4238 inline else => |sym| elf.targetStore(&sym.size, @intCast(nw.interface.end)),
3307 }4239 }
3308 si.applyLocationRelocs(elf);
3309}4240}
33104241
3311fn flushInputSection(elf: *Elf, isi: Node.InputSectionIndex) !void {4242fn flushInputSection(elf: *Elf, isi: InputSection.Index) !void {
3312 const file_loc = isi.fileLocation(elf);4243 const file_loc = isi.fileLocation(elf);
3313 if (file_loc.size == 0) return;4244 if (file_loc.size == 0) return;
3314 const comp = elf.base.comp;4245 const comp = elf.base.comp;
...@@ -3321,12 +4252,13 @@ fn flushInputSection(elf: *Elf, isi: Node.InputSectionIndex) !void {...@@ -3321,12 +4252,13 @@ fn flushInputSection(elf: *Elf, isi: Node.InputSectionIndex) !void {
3321 var fr = file.reader(io, &.{});4252 var fr = file.reader(io, &.{});
3322 try fr.seekTo(file_loc.offset);4253 try fr.seekTo(file_loc.offset);
3323 var nw: MappedFile.Node.Writer = undefined;4254 var nw: MappedFile.Node.Writer = undefined;
3324 const si = isi.symbol(elf);4255 isi.node(elf).writer(&elf.mf, gpa, &nw);
3325 si.node(elf).writer(&elf.mf, gpa, &nw);
3326 defer nw.deinit();4256 defer nw.deinit();
3327 if (try nw.interface.sendFileAll(&fr, .limited(@intCast(file_loc.size))) != file_loc.size)4257 if (try nw.interface.sendFileAll(&fr, .limited(@intCast(file_loc.size))) != file_loc.size)
3328 return error.EndOfStream;4258 return error.EndOfStream;
3329 si.applyLocationRelocs(elf);4259 // The input section should already be considered to have moved, because it is created as moved
4260 // and pending calls to `flushInputSection` always happen before pending calls to `flushMoved`.
4261 assert(isi.node(elf).hasMoved(&elf.mf));
3330}4262}
33314263
3332fn flushFileOffset(elf: *Elf, ni: MappedFile.Node.Index) !void {4264fn flushFileOffset(elf: *Elf, ni: MappedFile.Node.Index) !void {
...@@ -3349,7 +4281,7 @@ fn flushFileOffset(elf: *Elf, ni: MappedFile.Node.Index) !void {...@@ -3349,7 +4281,7 @@ fn flushFileOffset(elf: *Elf, ni: MappedFile.Node.Index) !void {
3349 var child_it = ni.children(&elf.mf);4281 var child_it = ni.children(&elf.mf);
3350 while (child_it.next()) |child_ni| try elf.flushFileOffset(child_ni);4282 while (child_it.next()) |child_ni| try elf.flushFileOffset(child_ni);
3351 },4283 },
3352 .section => |si| switch (elf.shdrPtr(si.shndx(elf))) {4284 .section => |shndx| switch (elf.shdrPtr(shndx)) {
3353 inline else => |shdr| elf.targetStore(&shdr.offset, @intCast(4285 inline else => |shdr| elf.targetStore(&shdr.offset, @intCast(
3354 ni.fileLocation(&elf.mf, false).offset,4286 ni.fileLocation(&elf.mf, false).offset,
3355 )),4287 )),
...@@ -3378,22 +4310,21 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {...@@ -3378,22 +4310,21 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {
3378 },4310 },
3379 }4311 }
3380 },4312 },
3381 .section => |si| {4313 .section => |shndx| {
3382 try elf.flushFileOffset(ni);4314 try elf.flushFileOffset(ni);
3383 const addr = elf.computeNodeVAddr(ni);4315 const addr = elf.computeNodeVAddr(ni);
3384 const shndx = si.shndx(elf);
3385 switch (elf.shdrPtr(shndx)) {4316 switch (elf.shdrPtr(shndx)) {
3386 inline else => |shdr, class| {4317 inline else => |shdr, class| {
3387 const flags = elf.targetLoad(&shdr.flags).shf;4318 const flags = elf.targetLoad(&shdr.flags).shf;
3388 if (flags.ALLOC) {4319 if (flags.ALLOC) {
3389 if (elf.si.dynamic != .null) {4320 if (elf.shndx.dynamic != .UNDEF) {
3390 if (si == elf.si.got) {4321 if (shndx == elf.shndx.got) {
3391 const old_addr = elf.targetLoad(&shdr.addr);4322 const old_addr = elf.targetLoad(&shdr.addr);
3392 const rela_dyn_si = shndx.get(elf).rela_si;4323 const rela_dyn_shndx = shndx.get(elf).rela_shndx;
3393 const relas: []class.ElfN().Rela = @ptrCast(@alignCast(4324 const relas: []class.ElfN().Rela = @ptrCast(@alignCast(
3394 rela_dyn_si.node(elf).slice(&elf.mf)[0..@intCast(4325 rela_dyn_shndx.get(elf).ni.slice(&elf.mf)[0..@intCast(
3395 elf.targetLoad(&@field(4326 elf.targetLoad(&@field(
3396 elf.shdrPtr(rela_dyn_si.shndx(elf)),4327 elf.shdrPtr(rela_dyn_shndx),
3397 @tagName(class),4328 @tagName(class),
3398 ).size),4329 ).size),
3399 )],4330 )],
...@@ -3413,19 +4344,19 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {...@@ -3413,19 +4344,19 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {
3413 ),4344 ),
3414 },4345 },
3415 }4346 }
3416 } else if (si == elf.si.got_plt) {4347 } else if (shndx == elf.shndx.got_plt) {
3417 const target_endian = elf.targetEndian();4348 const target_endian = elf.targetEndian();
3418 const old_addr = elf.targetLoad(&shdr.addr);4349 const old_addr = elf.targetLoad(&shdr.addr);
3419 const rela_plt_si = shndx.get(elf).rela_si;4350 const rela_plt_shndx = shndx.get(elf).rela_shndx;
3420 const relas: []class.ElfN().Rela = @ptrCast(@alignCast(4351 const relas: []class.ElfN().Rela = @ptrCast(@alignCast(
3421 rela_plt_si.node(elf).slice(&elf.mf)[0..@intCast(4352 rela_plt_shndx.get(elf).ni.slice(&elf.mf)[0..@intCast(
3422 elf.targetLoad(&@field(4353 elf.targetLoad(&@field(
3423 elf.shdrPtr(rela_plt_si.shndx(elf)),4354 elf.shdrPtr(rela_plt_shndx),
3424 @tagName(class),4355 @tagName(class),
3425 ).size),4356 ).size),
3426 )],4357 )],
3427 ));4358 ));
3428 const plt_sec_slice = elf.si.plt_sec.node(elf).slice(&elf.mf);4359 const plt_sec_slice = elf.shndx.plt_sec.get(elf).ni.slice(&elf.mf);
3429 switch (elf.ehdrField(.machine)) {4360 switch (elf.ehdrField(.machine)) {
3430 else => |machine| @panic(@tagName(machine)),4361 else => |machine| @panic(@tagName(machine)),
3431 .AARCH64, .PPC64, .RISCV => {},4362 .AARCH64, .PPC64, .RISCV => {},
...@@ -3454,7 +4385,7 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {...@@ -3454,7 +4385,7 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {
3454 }4385 }
3455 },4386 },
3456 }4387 }
3457 } else if (si == elf.si.plt_sec) {4388 } else if (shndx == elf.shndx.plt_sec) {
3458 const target_endian = elf.targetEndian();4389 const target_endian = elf.targetEndian();
3459 const old_addr = elf.targetLoad(&shdr.addr);4390 const old_addr = elf.targetLoad(&shdr.addr);
3460 const plt_sec_slice = ni.slice(&elf.mf);4391 const plt_sec_slice = ni.slice(&elf.mf);
...@@ -3477,34 +4408,72 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {...@@ -3477,34 +4408,72 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {
3477 }4408 }
3478 }4409 }
3479 elf.targetStore(&shdr.addr, @intCast(addr));4410 elf.targetStore(&shdr.addr, @intCast(addr));
3480 @field(elf.symPtr(si), @tagName(class)).value = shdr.addr;4411 shndx.get(elf).lsi.index().flushMoved(elf, addr);
4412 }
4413
4414 if (shndx == elf.shndx.plt) {
4415 elf.flushMovedNodeRelocs(ni, elf.targetLoad(&shdr.addr), elf.first_plt_reloc);
4416 } else if (shndx == elf.shndx.dynamic) {
4417 elf.flushMovedNodeRelocs(ni, elf.targetLoad(&shdr.addr), elf.first_dynamic_reloc);
3481 }4418 }
3482 },4419 },
3483 }4420 }
3484 si.flushMoved(elf, addr);
3485 },4421 },
3486 .input_section => |isi| {4422 .input_section => |isi| {
3487 const old_addr = switch (elf.symPtr(isi.symbol(elf))) {4423 const old_section_addr = isi.ptr(elf).vaddr;
3488 inline else => |sym| elf.targetLoad(&sym.value),4424 const new_section_addr = elf.computeNodeVAddr(ni);
3489 };4425 isi.ptr(elf).vaddr = new_section_addr;
3490 const new_addr = elf.computeNodeVAddr(ni);4426
4427 // Update local symbols
3491 const ii = isi.input(elf);4428 const ii = isi.input(elf);
3492 var si = ii.symbol(elf);4429 var lsi, const end_lsi = ii.localSymbolRange(elf);
3493 const end_si = ii.endSymbol(elf);4430 while (lsi != end_lsi) : (lsi = @enumFromInt(@intFromEnum(lsi) + 1)) {
3494 while (cond: {4431 if (lsi.index().ptr(elf).node != ni) continue;
3495 si = si.next();4432 const old_sym_addr: u64 = switch (elf.symPtr(lsi.index())) {
3496 break :cond si != end_si;4433 inline else => |sym| switch (elf.targetLoad(&sym.other).visibility) {
3497 }) {4434 .HIDDEN, .INTERNAL => {
3498 if (si.get(elf).ni != ni) continue;4435 // This is actually a global symbol which got demoted to STB_LOCAL due
3499 si.flushMoved(elf, switch (elf.symPtr(si)) {4436 // to its visibility. It will be handled in the global symbols pass
3500 inline else => |sym| elf.targetLoad(&sym.value),4437 // below; don't touch it now.
3501 } - old_addr + new_addr);4438 continue;
4439 },
4440 .PROTECTED => unreachable, // not allowed for an STB_LOCAL symbol
4441 .DEFAULT => elf.targetLoad(&sym.value),
4442 },
4443 };
4444 lsi.index().flushMoved(elf, old_sym_addr - old_section_addr + new_section_addr);
4445 }
4446
4447 // Update global symbols
4448 if (elf.node_global_symbols.get(ni)) |first_name| {
4449 assert(first_name != .empty);
4450 var name = first_name;
4451 while (name != .empty) {
4452 const global = elf.globalByName(name).?;
4453 const old_sym_addr: u64 = switch (elf.symPtr(global.symtab_index)) {
4454 inline else => |sym| elf.targetLoad(&sym.value),
4455 };
4456 global.flushMoved(elf, old_sym_addr - old_section_addr + new_section_addr);
4457 name = global.next_in_node;
4458 }
3502 }4459 }
4460
4461 elf.flushMovedNodeRelocs(ni, new_section_addr, isi.ptrConst(elf).first_reloc);
4462 },
4463 inline .nav, .uav, .lazy_code, .lazy_const_data => |mi| {
4464 const new_addr = elf.computeNodeVAddr(ni);
4465 mi.symbol(elf).index().flushMoved(elf, new_addr);
4466 if (elf.node_global_symbols.get(ni)) |first_name| {
4467 assert(first_name != .empty);
4468 var name = first_name;
4469 while (name != .empty) {
4470 const global = elf.globalByName(name).?;
4471 global.flushMoved(elf, new_addr);
4472 name = global.next_in_node;
4473 }
4474 }
4475 elf.flushMovedNodeRelocs(ni, new_addr, mi.firstReloc(elf));
3503 },4476 },
3504 inline .nav, .uav, .lazy_code, .lazy_const_data => |mi| mi.symbol(elf).flushMoved(
3505 elf,
3506 elf.computeNodeVAddr(ni),
3507 ),
3508 }4477 }
3509 try ni.childrenMoved(elf.base.comp.gpa, &elf.mf);4478 try ni.childrenMoved(elf.base.comp.gpa, &elf.mf);
3510}4479}
...@@ -3542,7 +4511,7 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void {...@@ -3542,7 +4511,7 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void {
3542 switch (elf.targetLoad(&next_ph.type)) {4511 switch (elf.targetLoad(&next_ph.type)) {
3543 else => unreachable,4512 else => unreachable,
3544 .NULL, .LOAD => {},4513 .NULL, .LOAD => {},
3545 .DYNAMIC, .INTERP, .PHDR, .TLS => break,4514 .DYNAMIC, .INTERP, .PHDR, .TLS, std.elf.PT.GNU_RELRO => break,
3546 }4515 }
3547 const next_vaddr = elf.targetLoad(&next_ph.vaddr);4516 const next_vaddr = elf.targetLoad(&next_ph.vaddr);
3548 if (vaddr + memsz <= next_vaddr) break;4517 if (vaddr + memsz <= next_vaddr) break;
...@@ -3564,7 +4533,7 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void {...@@ -3564,7 +4533,7 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void {
3564 }4533 }
3565 },4534 },
3566 },4535 },
3567 .section => |si| switch (elf.shdrPtr(si.shndx(elf))) {4536 .section => |shndx| switch (elf.shdrPtr(shndx)) {
3568 inline else => |shdr, class| {4537 inline else => |shdr, class| {
3569 switch (elf.targetLoad(&shdr.type)) {4538 switch (elf.targetLoad(&shdr.type)) {
3570 else => unreachable,4539 else => unreachable,
...@@ -3572,10 +4541,10 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void {...@@ -3572,10 +4541,10 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void {
3572 .PROGBITS => if (size == 0) elf.targetStore(&shdr.type, .NULL),4541 .PROGBITS => if (size == 0) elf.targetStore(&shdr.type, .NULL),
3573 .SYMTAB, .DYNAMIC, .REL, .DYNSYM => return,4542 .SYMTAB, .DYNAMIC, .REL, .DYNSYM => return,
3574 .STRTAB => {4543 .STRTAB => {
3575 if (elf.si.dynamic != .null) {4544 if (elf.shndx.dynamic != .UNDEF) {
3576 if (si == elf.si.dynstr) {4545 if (shndx == elf.shndx.dynstr) {
3577 const dynamic_entries: [][2]class.ElfN().Addr = @ptrCast(@alignCast(4546 const dynamic_entries: [][2]class.ElfN().Addr = @ptrCast(@alignCast(
3578 elf.si.dynamic.node(elf).slice(&elf.mf),4547 elf.shndx.dynamic.get(elf).ni.slice(&elf.mf),
3579 ));4548 ));
3580 for (dynamic_entries) |*dynamic_entry|4549 for (dynamic_entries) |*dynamic_entry|
3581 switch (elf.targetLoad(&dynamic_entry[0])) {4550 switch (elf.targetLoad(&dynamic_entry[0])) {
...@@ -3587,19 +4556,19 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void {...@@ -3587,19 +4556,19 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void {
3587 return;4556 return;
3588 },4557 },
3589 .RELA => {4558 .RELA => {
3590 if (elf.si.dynamic != .null) {4559 if (elf.shndx.dynamic != .UNDEF) {
3591 if (si == elf.si.got.shndx(elf).get(elf).rela_si) {4560 if (shndx == elf.shndx.got.get(elf).rela_shndx) {
3592 const dynamic_entries: [][2]class.ElfN().Addr = @ptrCast(@alignCast(4561 const dynamic_entries: [][2]class.ElfN().Addr = @ptrCast(@alignCast(
3593 elf.si.dynamic.node(elf).slice(&elf.mf),4562 elf.shndx.dynamic.get(elf).ni.slice(&elf.mf),
3594 ));4563 ));
3595 for (dynamic_entries) |*dynamic_entry|4564 for (dynamic_entries) |*dynamic_entry|
3596 switch (elf.targetLoad(&dynamic_entry[0])) {4565 switch (elf.targetLoad(&dynamic_entry[0])) {
3597 else => {},4566 else => {},
3598 std.elf.DT_RELASZ => dynamic_entry[1] = shdr.size,4567 std.elf.DT_RELASZ => dynamic_entry[1] = shdr.size,
3599 };4568 };
3600 } else if (si == elf.si.got_plt.shndx(elf).get(elf).rela_si) {4569 } else if (shndx == elf.shndx.got_plt.get(elf).rela_shndx) {
3601 const dynamic_entries: [][2]class.ElfN().Addr = @ptrCast(@alignCast(4570 const dynamic_entries: [][2]class.ElfN().Addr = @ptrCast(@alignCast(
3602 elf.si.dynamic.node(elf).slice(&elf.mf),4571 elf.shndx.dynamic.get(elf).ni.slice(&elf.mf),
3603 ));4572 ));
3604 for (dynamic_entries) |*dynamic_entry|4573 for (dynamic_entries) |*dynamic_entry|
3605 switch (elf.targetLoad(&dynamic_entry[0])) {4574 switch (elf.targetLoad(&dynamic_entry[0])) {
...@@ -3611,7 +4580,9 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void {...@@ -3611,7 +4580,9 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void {
3611 return;4580 return;
3612 },4581 },
3613 }4582 }
3614 elf.targetStore(&shdr.size, @intCast(size));4583 if (shndx != elf.shndx.plt) {
4584 elf.targetStore(&shdr.size, @intCast(size));
4585 }
3615 },4586 },
3616 },4587 },
3617 .input_section, .nav, .uav, .lazy_code, .lazy_const_data => {},4588 .input_section, .nav, .uav, .lazy_code, .lazy_const_data => {},
...@@ -3642,7 +4613,6 @@ fn updateExportsInner(...@@ -3642,7 +4613,6 @@ fn updateExportsInner(
3642 export_indices: []const Zcu.Export.Index,4613 export_indices: []const Zcu.Export.Index,
3643) !void {4614) !void {
3644 const zcu = pt.zcu;4615 const zcu = pt.zcu;
3645 const gpa = zcu.gpa;
3646 const ip = &zcu.intern_pool;4616 const ip = &zcu.intern_pool;
36474617
3648 switch (exported) {4618 switch (exported) {
...@@ -3652,44 +4622,35 @@ fn updateExportsInner(...@@ -3652,44 +4622,35 @@ fn updateExportsInner(
3652 Value.fromInterned(uav).fmtValue(pt),4622 Value.fromInterned(uav).fmtValue(pt),
3653 }),4623 }),
3654 }4624 }
3655 try elf.symtab.ensureUnusedCapacity(gpa, export_indices.len);4625 try elf.ensureUnusedSymbolCapacity(@intCast(export_indices.len), .maybe_global);
3656 const exported_si: Symbol.Index, const @"type": std.elf.STT = switch (exported) {4626 const exported_lsi: Symbol.LocalIndex, const @"type": std.elf.STT = switch (exported) {
3657 .nav => |nav| .{4627 .nav => |nav| .{
3658 try elf.navSymbol(zcu, nav),4628 (try elf.navMapIndex(zcu, nav)).symbol(elf),
3659 navType(ip, ip.getNav(nav).resolved.?, elf.base.comp.config.any_non_single_threaded),4629 navType(ip, ip.getNav(nav).resolved.?, elf.base.comp.config.any_non_single_threaded),
3660 },4630 },
3661 .uav => |uav| .{ @enumFromInt(switch (try elf.lowerUav(4631 .uav => |uav| .{ (try elf.uavMapIndex(uav, .none)).symbol(elf), .OBJECT },
3662 pt,
3663 uav,
3664 Type.fromInterned(ip.typeOf(uav)).abiAlignment(zcu),
3665 export_indices[0].ptr(zcu).src,
3666 )) {
3667 .sym_index => |si| si,
3668 .fail => |em| {
3669 defer em.destroy(gpa);
3670 return elf.base.comp.link_diags.fail("{s}", .{em.msg});
3671 },
3672 }), .OBJECT },
3673 };4632 };
3674 while (try elf.idle(pt.tid)) {}4633 while (try elf.idle(pt.tid)) {}
3675 const exported_ni = exported_si.node(elf);4634 const value: u64, const size: u64, const shndx: Section.Index = switch (elf.symPtr(exported_lsi.index())) {
3676 const value, const size, const shndx = switch (elf.symPtr(exported_si)) {
3677 inline else => |exported_sym| .{4635 inline else => |exported_sym| .{
3678 elf.targetLoad(&exported_sym.value),4636 elf.targetLoad(&exported_sym.value),
3679 exported_sym.size,4637 elf.targetLoad(&exported_sym.size),
3680 exported_sym.shndx,4638 .fromSection(elf.targetLoad(&exported_sym.shndx)),
3681 },4639 },
3682 };4640 };
3683 for (export_indices) |export_index| {4641 for (export_indices) |export_index| {
3684 const @"export" = export_index.ptr(zcu);4642 const @"export" = export_index.ptr(zcu);
3685 const name = @"export".opts.name.toSlice(ip);4643 const name = @"export".opts.name.toSlice(ip);
3686 const export_si = try elf.globalSymbol(.{4644 _ = elf.addGlobalSymbolAssumeCapacity(.{
3687 .name = name,4645 .node = .none,
4646 .name = try .string(elf, name),
4647 .value = value,
4648 .size = @intCast(size),
3688 .type = @"type",4649 .type = @"type",
3689 .bind = switch (@"export".opts.linkage) {4650 .bind = switch (@"export".opts.linkage) {
3690 .internal => .LOCAL,4651 .internal => @panic("TODO internal linkage"),
3691 .strong => .GLOBAL,4652 .strong => .strong,
3692 .weak => .WEAK,4653 .weak => .weak,
3693 .link_once => return error.LinkOnceUnsupported,4654 .link_once => return error.LinkOnceUnsupported,
3694 },4655 },
3695 .visibility = switch (@"export".opts.visibility) {4656 .visibility = switch (@"export".opts.visibility) {
...@@ -3697,15 +4658,23 @@ fn updateExportsInner(...@@ -3697,15 +4658,23 @@ fn updateExportsInner(
3697 .hidden => .HIDDEN,4658 .hidden => .HIDDEN,
3698 .protected => .PROTECTED,4659 .protected => .PROTECTED,
3699 },4660 },
3700 });4661 .shndx = shndx,
3701 export_si.get(elf).ni = exported_ni;4662 }) catch |err| switch (err) {
3702 switch (elf.symPtr(export_si)) {4663 error.MultipleDefinitions => {
3703 inline else => |export_sym| {4664 // HACK: because we currently don't/can't delete these exports, we would typically
3704 export_sym.size = @intCast(size);4665 // get these errors on every non-initial incremental update. Hack around that by
3705 export_sym.shndx = shndx;4666 // only emitting this error if the symbol we're conflicting with comes from an input
4667 // section (as opposed to the ZCU).
4668 const conflicting_global = elf.globalByName(try elf.string(.strtab, name)).?;
4669 const conflicting_node = conflicting_global.symtab_index.ptr(elf).node;
4670 if (elf.getNode(conflicting_node) == .input_section) {
4671 return elf.base.comp.link_diags.fail(
4672 "multiple definitions of '{s}'",
4673 .{name},
4674 );
4675 }
3706 },4676 },
3707 }4677 };
3708 export_si.flushMoved(elf, value);
3709 }4678 }
3710}4679}
37114680
...@@ -3759,13 +4728,13 @@ pub fn printNode(...@@ -3759,13 +4728,13 @@ pub fn printNode(
3759 try w.writeByte(')');4728 try w.writeByte(')');
3760 },4729 },
3761 },4730 },
3762 .section => |si| try w.print("({s})", .{elf.sectionName(si)}),4731 .section => |shndx| try w.print("({s})", .{shndx.name(elf)}),
3763 .input_section => |isi| {4732 .input_section => |isi| {
3764 const ii = isi.input(elf);4733 const ii = isi.input(elf);
3765 try w.print("({f}{f}, {s})", .{4734 try w.print("({f}{f}, {s})", .{
3766 ii.path(elf).fmtEscapeString(),4735 ii.path(elf).fmtEscapeString(),
3767 fmtMemberString(ii.member(elf)),4736 fmtMemberString(ii.member(elf)),
3768 elf.sectionName(elf.getNode(isi.symbol(elf).node(elf).parent(&elf.mf)).section),4737 elf.getNode(isi.node(elf).parent(&elf.mf)).section.name(elf),
3769 });4738 });
3770 },4739 },
3771 .nav => |nmi| {4740 .nav => |nmi| {
src/link/MachO/ZigObject.zig+14-14
...@@ -632,7 +632,7 @@ pub fn getNavVAddr(...@@ -632,7 +632,7 @@ pub fn getNavVAddr(
632 switch (reloc_info.parent) {632 switch (reloc_info.parent) {
633 .none => unreachable,633 .none => unreachable,
634 .atom_index => |atom_index| {634 .atom_index => |atom_index| {
635 const parent_atom = self.symbols.items[atom_index].getAtom(macho_file).?;635 const parent_atom = self.symbols.items[@intFromEnum(atom_index)].getAtom(macho_file).?;
636 try parent_atom.addReloc(macho_file, .{636 try parent_atom.addReloc(macho_file, .{
637 .tag = .@"extern",637 .tag = .@"extern",
638 .offset = @intCast(reloc_info.offset),638 .offset = @intCast(reloc_info.offset),
...@@ -650,7 +650,7 @@ pub fn getNavVAddr(...@@ -650,7 +650,7 @@ pub fn getNavVAddr(
650 .debug_output => |debug_output| switch (debug_output) {650 .debug_output => |debug_output| switch (debug_output) {
651 .dwarf => |wip_nav| try wip_nav.infoExternalReloc(.{651 .dwarf => |wip_nav| try wip_nav.infoExternalReloc(.{
652 .source_off = @intCast(reloc_info.offset),652 .source_off = @intCast(reloc_info.offset),
653 .target_sym = sym_index,653 .target_sym = @enumFromInt(sym_index),
654 .target_off = reloc_info.addend,654 .target_off = reloc_info.addend,
655 }),655 }),
656 .none => unreachable,656 .none => unreachable,
...@@ -671,7 +671,7 @@ pub fn getUavVAddr(...@@ -671,7 +671,7 @@ pub fn getUavVAddr(
671 switch (reloc_info.parent) {671 switch (reloc_info.parent) {
672 .none => unreachable,672 .none => unreachable,
673 .atom_index => |atom_index| {673 .atom_index => |atom_index| {
674 const parent_atom = self.symbols.items[atom_index].getAtom(macho_file).?;674 const parent_atom = self.symbols.items[@intFromEnum(atom_index)].getAtom(macho_file).?;
675 try parent_atom.addReloc(macho_file, .{675 try parent_atom.addReloc(macho_file, .{
676 .tag = .@"extern",676 .tag = .@"extern",
677 .offset = @intCast(reloc_info.offset),677 .offset = @intCast(reloc_info.offset),
...@@ -689,7 +689,7 @@ pub fn getUavVAddr(...@@ -689,7 +689,7 @@ pub fn getUavVAddr(
689 .debug_output => |debug_output| switch (debug_output) {689 .debug_output => |debug_output| switch (debug_output) {
690 .dwarf => |wip_nav| try wip_nav.infoExternalReloc(.{690 .dwarf => |wip_nav| try wip_nav.infoExternalReloc(.{
691 .source_off = @intCast(reloc_info.offset),691 .source_off = @intCast(reloc_info.offset),
692 .target_sym = sym_index,692 .target_sym = @enumFromInt(sym_index),
693 .target_off = reloc_info.addend,693 .target_off = reloc_info.addend,
694 }),694 }),
695 .none => unreachable,695 .none => unreachable,
...@@ -717,7 +717,7 @@ pub fn lowerUav(...@@ -717,7 +717,7 @@ pub fn lowerUav(
717 const sym = self.symbols.items[metadata.symbol_index];717 const sym = self.symbols.items[metadata.symbol_index];
718 const existing_alignment = sym.getAtom(macho_file).?.alignment;718 const existing_alignment = sym.getAtom(macho_file).?.alignment;
719 if (uav_alignment.order(existing_alignment).compare(.lte))719 if (uav_alignment.order(existing_alignment).compare(.lte))
720 return .{ .sym_index = metadata.symbol_index };720 return .{ .sym_index = @enumFromInt(metadata.symbol_index) };
721 }721 }
722722
723 var name_buf: [32]u8 = undefined;723 var name_buf: [32]u8 = undefined;
...@@ -742,7 +742,7 @@ pub fn lowerUav(...@@ -742,7 +742,7 @@ pub fn lowerUav(
742 ) },742 ) },
743 };743 };
744 switch (res) {744 switch (res) {
745 .sym_index => |sym_index| try self.uavs.put(gpa, uav, .{ .symbol_index = sym_index }),745 .sym_index => |sym_index| try self.uavs.put(gpa, uav, .{ .symbol_index = @intFromEnum(sym_index) }),
746 .fail => {},746 .fail => {},
747 }747 }
748 return res;748 return res;
...@@ -790,7 +790,7 @@ pub fn updateFunc(...@@ -790,7 +790,7 @@ pub fn updateFunc(
790 var aw: std.Io.Writer.Allocating = .init(gpa);790 var aw: std.Io.Writer.Allocating = .init(gpa);
791 defer aw.deinit();791 defer aw.deinit();
792792
793 var debug_wip_nav = if (self.dwarf) |*dwarf| try dwarf.initWipNav(pt, func.owner_nav, sym_index) else null;793 var debug_wip_nav = if (self.dwarf) |*dwarf| try dwarf.initWipNav(pt, func.owner_nav, @enumFromInt(sym_index)) else null;
794 defer if (debug_wip_nav) |*wip_nav| wip_nav.deinit();794 defer if (debug_wip_nav) |*wip_nav| wip_nav.deinit();
795795
796 codegen.emitFunction(796 codegen.emitFunction(
...@@ -798,7 +798,7 @@ pub fn updateFunc(...@@ -798,7 +798,7 @@ pub fn updateFunc(
798 pt,798 pt,
799 zcu.navSrcLoc(func.owner_nav),799 zcu.navSrcLoc(func.owner_nav),
800 func_index,800 func_index,
801 sym_index,801 @enumFromInt(sym_index),
802 mir,802 mir,
803 &aw.writer,803 &aw.writer,
804 if (debug_wip_nav) |*wip_nav| .{ .dwarf = wip_nav } else .none,804 if (debug_wip_nav) |*wip_nav| .{ .dwarf = wip_nav } else .none,
...@@ -884,7 +884,7 @@ pub fn updateNav(...@@ -884,7 +884,7 @@ pub fn updateNav(
884 const sym_index = try self.getGlobalSymbol(macho_file, name, lib_name);884 const sym_index = try self.getGlobalSymbol(macho_file, name, lib_name);
885 if (nav.resolved.?.@"threadlocal" and macho_file.base.comp.config.any_non_single_threaded) self.symbols.items[sym_index].flags.tlv = true;885 if (nav.resolved.?.@"threadlocal" and macho_file.base.comp.config.any_non_single_threaded) self.symbols.items[sym_index].flags.tlv = true;
886 if (self.dwarf) |*dwarf| {886 if (self.dwarf) |*dwarf| {
887 var debug_wip_nav = try dwarf.initWipNav(pt, nav_index, sym_index);887 var debug_wip_nav = try dwarf.initWipNav(pt, nav_index, @enumFromInt(sym_index));
888 defer debug_wip_nav.deinit();888 defer debug_wip_nav.deinit();
889 dwarf.finishWipNav(pt, nav_index, &debug_wip_nav) catch |err| switch (err) {889 dwarf.finishWipNav(pt, nav_index, &debug_wip_nav) catch |err| switch (err) {
890 error.OutOfMemory, error.Overflow => |e| return e,890 error.OutOfMemory, error.Overflow => |e| return e,
...@@ -902,7 +902,7 @@ pub fn updateNav(...@@ -902,7 +902,7 @@ pub fn updateNav(
902 var aw: std.Io.Writer.Allocating = .init(zcu.gpa);902 var aw: std.Io.Writer.Allocating = .init(zcu.gpa);
903 defer aw.deinit();903 defer aw.deinit();
904904
905 var debug_wip_nav = if (self.dwarf) |*dwarf| try dwarf.initWipNav(pt, nav_index, sym_index) else null;905 var debug_wip_nav = if (self.dwarf) |*dwarf| try dwarf.initWipNav(pt, nav_index, @enumFromInt(sym_index)) else null;
906 defer if (debug_wip_nav) |*wip_nav| wip_nav.deinit();906 defer if (debug_wip_nav) |*wip_nav| wip_nav.deinit();
907907
908 codegen.generateSymbol(908 codegen.generateSymbol(
...@@ -911,7 +911,7 @@ pub fn updateNav(...@@ -911,7 +911,7 @@ pub fn updateNav(
911 zcu.navSrcLoc(nav_index),911 zcu.navSrcLoc(nav_index),
912 .fromInterned(nav.resolved.?.value),912 .fromInterned(nav.resolved.?.value),
913 &aw.writer,913 &aw.writer,
914 .{ .atom_index = sym_index },914 .{ .atom_index = @enumFromInt(sym_index) },
915 ) catch |err| switch (err) {915 ) catch |err| switch (err) {
916 error.WriteFailed => return error.OutOfMemory,916 error.WriteFailed => return error.OutOfMemory,
917 else => |e| return e,917 else => |e| return e,
...@@ -1214,7 +1214,7 @@ fn lowerConst(...@@ -1214,7 +1214,7 @@ fn lowerConst(
1214 src_loc,1214 src_loc,
1215 val,1215 val,
1216 &aw.writer,1216 &aw.writer,
1217 .{ .atom_index = sym_index },1217 .{ .atom_index = @enumFromInt(sym_index) },
1218 ) catch |err| switch (err) {1218 ) catch |err| switch (err) {
1219 error.WriteFailed => return error.OutOfMemory,1219 error.WriteFailed => return error.OutOfMemory,
1220 else => |e| return e,1220 else => |e| return e,
...@@ -1242,7 +1242,7 @@ fn lowerConst(...@@ -1242,7 +1242,7 @@ fn lowerConst(
1242 const file_offset = sect.offset + atom.value;1242 const file_offset = sect.offset + atom.value;
1243 try macho_file.pwriteAll(code, file_offset);1243 try macho_file.pwriteAll(code, file_offset);
12441244
1245 return .{ .sym_index = sym_index };1245 return .{ .sym_index = @enumFromInt(sym_index) };
1246}1246}
12471247
1248pub fn updateExports(1248pub fn updateExports(
...@@ -1377,7 +1377,7 @@ fn updateLazySymbol(...@@ -1377,7 +1377,7 @@ fn updateLazySymbol(
1377 &required_alignment,1377 &required_alignment,
1378 &aw.writer,1378 &aw.writer,
1379 .none,1379 .none,
1380 .{ .atom_index = symbol_index },1380 .{ .atom_index = @enumFromInt(symbol_index) },
1381 );1381 );
1382 const code = aw.written();1382 const code = aw.written();
13831383
src/link/MappedFile.zig+9
...@@ -305,6 +305,15 @@ pub const Node = extern struct {...@@ -305,6 +305,15 @@ pub const Node = extern struct {
305 }305 }
306 }306 }
307307
308 pub fn realign(ni: Node.Index, mf: *MappedFile, new_alignment: std.mem.Alignment) void {
309 ni.get(mf).flags.alignment = new_alignment;
310
311 const old_offset, const old_size = ni.location(mf).resolve(mf);
312 if (!new_alignment.check(@intCast(old_offset)) or !new_alignment.check(@intCast(old_size))) {
313 @panic("TODO MappedFile.realign");
314 }
315 }
316
308 pub fn writer(ni: Node.Index, mf: *MappedFile, gpa: std.mem.Allocator, w: *Writer) void {317 pub fn writer(ni: Node.Index, mf: *MappedFile, gpa: std.mem.Allocator, w: *Writer) void {
309 w.* = .{318 w.* = .{
310 .gpa = gpa,319 .gpa = gpa,