authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-05-10 11:12:27+01:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-05-17 18:55:26+01:00
log97fe49a80f1aa24ebd7101635367c31bfb563078
treeaabd917b337b3283e6c6f762c25082804016cd18
parente8ef01f2221a8588ab86863fdb109b47fd6ceb50
signaturelock-open Commit is signed but in an unrecognized format.

Elf2: rework the symtab, and fix a bunch of stuff

Sorry for the mega-commit, this diff got a little out of control. The main thing here is a complete rework of how Elf2 handles the symbol table. I messed around with the design for a while and landed on something which is fairly memory-efficient (in particular the overhead for STB_LOCAL symbols is as low as possible) and fulfils some of the more awkward constraints of the ELF format. The main such constraint is that all STB_LOCAL symbols in a symbol table are required to appear before any STB_GLOBAL/STB_WEAK symbols. This is further complicated by the fact that when producing a DSO, symbols with STV_HIDDEN or STV_INTERNAL visibility are required to have STB_LOCAL binding in the symbol table, even though they are global symbols from the perspective of the link editor. Plus, when combining multiple symbols with the same name, the resulting visibility is the strictest of all of the inputs, so it is possible at any point in compilation to discover an extern/export symbol which forces an existing STB_GLOBAL symbol to become STB_LOCAL and therefore requires it to move to an earlier symtab index. Dealing with all of this was quite awkward. But I got there! I also implemented a lot of features in the process. I don't remember everything perfectly, but here's a vague list: * Multiple definitions of and/or unresolved references to symbols are now combined correctly in all cases * `.bss` sections from inputs are correctly lowered (we don't actually emit a `.bss` section of our own yet, but I was able to put that data into the `.data` section so that the functionality is correct) * Relocations in link inputs are now always processed (previously they would be silently ignored in most cases) * Linker errors are triggered if a supported input section has a relocation which targets an unsupported input section (previously the unsupported section's symbol was dropped and associated relocations would be silently ignored) * When linking a static executable, an error is emitted if a required symbol (i.e. an undefined reference with strong linkage) was never defined * Duplicate symbol errors now work correctly * When emitting a relocatable, the offsets of relocation entries are now correct (previously the offsets written were relative to a symbol rather than a section, meaning that e.g. almost all text relocations were just in a single function) The changes in all of the other linkers and codegen backends are some added type-safety at the codegen-linker API boundary. There are now distinct `u32`-backed types for identifying an "atom" (the thing we're codegenning) and a "symbol" (the thing which a relocation targets). Linker implementations can use a couple of private helper functions to convert between this implementation-agnostic type and their specific type; for instance, `Elf2` can convert between a `Symbol.Id` and a `link.File.SymbolId` with `Symbol.Id.fromTypeErased` and `Symbol.Id.toTypeErased`. I didn't implement this nicely for any other linker, so right now there's a lot of `@enumFromInt`/`@intFromEnum` sprinkled all over the place, particularly with the legacy ELF and Mach-O linkers. I tested that I could still perform incremental updates to the Zig compiler using this commit. In terms of the new behaviors, the most interesting stuff is symbol and relocation resolution, so I ran a few tests involving building a "Hello World" binary in various different ways: * `build-exe` correctly succeeds * `build-exe -fno-compiler-rt` correctly reports undefined symbols * `build-obj` linked with `build-exe` correctly succeeds * `build-obj` linked with `build-exe -fno-compiler-rt` correctly reports undefined symbols * `build-obj -fcompiler-rt` linked with `build-exe -fno-compiler-rt` correctly succeeds * `build-obj -fcompiler-rt` linked with `build-exe` correctly succeeds (the compiler-rt symbols are weak so the global symbols are arbitrarily resolved to one of the two implementations) I also manually verified with `readelf` that symbol tables were always ordered correctly (before this PR, `readelf -s` would usually emit warnings about incorrectly-ordered symtabs!), and verified that various visibility attributes worked as expected. No actual test coverage is added due to the current lack of a useful linker test harness. Once a good test harness is available I will be willing to write some tests.

17 files changed, 2404 insertions(+), 1468 deletions(-)

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+2112-1191
...@@ -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 }
109
110 pub fn fileLocation(isi: InputSectionIndex, elf: *const Elf) MappedFile.Node.FileLocation {
111 return elf.input_sections.items[@intFromEnum(isi)].file_location;
112 }139 }
113140
114 pub fn symbol(isi: InputSectionIndex, elf: *const Elf) Symbol.Index {141 pub fn localSymbolRange(ii: InputIndex, elf: *Elf) [2]Symbol.LocalIndex {
115 return elf.input_sections.items[@intFromEnum(isi)].si;142 if (@intFromEnum(ii) + 1 < elf.inputs.items.len) {
143 const next_ii: InputIndex = @enumFromInt(@intFromEnum(ii) + 1);
144 return .{ ii.fileSymbol(elf), next_ii.fileSymbol(elf) };
145 } else {
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);
268415
269 pub fn fromSection(sec: std.elf.Section) Shndx {416 try elf.node_global_symbols.ensureUnusedCapacity(gpa, len);
270 return switch (sec) {417
271 std.elf.SHN_UNDEF...std.elf.SHN_LORESERVE - 1 => @enumFromInt(sec),418 if (elf.shndx.dynsym != .UNDEF) {
272 std.elf.SHN_LORESERVE...std.elf.SHN_HIRESERVE => @enumFromInt(reserve(sec)),419 // Ensure the `.dynsym` section's node is big enough
420 const dynsym_need_size: u64 = switch (elf.shdrPtr(elf.shndx.dynsym)) {
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;
760 },
761 }
762 },
763 .prev_in_node = .empty,
764 .next_in_node = old_head,
765 };
766
767 if (old_head != .empty) {
768 const old_head_ptr = elf.globalByName(old_head).?;
769 assert(old_head_ptr.symtab_index.ptr(elf).node == opts.node);
770 assert(old_head_ptr.prev_in_node == .empty);
771 old_head_ptr.prev_in_node = opts.name.strtab;
772 }
773
774 if (force_local_bind) {
775 elf.moveDemotedGlobal(new_global_ptr);
776 }
777
778 if (new_global_ptr.dynsym_index != 0 and
779 opts.visibility == .DEFAULT and
780 opts.shndx == .UNDEF and
781 opts.type == .FUNC)
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;
822 }
823 }
824 } else {
825 assert(global_ptr.next_in_node == .empty);
826 assert(global_ptr.prev_in_node == .empty);
827 }
828
829 global_ptr.symtab_index.ptr(elf).node = new.node;
830
831 const old_head: String(.strtab) = old_head: {
832 if (new.node == .none) break :old_head .empty;
833 const gop = elf.node_global_symbols.getOrPutAssumeCapacity(new.node);
834 const old_head: String(.strtab) = if (gop.found_existing) gop.value_ptr.* else .empty;
835 gop.value_ptr.* = global_name;
836 break :old_head old_head;
837 };
838
839 global_ptr.prev_in_node = .empty;
840 global_ptr.next_in_node = old_head;
841
842 if (old_head != .empty) {
843 const old_head_ptr = elf.globalByName(old_head).?;
844 assert(old_head_ptr.symtab_index.ptr(elf).node == new.node);
845 assert(old_head_ptr.prev_in_node == .empty);
846 old_head_ptr.prev_in_node = global_name;
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,
339 },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);
340 }931 }
341 switch (elf.shdrPtr(elf.si.symtab.shndx(elf))) {932 },
342 inline else => |shdr| elf.targetStore(&shdr.info, @max(933 }
343 elf.targetLoad(&shdr.info),934 if (demote_to_local) {
344 @intFromEnum(si) + 1,935 // When demoting a global to STB_LOCAL, we need to move its symtab index so that it is with
345 )),936 // the STB_LOCAL symbols instead of the global symbols.
937 elf.moveDemotedGlobal(global_ptr);
938 }
939}
940/// If a symbol which was STB_GLOBAL/STB_WEAK becomes STB_LOCAL (see `mergeGlobalSymbolVisibility`),
941/// the symbol must be moved from the "globals" part of the symtab to the "locals" part, because ELF
942/// requires that all STB_LOCAL symbols in a symbol table appear before any global symbols.
943fn moveDemotedGlobal(elf: *Elf, global_ptr: *Symbol.Global) void {
944 assert(elf.ehdrField(.type) != .REL); // demotion only happens when emitting an ELF module
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;
346 }961 }
347962
348 if (opts.bind == .LOCAL) return;963 const src_sym_ptr = @field(elf.symPtr(src_index), @tagName(class));
349 no_entry: {964 const dest_sym_ptr = @field(elf.symPtr(dest_index), @tagName(class));
350 if (std.mem.eql(u8, opts.name, entry: switch (elf.options.entry) {965
351 .default => switch (comp.config.output_mode) {966 const this_name: String(.strtab) = @enumFromInt(elf.targetLoad(&src_sym_ptr.name));
352 .Exe => continue :entry .enabled,967 assert(elf.globalByName(this_name).? == global_ptr);
353 .Lib, .Obj => continue :entry .disabled,968 if (global_ptr.symtab_index.ptr(elf).first_target_reloc != .none) {
969 // This symbol's index is changing, so queue an update of relocs targeting it.
970 elf.changed_symtab_index.putAssumeCapacity(this_name, {});
971 }
972
973 const other_name: String(.strtab) = @enumFromInt(elf.targetLoad(&dest_sym_ptr.name));
974 const other_global_ptr = elf.globalByName(other_name).?;
975 assert(other_global_ptr.symtab_index == dest_index);
976 if (other_global_ptr.symtab_index.ptr(elf).first_target_reloc != .none) {
977 // This other symbol's index is changing, so queue an update of relocs targeting it.
978 elf.changed_symtab_index.putAssumeCapacity(other_name, {});
979 }
980
981 // First swap the symtab entries...
982 std.mem.swap(class.ElfN().Sym, src_sym_ptr, dest_sym_ptr);
983 // ...then the `elf.symtab` metadata...
984 std.mem.swap(Symbol, src_index.ptr(elf), dest_index.ptr(elf));
985 // ...then update the `elf.globals` tracking.
986 global_ptr.symtab_index = dest_index;
987 other_global_ptr.symtab_index = src_index;
988
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,
354 },1004 },
355 .disabled => break :no_entry,1005 // SHN_UNDEF is important: we mustn't define this symbol for other DSOs.
356 .enabled => "_start",1006 .shndx = std.elf.SHN_UNDEF,
357 .named => |named| named,1007 .other = .{ .visibility = .DEFAULT },
358 })) {1008 };
359 elf.si.entry = si;1009 if (elf.targetEndian() != native_endian) {
360 switch (elf.ehdrPtr()) {1010 std.mem.byteSwapAllFields(class.ElfN().Sym, dynsym);
361 inline else => |ehdr| elf.targetStore(&ehdr.entry, @intCast(opts.value)),
362 }
363 }1011 }
364 }1012 }
3651013 },
366 if (elf.si.dynsym == .null) return;1014 }
367 const dsi = elf.dynsym.count();1015}
368 try elf.dynsym.putNoClobber(gpa, si, {});1016fn addPltEntry(elf: *Elf, global_name: String(.strtab), dynsym_index: u32) void {
369 const name_dynstr_entry = try elf.string(.dynstr, opts.name);1017 const target_endian = elf.targetEndian();
370 switch (elf.shdrPtr(elf.si.dynsym.shndx(elf))) {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)) {
371 inline else => |shdr| {1025 inline else => |shdr| {
372 const old_size = elf.targetLoad(&shdr.size);1026 const old_size = 16 * (1 + plt_index);
373 const ent_size = elf.targetLoad(&shdr.entsize);1027 assert(elf.targetLoad(&shdr.size) == old_size);
374 const new_size = ent_size * elf.dynsym.count();1028 elf.targetStore(&shdr.size, old_size + 16);
375 if (new_size > old_size) {1029 const plt_slice = plt_ni.slice(&elf.mf)[old_size..][0..16];
376 elf.targetStore(&shdr.size, @intCast(new_size));1030 @memcpy(plt_slice, &[16]u8{
377 const dynsym_ni = elf.si.dynsym.node(elf);1031 0xf3, 0x0f, 0x1e, 0xfa, // endbr64
378 _, const node_size = dynsym_ni.location(&elf.mf).resolve(&elf.mf);1032 0x68, 0x00, 0x00, 0x00, 0x00, // push $0x0
379 if (new_size > node_size) try dynsym_ni.resize(1033 0xe9, 0x00, 0x00, 0x00, 0x00, // jmp 0
380 &elf.mf,1034 0x66, 0x90, // xchg %ax,%ax
381 gpa,1035 });
382 new_size +| new_size / MappedFile.growth_factor,1036 std.mem.writeInt(u32, plt_slice[5..][0..4], plt_index, target_endian);
383 );1037 std.mem.writeInt(
384 }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;
385 },1044 },
386 }1045 };
387 switch (elf.dynsymSlice()) {1046
388 inline else => |dynsyms, class| {1047 const got_plt_shndx = elf.shndx.got_plt;
389 const Sym = class.ElfN().Sym;1048 const got_plt_ni = elf.shndx.got_plt.get(elf).ni;
390 const dynsym = &dynsyms[dsi];1049 const got_plt_addr = got_plt_addr: switch (elf.shdrPtr(got_plt_shndx)) {
391 dynsym.* = .{1050 inline else => |shdr, class| {
392 .name = name_dynstr_entry,1051 const ent_size = @sizeOf(class.ElfN().Addr);
393 .value = @intCast(opts.value),1052 const old_size = ent_size * (3 + plt_index);
394 .size = @intCast(opts.size),1053 elf.targetStore(&shdr.size, old_size + ent_size);
395 .info = .{ .type = opts.type, .bind = opts.bind },1054 std.mem.writeInt(
396 .other = .{ .visibility = opts.visibility },1055 class.ElfN().Addr,
397 .shndx = opts.shndx.toSection().?,1056 got_plt_ni.slice(&elf.mf)[old_size..][0..ent_size],
398 };1057 @intCast(plt_addr),
399 if (target_endian != native_endian) std.mem.byteSwapAllFields(Sym, dynsym);1058 target_endian,
1059 );
1060 break :got_plt_addr elf.targetLoad(&shdr.addr) + old_size;
1061 },
1062 };
1063
1064 const plt_sec_ni = elf.shndx.plt_sec.get(elf).ni;
1065 switch (elf.shdrPtr(elf.shndx.plt_sec)) {
1066 inline else => |shdr| {
1067 const old_size = 16 * plt_index;
1068 elf.targetStore(&shdr.size, old_size + 16);
1069 const plt_sec_slice = plt_sec_ni.slice(&elf.mf)[old_size..][0..16];
1070 @memcpy(plt_sec_slice, &[16]u8{
1071 0xf3, 0x0f, 0x1e, 0xfa, // endbr64
1072 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *0x0(%rip)
1073 0x66, 0x0f, 0x1f, 0x44, 0x00, 0x00, // nopw 0x0(%rax,%rax,1)
1074 });
1075 std.mem.writeInt(
1076 i32,
1077 plt_sec_slice[6..][0..4],
1078 @intCast(@as(i64, @bitCast(
1079 got_plt_addr -% (elf.targetLoad(&shdr.addr) + old_size + 10),
1080 ))),
1081 target_endian,
1082 );
400 },1083 },
401 }1084 }
4021085
403 if (opts.type != .FUNC or opts.shndx != .UNDEF) return;1086 const rela_plt_shndx = got_plt_shndx.get(elf).rela_shndx;
404 const plt_index: u32 = @intCast(elf.got.plt.count());1087 const rela_plt_ni = rela_plt_shndx.get(elf).ni;
405 try elf.got.plt.putNoClobber(gpa, si, {});1088 switch (elf.shdrPtr(rela_plt_shndx)) {
406 switch (elf.ehdrField(.machine)) {1089 inline else => |shdr, class| {
407 else => |machine| @panic(@tagName(machine)),1090 const Rela = class.ElfN().Rela;
408 .X86_64 => {1091 const rela_size = elf.targetLoad(&shdr.entsize);
409 const plt_ni = elf.si.plt.node(elf);1092 const old_size = rela_size * plt_index;
410 _, const plt_node_size = plt_ni.location(&elf.mf).resolve(&elf.mf);1093 const new_size = old_size + rela_size;
411 const plt_addr = plt_addr: switch (elf.shdrPtr(elf.si.plt.shndx(elf))) {1094 elf.targetStore(&shdr.size, new_size);
412 inline else => |shdr| {1095 const rela: *Rela = @ptrCast(@alignCast(
413 const old_size = 16 * (1 + plt_index);1096 rela_plt_ni.slice(&elf.mf)[@intCast(old_size)..@intCast(new_size)],
414 const new_size = old_size + 16;1097 ));
415 elf.targetStore(&shdr.size, new_size);1098 rela.* = .{
416 if (new_size > plt_node_size) try plt_ni.resize(1099 .offset = @intCast(got_plt_addr),
417 &elf.mf,1100 .info = .{
418 gpa,1101 .type = @intFromEnum(std.elf.R_X86_64.JUMP_SLOT),
419 new_size +| new_size / MappedFile.growth_factor,1102 .sym = @intCast(dynsym_index),
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 };
438
439 const got_plt_shndx = elf.si.got_plt.shndx(elf);
440 const got_plt_ni = elf.si.got_plt.node(elf);
441 _, const got_plt_node_size = got_plt_ni.location(&elf.mf).resolve(&elf.mf);
442 const got_plt_addr = got_plt_addr: switch (elf.shdrPtr(got_plt_shndx)) {
443 inline else => |shdr, class| {
444 const Addr = class.ElfN().Addr;
445 const addr_size = @sizeOf(Addr);
446 const old_size = addr_size * (3 + plt_index);
447 const new_size = old_size + addr_size;
448 elf.targetStore(&shdr.size, new_size);
449 if (new_size > got_plt_node_size) try got_plt_ni.resize(
450 &elf.mf,
451 gpa,
452 new_size +| new_size / MappedFile.growth_factor,
453 );
454 std.mem.writeInt(
455 Addr,
456 got_plt_ni.slice(&elf.mf)[old_size..][0..addr_size],
457 @intCast(plt_addr),
458 target_endian,
459 );
460 break :got_plt_addr elf.targetLoad(&shdr.addr) + old_size;
461 },1103 },
1104 .addend = 0,
462 };1105 };
4631106 if (target_endian != native_endian) std.mem.byteSwapAllFields(Rela, rela);
464 const plt_sec_ni = elf.si.plt_sec.node(elf);
465 _, const plt_sec_node_size = plt_sec_ni.location(&elf.mf).resolve(&elf.mf);
466 switch (elf.shdrPtr(elf.si.plt_sec.shndx(elf))) {
467 inline else => |shdr| {
468 const old_size = 16 * plt_index;
469 const new_size = old_size + 16;
470 elf.targetStore(&shdr.size, new_size);
471 if (new_size > plt_sec_node_size) try plt_sec_ni.resize(
472 &elf.mf,
473 gpa,
474 new_size +| new_size / MappedFile.growth_factor,
475 );
476 const plt_sec_slice = plt_sec_ni.slice(&elf.mf)[old_size..new_size];
477 @memcpy(plt_sec_slice, &[16]u8{
478 0xf3, 0x0f, 0x1e, 0xfa, // endbr64
479 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *0x0(%rip)
480 0x66, 0x0f, 0x1f, 0x44, 0x00, 0x00, // nopw 0x0(%rax,%rax,1)
481 });
482 std.mem.writeInt(
483 i32,
484 plt_sec_slice[6..][0..4],
485 @intCast(@as(i64, @bitCast(
486 got_plt_addr -% (elf.targetLoad(&shdr.addr) + old_size + 10),
487 ))),
488 target_endian,
489 );
490 },
491 }
492
493 const rela_plt_si = got_plt_shndx.get(elf).rela_si;
494 const rela_plt_ni = rela_plt_si.node(elf);
495 _, const rela_plt_node_size = rela_plt_ni.location(&elf.mf).resolve(&elf.mf);
496 switch (elf.shdrPtr(rela_plt_si.shndx(elf))) {
497 inline else => |shdr, class| {
498 const Rela = class.ElfN().Rela;
499 const rela_size = elf.targetLoad(&shdr.entsize);
500 const old_size = rela_size * plt_index;
501 const new_size = old_size + rela_size;
502 elf.targetStore(&shdr.size, new_size);
503 if (new_size > rela_plt_node_size) try rela_plt_ni.resize(
504 &elf.mf,
505 gpa,
506 new_size +| new_size / MappedFile.growth_factor,
507 );
508 const rela: *Rela = @ptrCast(@alignCast(
509 rela_plt_ni.slice(&elf.mf)[@intCast(old_size)..@intCast(new_size)],
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 },
521 }
522 try rela_plt_ni.resized(gpa, &elf.mf);
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 };
1179
1180 /// A `LocalIndex` is a raw index into the symtab like `Index`, but it guarantees that the
1181 /// symbol in question has STB_LOCAL binding, which guarantees that its symtab index is stable
1182 /// so can be stored long-term without needing to be updated
1183 ///
1184 /// This is because symbols which have STB_LOCAL binding in the output file gain fixed symtab
1185 /// indices, thanks to a combination of a few factors:
1186 /// * We never remove STB_LOCAL symbols
1187 /// * There is no symbol ordering requirement *within* the leading range of STB_LOCAL symbols
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));
1196 }
1197 };
5511198
552 pub fn applyTargetRelocs(si: Symbol.Index, elf: *Elf) void {1199 /// Opaque, stable identifier for a symbol. Does not necessarily equal the index into the symtab.
553 if (elf.ehdrField(.type) == .REL) return;1200 const Id = packed struct(u32) {
554 var ri = si.get(elf).target_relocs;1201 kind: enum(u1) { local, global },
555 while (ri != .none) {1202 raw: u31,
556 const reloc = ri.get(elf);1203
557 assert(reloc.target == si);1204 const @"null": Symbol.Id = .local(.null);
558 reloc.apply(elf);1205
559 ri = reloc.next;1206 fn local(lsi: Symbol.LocalIndex) Symbol.Id {
560 }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 };
561 }1220 }
5621221
563 pub fn deleteLocationRelocs(si: Symbol.Index, elf: *Elf) void {1222 fn toTypeErased(s: Symbol.Id) link.File.SymbolId {
564 const sym = si.get(elf);1223 return @enumFromInt(@as(u32, @bitCast(s)));
565 for (elf.relocs.items[@intFromEnum(sym.loc_relocs)..]) |*reloc| {1224 }
566 if (reloc.loc != si) break;1225 fn fromTypeErased(s: link.File.SymbolId) Symbol.Id {
567 reloc.delete(elf);1226 return @bitCast(@intFromEnum(s));
568 }1227 }
569 sym.loc_relocs = .none;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
...@@ -1135,7 +2052,6 @@ fn initHeaders(...@@ -1135,7 +2052,6 @@ fn initHeaders(
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) {
...@@ -1365,7 +2281,7 @@ fn initHeaders(...@@ -1365,7 +2281,7 @@ fn initHeaders(
13652281
1366 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)));
1367 sh_undef.* = .{2283 sh_undef.* = .{
1368 .name = try elf.string(.shstrtab, ""),2284 .name = @intFromEnum(String(.shstrtab).empty),
1369 .type = .NULL,2285 .type = .NULL,
1370 .flags = .{ .shf = .{} },2286 .flags = .{ .shf = .{} },
1371 .addr = 0,2287 .addr = 0,
...@@ -1377,24 +2293,23 @@ fn initHeaders(...@@ -1377,24 +2293,23 @@ fn initHeaders(
1377 .entsize = 0,2293 .entsize = 0,
1378 };2294 };
1379 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);
1380 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 });
13812297
1382 elf.symtab.addOneAssumeCapacity().* = .{2298 elf.symtab.addOneAssumeCapacity().* = .{
1383 .ni = .none,2299 .node = .none,
1384 .loc_relocs = .none,2300 .first_target_reloc = .none,
1385 .target_relocs = .none,
1386 .unused = 0,
1387 };2301 };
1388 assert(elf.si.symtab == try elf.addSection(elf.ni.file, .{2302 assert(.symtab == try elf.addSection(elf.ni.file, .{
1389 .type = .SYMTAB,2303 .type = .SYMTAB,
1390 .size = @sizeOf(ElfN.Sym) * 1,2304 .size = @sizeOf(ElfN.Sym) * 1,
1391 .addralign = addr_align,2305 .addralign = addr_align,
1392 .entsize = @sizeOf(ElfN.Sym),2306 .entsize = @sizeOf(ElfN.Sym),
1393 .node_align = elf.mf.flags.block_size,2307 .node_align = elf.mf.flags.block_size,
2308 .info = 1, // index of first non-local symbol
1394 }));2309 }));
1395 const symtab_null = @field(elf.symPtr(.null), @tagName(ct_class));2310 const symtab_null = @field(elf.symPtr(.null), @tagName(ct_class));
1396 symtab_null.* = .{2311 symtab_null.* = .{
1397 .name = try elf.string(.strtab, ""),2312 .name = @intFromEnum(String(.strtab).empty),
1398 .value = 0,2313 .value = 0,
1399 .size = 0,2314 .size = 0,
1400 .info = .{ .type = .NOTYPE, .bind = .LOCAL },2315 .info = .{ .type = .NOTYPE, .bind = .LOCAL },
...@@ -1407,55 +2322,56 @@ fn initHeaders(...@@ -1407,55 +2322,56 @@ fn initHeaders(
1407 ehdr.shstrndx = ehdr.shnum;2322 ehdr.shstrndx = ehdr.shnum;
1408 },2323 },
1409 }2324 }
1410 assert(elf.si.shstrtab == try elf.addSection(elf.ni.file, .{2325 assert(.shstrtab == try elf.addSection(elf.ni.file, .{
1411 .type = .STRTAB,2326 .type = .STRTAB,
1412 .size = 1,2327 .size = 1,
1413 .entsize = 1,2328 .entsize = 1,
1414 .node_align = elf.mf.flags.block_size,2329 .node_align = elf.mf.flags.block_size,
1415 }));2330 }));
1416 try elf.renameSection(.symtab, ".symtab");2331 Section.Index.get(.shstrtab, elf).ni.slice(&elf.mf)[0] = 0;
1417 try elf.renameSection(.shstrtab, ".shstrtab");2332
1418 elf.si.shstrtab.node(elf).slice(&elf.mf)[0] = 0;2333 try Section.Index.symtab.rename(elf, ".symtab");
2334 try Section.Index.shstrtab.rename(elf, ".shstrtab");
14192335
1420 assert(elf.si.strtab == try elf.addSection(elf.ni.file, .{2336 assert(.strtab == try elf.addSection(elf.ni.file, .{
1421 .name = ".strtab",2337 .name = ".strtab",
1422 .type = .STRTAB,2338 .type = .STRTAB,
1423 .size = 1,2339 .size = 1,
1424 .entsize = 1,2340 .entsize = 1,
1425 .node_align = elf.mf.flags.block_size,2341 .node_align = elf.mf.flags.block_size,
1426 }));2342 }));
1427 switch (elf.shdrPtr(elf.si.symtab.shndx(elf))) {2343 Section.Index.get(.strtab, elf).ni.slice(&elf.mf)[0] = 0;
1428 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)),
1429 }2346 }
1430 elf.si.strtab.node(elf).slice(&elf.mf)[0] = 0;
14312347
1432 assert(elf.si.rodata == try elf.addSection(elf.ni.rodata, .{2348 assert(.rodata == try elf.addSection(elf.ni.rodata, .{
1433 .name = ".rodata",2349 .name = ".rodata",
1434 .flags = .{ .ALLOC = true },2350 .flags = .{ .ALLOC = true },
1435 .addralign = elf.mf.flags.block_size,2351 .addralign = elf.mf.flags.block_size,
1436 }));2352 }));
1437 assert(elf.si.text == try elf.addSection(elf.ni.text, .{2353 assert(.text == try elf.addSection(elf.ni.text, .{
1438 .name = ".text",2354 .name = ".text",
1439 .flags = .{ .ALLOC = true, .EXECINSTR = true },2355 .flags = .{ .ALLOC = true, .EXECINSTR = true },
1440 .addralign = elf.mf.flags.block_size,2356 .addralign = elf.mf.flags.block_size,
1441 }));2357 }));
1442 assert(elf.si.data == try elf.addSection(elf.ni.data, .{2358 assert(.data == try elf.addSection(elf.ni.data, .{
1443 .name = ".data",2359 .name = ".data",
1444 .flags = .{ .WRITE = true, .ALLOC = true },2360 .flags = .{ .WRITE = true, .ALLOC = true },
1445 .addralign = elf.mf.flags.block_size,2361 .addralign = elf.mf.flags.block_size,
1446 }));2362 }));
1447 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, .{
1448 .name = ".data.rel.ro",2364 .name = ".data.rel.ro",
1449 .flags = .{ .WRITE = true, .ALLOC = true },2365 .flags = .{ .WRITE = true, .ALLOC = true },
1450 .addralign = elf.mf.flags.block_size,2366 .addralign = elf.mf.flags.block_size,
1451 }));2367 }));
1452 if (@"type" != .REL) {2368 if (@"type" != .REL) {
1453 assert(elf.si.got == try elf.addSection(elf.ni.data_rel_ro, .{2369 elf.shndx.got = try elf.addSection(elf.ni.data_rel_ro, .{
1454 .name = ".got",2370 .name = ".got",
1455 .flags = .{ .WRITE = true, .ALLOC = true },2371 .flags = .{ .WRITE = true, .ALLOC = true },
1456 .addralign = addr_align,2372 .addralign = addr_align,
1457 }));2373 });
1458 assert(elf.si.got_plt == try elf.addSection(2374 elf.shndx.got_plt = try elf.addSection(
1459 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,
1460 .{2376 .{
1461 .name = ".got.plt",2377 .name = ".got.plt",
...@@ -1468,26 +2384,26 @@ fn initHeaders(...@@ -1468,26 +2384,26 @@ fn initHeaders(
1468 },2384 },
1469 .addralign = addr_align,2385 .addralign = addr_align,
1470 },2386 },
1471 ));2387 );
1472 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 =
1473 switch (machine) {2389 switch (machine) {
1474 else => @panic(@tagName(machine)),2390 else => @panic(@tagName(machine)),
1475 .X86_64 => .{ 16, .@"16", true },2391 .X86_64 => .{ 16, .@"16", true },
1476 };2392 };
1477 assert(elf.si.plt == try elf.addSection(elf.ni.text, .{2393 elf.shndx.plt = try elf.addSection(elf.ni.text, .{
1478 .name = ".plt",2394 .name = ".plt",
1479 .type = .PROGBITS,2395 .type = .PROGBITS,
1480 .flags = .{ .ALLOC = true, .EXECINSTR = true },2396 .flags = .{ .ALLOC = true, .EXECINSTR = true },
1481 .size = plt_size,2397 .size = plt_size,
1482 .addralign = plt_align,2398 .addralign = plt_align,
1483 .node_align = elf.mf.flags.block_size,2399 .node_align = elf.mf.flags.block_size,
1484 }));2400 });
1485 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, .{
1486 .name = ".plt.sec",2402 .name = ".plt.sec",
1487 .flags = .{ .ALLOC = true, .EXECINSTR = true },2403 .flags = .{ .ALLOC = true, .EXECINSTR = true },
1488 .addralign = plt_align,2404 .addralign = plt_align,
1489 .node_align = elf.mf.flags.block_size,2405 .node_align = elf.mf.flags.block_size,
1490 }));2406 });
1491 if (maybe_interp) |interp| {2407 if (maybe_interp) |interp| {
1492 const interp_ni = try elf.mf.addLastChildNode(gpa, elf.ni.rodata, .{2408 const interp_ni = try elf.mf.addLastChildNode(gpa, elf.ni.rodata, .{
1493 .size = interp.len + 1,2409 .size = interp.len + 1,
...@@ -1498,13 +2414,13 @@ fn initHeaders(...@@ -1498,13 +2414,13 @@ fn initHeaders(
1498 elf.nodes.appendAssumeCapacity(.{ .segment = interp_phndx });2414 elf.nodes.appendAssumeCapacity(.{ .segment = interp_phndx });
1499 elf.phdrs.items[interp_phndx] = interp_ni;2415 elf.phdrs.items[interp_phndx] = interp_ni;
15002416
1501 const sec_interp_si = try elf.addSection(interp_ni, .{2417 const sec_interp_shndx = try elf.addSection(interp_ni, .{
1502 .name = ".interp",2418 .name = ".interp",
1503 .type = .PROGBITS,2419 .type = .PROGBITS,
1504 .flags = .{ .ALLOC = true },2420 .flags = .{ .ALLOC = true },
1505 .size = @intCast(interp.len + 1),2421 .size = @intCast(interp.len + 1),
1506 });2422 });
1507 const sec_interp = sec_interp_si.node(elf).slice(&elf.mf);2423 const sec_interp = sec_interp_shndx.get(elf).ni.slice(&elf.mf);
1508 @memcpy(sec_interp[0..interp.len], interp);2424 @memcpy(sec_interp[0..interp.len], interp);
1509 sec_interp[interp.len] = 0;2425 sec_interp[interp.len] = 0;
1510 }2426 }
...@@ -1517,7 +2433,7 @@ fn initHeaders(...@@ -1517,7 +2433,7 @@ fn initHeaders(
1517 elf.nodes.appendAssumeCapacity(.{ .segment = dynamic_phndx });2433 elf.nodes.appendAssumeCapacity(.{ .segment = dynamic_phndx });
1518 elf.phdrs.items[dynamic_phndx] = dynamic_ni;2434 elf.phdrs.items[dynamic_phndx] = dynamic_ni;
15192435
1520 elf.si.dynstr = try elf.addSection(elf.ni.rodata, .{2436 const dynstr_shndx = try elf.addSection(elf.ni.rodata, .{
1521 .name = ".dynstr",2437 .name = ".dynstr",
1522 .type = .STRTAB,2438 .type = .STRTAB,
1523 .flags = .{ .ALLOC = true },2439 .flags = .{ .ALLOC = true },
...@@ -1525,26 +2441,27 @@ fn initHeaders(...@@ -1525,26 +2441,27 @@ fn initHeaders(
1525 .entsize = 1,2441 .entsize = 1,
1526 .node_align = elf.mf.flags.block_size,2442 .node_align = elf.mf.flags.block_size,
1527 });2443 });
1528 const dynstr_shndx = elf.si.dynstr.shndx(elf);2444 dynstr_shndx.get(elf).ni.slice(&elf.mf)[0] = 0;
1529 elf.dynsym.putAssumeCapacityNoClobber(.null, {});2445 elf.shndx.dynstr = dynstr_shndx;
2446
1530 switch (class) {2447 switch (class) {
1531 .NONE, _ => unreachable,2448 .NONE, _ => unreachable,
1532 inline else => |ct_class| {2449 inline else => |ct_class| {
1533 const Sym = ct_class.ElfN().Sym;2450 const Sym = ct_class.ElfN().Sym;
1534 elf.si.dynsym = try elf.addSection(elf.ni.rodata, .{2451 elf.shndx.dynsym = try elf.addSection(elf.ni.rodata, .{
1535 .name = ".dynsym",2452 .name = ".dynsym",
1536 .type = .DYNSYM,2453 .type = .DYNSYM,
1537 .flags = .{ .ALLOC = true },2454 .flags = .{ .ALLOC = true },
1538 .size = @sizeOf(Sym) * 1,2455 .size = @sizeOf(Sym) * 1,
1539 .link = @intFromEnum(dynstr_shndx),2456 .link = dynstr_shndx.toSection().?,
1540 .info = 1,2457 .info = 1,
1541 .addralign = addr_align,2458 .addralign = addr_align,
1542 .entsize = @sizeOf(Sym),2459 .entsize = @sizeOf(Sym),
1543 .node_align = elf.mf.flags.block_size,2460 .node_align = elf.mf.flags.block_size,
1544 });2461 });
1545 const dynsym_null = &@field(elf.dynsymSlice(), @tagName(ct_class))[0];2462 const dynsym_null = @field(elf.dynsymPtr(0), @tagName(ct_class));
1546 dynsym_null.* = .{2463 dynsym_null.* = .{
1547 .name = try elf.string(.dynstr, ""),2464 .name = @intFromEnum(String(.dynstr).empty),
1548 .value = 0,2465 .value = 0,
1549 .size = 0,2466 .size = 0,
1550 .info = .{ .type = .NOTYPE, .bind = .LOCAL },2467 .info = .{ .type = .NOTYPE, .bind = .LOCAL },
...@@ -1561,57 +2478,57 @@ fn initHeaders(...@@ -1561,57 +2478,57 @@ fn initHeaders(
1561 .NONE, _ => unreachable,2478 .NONE, _ => unreachable,
1562 inline else => |ct_class| @sizeOf(ct_class.ElfN().Rela),2479 inline else => |ct_class| @sizeOf(ct_class.ElfN().Rela),
1563 };2480 };
1564 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, .{
1565 .name = ".rela.dyn",2482 .name = ".rela.dyn",
1566 .type = .RELA,2483 .type = .RELA,
1567 .flags = .{ .ALLOC = true },2484 .flags = .{ .ALLOC = true },
1568 .link = @intFromEnum(elf.si.dynsym.shndx(elf)),2485 .link = elf.shndx.dynsym.toSection().?,
1569 .addralign = addr_align,2486 .addralign = addr_align,
1570 .entsize = rela_size,2487 .entsize = rela_size,
1571 .node_align = elf.mf.flags.block_size,2488 .node_align = elf.mf.flags.block_size,
1572 });2489 });
1573 const got_plt_shndx = elf.si.got_plt.shndx(elf);2490 const got_plt_shndx = elf.shndx.got_plt;
1574 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, .{
1575 .name = ".rela.plt",2492 .name = ".rela.plt",
1576 .type = .RELA,2493 .type = .RELA,
1577 .flags = .{ .ALLOC = true, .INFO_LINK = true },2494 .flags = .{ .ALLOC = true, .INFO_LINK = true },
1578 .link = @intFromEnum(elf.si.dynsym.shndx(elf)),2495 .link = elf.shndx.dynsym.toSection().?,
1579 .info = @intFromEnum(got_plt_shndx),2496 .info = got_plt_shndx.toSection().?,
1580 .addralign = addr_align,2497 .addralign = addr_align,
1581 .entsize = rela_size,2498 .entsize = rela_size,
1582 .node_align = elf.mf.flags.block_size,2499 .node_align = elf.mf.flags.block_size,
1583 });2500 });
1584 elf.si.dynamic = try elf.addSection(dynamic_ni, .{2501 elf.shndx.dynamic = try elf.addSection(dynamic_ni, .{
1585 .name = ".dynamic",2502 .name = ".dynamic",
1586 .type = .DYNAMIC,2503 .type = .DYNAMIC,
1587 .flags = .{ .ALLOC = true, .WRITE = true },2504 .flags = .{ .ALLOC = true, .WRITE = true },
1588 .link = @intFromEnum(dynstr_shndx),2505 .link = dynstr_shndx.toSection().?,
1589 .entsize = @intCast(addr_align.toByteUnits() * 2),2506 .entsize = @intCast(addr_align.toByteUnits() * 2),
1590 .node_align = addr_align,2507 .node_align = addr_align,
1591 });2508 });
1592 switch (machine) {2509 switch (machine) {
1593 else => @panic(@tagName(machine)),2510 else => @panic(@tagName(machine)),
1594 .X86_64 => {2511 .X86_64 => {
1595 @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{
1596 0xff, 0x35, 0x00, 0x00, 0x00, 0x00, // push 0x0(%rip)2515 0xff, 0x35, 0x00, 0x00, 0x00, 0x00, // push 0x0(%rip)
1597 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *0x0(%rip)2516 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *0x0(%rip)
1598 0x0f, 0x1f, 0x40, 0x00, // nopl 0x0(%rax)2517 0x0f, 0x1f, 0x40, 0x00, // nopl 0x0(%rax)
1599 });2518 });
1600 const plt_sym = elf.si.plt.get(elf);2519 elf.first_plt_reloc = @enumFromInt(elf.relocs.items.len);
1601 assert(plt_sym.loc_relocs == .none);2520 try elf.ensureUnusedRelocCapacity(plt_ni, 2);
1602 plt_sym.loc_relocs = @enumFromInt(elf.relocs.items.len);
1603 try elf.ensureUnusedRelocCapacity(elf.si.plt, 2);
1604 elf.addRelocAssumeCapacity(2521 elf.addRelocAssumeCapacity(
1605 elf.si.plt,2522 plt_ni,
1606 2,2523 2,
1607 elf.si.got_plt,2524 got_plt_sym,
1608 8 * 1 - 4,2525 8 * 1 - 4,
1609 .{ .X86_64 = .PC32 },2526 .{ .X86_64 = .PC32 },
1610 );2527 );
1611 elf.addRelocAssumeCapacity(2528 elf.addRelocAssumeCapacity(
1612 elf.si.plt,2529 plt_ni,
1613 8,2530 8,
1614 elf.si.got_plt,2531 got_plt_sym,
1615 8 * 2 - 4,2532 8 * 2 - 4,
1616 .{ .X86_64 = .PC32 },2533 .{ .X86_64 = .PC32 },
1617 );2534 );
...@@ -1631,7 +2548,7 @@ fn initHeaders(...@@ -1631,7 +2548,7 @@ fn initHeaders(
1631 assert(maybe_interp == null);2548 assert(maybe_interp == null);
1632 assert(!have_dynamic_section);2549 assert(!have_dynamic_section);
1633 }2550 }
1634 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, .{
1635 .name = ".tdata",2552 .name = ".tdata",
1636 .flags = .{ .WRITE = true, .ALLOC = true, .TLS = true },2553 .flags = .{ .WRITE = true, .ALLOC = true, .TLS = true },
1637 .addralign = elf.mf.flags.block_size,2554 .addralign = elf.mf.flags.block_size,
...@@ -1641,7 +2558,7 @@ fn initHeaders(...@@ -1641,7 +2558,7 @@ fn initHeaders(
16412558
1642pub fn startProgress(elf: *Elf, prog_node: std.Progress.Node) void {2559pub fn startProgress(elf: *Elf, prog_node: std.Progress.Node) void {
1643 prog_node.increaseEstimatedTotalItems(4);2560 prog_node.increaseEstimatedTotalItems(4);
1644 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);
1645 elf.synth_prog_node = prog_node.start("Synthetics", count: {2562 elf.synth_prog_node = prog_node.start("Synthetics", count: {
1646 var count: usize = 0;2563 var count: usize = 0;
1647 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;
...@@ -1668,35 +2585,105 @@ pub fn endProgress(elf: *Elf) void {...@@ -1668,35 +2585,105 @@ pub fn endProgress(elf: *Elf) void {
1668fn getNode(elf: *const Elf, ni: MappedFile.Node.Index) Node {2585fn getNode(elf: *const Elf, ni: MappedFile.Node.Index) Node {
1669 return elf.nodes.get(@intFromEnum(ni));2586 return elf.nodes.get(@intFromEnum(ni));
1670}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}
1671fn computeNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 {2606fn computeNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 {
1672 const parent_vaddr = parent_vaddr: {2607 const parent_vaddr = switch (elf.getNode(ni.parent(&elf.mf))) {
1673 const parent_ni = ni.parent(&elf.mf);2608 .file => return 0,
1674 const parent_si = switch (elf.getNode(parent_ni)) {2609 .ehdr, .shdr => unreachable,
1675 .file => return 0,2610 .segment => |phndx| switch (elf.phdrSlice()) {
1676 .ehdr, .shdr => unreachable,2611 inline else => |phdr| elf.targetLoad(&phdr[phndx].vaddr),
1677 .segment => |phndx| break :parent_vaddr switch (elf.phdrSlice()) {2612 },
1678 inline else => |phdr| elf.targetLoad(&phdr[phndx].vaddr),2613 .section => |shndx| if (shndx == elf.shndx.tdata) 0 else shndx.vaddr(elf),
1679 },2614 .input_section => unreachable,
1680 .section => |si| si,2615 inline .nav, .uav, .lazy_code, .lazy_const_data => |i| Symbol.Id.local(i.symbol(elf)).value(elf),
1681 .input_section => unreachable,
1682 inline .nav, .uav, .lazy_code, .lazy_const_data => |mi| mi.symbol(elf),
1683 };
1684 break :parent_vaddr if (parent_si == elf.si.tdata) 0 else switch (elf.symPtr(parent_si)) {
1685 inline else => |sym| elf.targetLoad(&sym.value),
1686 };
1687 };2616 };
1688 const offset, _ = ni.location(&elf.mf).resolve(&elf.mf);2617 const offset, _ = ni.location(&elf.mf).resolve(&elf.mf);
1689 return parent_vaddr + offset;2618 return parent_vaddr + offset;
1690}2619}
16912620
1692pub 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 {
1693 return @enumFromInt(elf.mf.memory_map.memory[std.elf.EI.CLASS]);2680 return @enumFromInt(elf.mf.memory_map.memory[std.elf.EI.CLASS]);
1694}2681}
1695pub fn identData(elf: *const Elf) std.elf.DATA {2682fn identData(elf: *const Elf) std.elf.DATA {
1696 return @enumFromInt(elf.mf.memory_map.memory[std.elf.EI.DATA]);2683 return @enumFromInt(elf.mf.memory_map.memory[std.elf.EI.DATA]);
1697}2684}
16982685
1699pub fn targetEndian(elf: *const Elf) std.lang.Endian {2686fn targetEndian(elf: *const Elf) std.lang.Endian {
1700 return switch (elf.identData()) {2687 return switch (elf.identData()) {
1701 .NONE, _ => unreachable,2688 .NONE, _ => unreachable,
1702 .@"2LSB" => .little,2689 .@"2LSB" => .little,
...@@ -1730,12 +2717,12 @@ fn targetStore(elf: *const Elf, ptr: anytype, val: @typeInfo(@TypeOf(ptr)).point...@@ -1730,12 +2717,12 @@ fn targetStore(elf: *const Elf, ptr: anytype, val: @typeInfo(@TypeOf(ptr)).point
1730 };2717 };
1731}2718}
17322719
1733pub const EhdrPtr = union(std.elf.CLASS) {2720const EhdrPtr = union(std.elf.CLASS) {
1734 NONE: noreturn,2721 NONE: noreturn,
1735 @"32": *std.elf.Elf32.Ehdr,2722 @"32": *std.elf.Elf32.Ehdr,
1736 @"64": *std.elf.Elf64.Ehdr,2723 @"64": *std.elf.Elf64.Ehdr,
1737};2724};
1738pub fn ehdrPtr(elf: *Elf) EhdrPtr {2725fn ehdrPtr(elf: *Elf) EhdrPtr {
1739 const slice = elf.ni.ehdr.slice(&elf.mf);2726 const slice = elf.ni.ehdr.slice(&elf.mf);
1740 return switch (elf.identClass()) {2727 return switch (elf.identClass()) {
1741 .NONE, _ => unreachable,2728 .NONE, _ => unreachable,
...@@ -1746,7 +2733,7 @@ pub fn ehdrPtr(elf: *Elf) EhdrPtr {...@@ -1746,7 +2733,7 @@ pub fn ehdrPtr(elf: *Elf) EhdrPtr {
1746 ),2733 ),
1747 };2734 };
1748}2735}
1749pub fn ehdrField(2736fn ehdrField(
1750 elf: *Elf,2737 elf: *Elf,
1751 comptime field: std.meta.FieldEnum(std.elf.Elf64.Ehdr),2738 comptime field: std.meta.FieldEnum(std.elf.Elf64.Ehdr),
1752) @FieldType(std.elf.Elf64.Ehdr, @tagName(field)) {2739) @FieldType(std.elf.Elf64.Ehdr, @tagName(field)) {
...@@ -1755,12 +2742,12 @@ pub fn ehdrField(...@@ -1755,12 +2742,12 @@ pub fn ehdrField(
1755 };2742 };
1756}2743}
17572744
1758pub const PhdrSlice = union(std.elf.CLASS) {2745const PhdrSlice = union(std.elf.CLASS) {
1759 NONE: noreturn,2746 NONE: noreturn,
1760 @"32": []std.elf.Elf32.Phdr,2747 @"32": []std.elf.Elf32.Phdr,
1761 @"64": []std.elf.Elf64.Phdr,2748 @"64": []std.elf.Elf64.Phdr,
1762};2749};
1763pub fn phdrSlice(elf: *Elf) PhdrSlice {2750fn phdrSlice(elf: *Elf) PhdrSlice {
1764 assert(elf.ehdrField(.type) != .REL);2751 assert(elf.ehdrField(.type) != .REL);
1765 const slice = elf.ni.phdr.slice(&elf.mf);2752 const slice = elf.ni.phdr.slice(&elf.mf);
1766 return switch (elf.identClass()) {2753 return switch (elf.identClass()) {
...@@ -1773,104 +2760,47 @@ pub fn phdrSlice(elf: *Elf) PhdrSlice {...@@ -1773,104 +2760,47 @@ pub fn phdrSlice(elf: *Elf) PhdrSlice {
1773 };2760 };
1774}2761}
17752762
1776pub const ShdrSlice = union(std.elf.CLASS) {2763const ShdrPtr = union(std.elf.CLASS) {
1777 NONE: noreturn,
1778 @"32": []std.elf.Elf32.Shdr,
1779 @"64": []std.elf.Elf64.Shdr,
1780};
1781pub fn shdrSlice(elf: *Elf) ShdrSlice {
1782 const slice = elf.ni.shdr.slice(&elf.mf);
1783 return switch (elf.identClass()) {
1784 .NONE, _ => unreachable,
1785 inline else => |class| @unionInit(
1786 ShdrSlice,
1787 @tagName(class),
1788 @ptrCast(@alignCast(slice)),
1789 ),
1790 };
1791}
1792
1793pub const ShdrPtr = union(std.elf.CLASS) {
1794 NONE: noreturn,2764 NONE: noreturn,
1795 @"32": *std.elf.Elf32.Shdr,2765 @"32": *std.elf.Elf32.Shdr,
1796 @"64": *std.elf.Elf64.Shdr,2766 @"64": *std.elf.Elf64.Shdr,
1797};2767};
1798pub fn shdrPtr(elf: *Elf, shndx: Symbol.Index.Shndx) ShdrPtr {2768fn shdrPtr(elf: *Elf, shndx: Section.Index) ShdrPtr {
1799 return switch (elf.shdrSlice()) {2769 const raw_slice = elf.ni.shdr.slice(&elf.mf);
1800 inline else => |shdrs, class| @unionInit(ShdrPtr, @tagName(class), &shdrs[@intFromEnum(shndx)]),2770 switch (elf.identClass()) {
1801 };2771 .NONE, _ => unreachable,
1802}2772 inline else => |class| {
18032773 const shdr_slice: []class.ElfN().Shdr = @ptrCast(@alignCast(raw_slice));
1804pub const SymtabSlice = union(std.elf.CLASS) {2774 const shdr_ptr = &shdr_slice[@intFromEnum(shndx)];
1805 NONE: noreturn,2775 return @unionInit(ShdrPtr, @tagName(class), shdr_ptr);
1806 @"32": []std.elf.Elf32.Sym,2776 },
1807 @"64": []std.elf.Elf64.Sym,2777 }
1808};
1809pub fn symtabSlice(elf: *Elf) SymtabSlice {
1810 const slice = elf.si.symtab.node(elf).slice(&elf.mf);
1811 return switch (elf.identClass()) {
1812 .NONE, _ => unreachable,
1813 inline else => |class| @unionInit(SymtabSlice, @tagName(class), @ptrCast(@alignCast(
1814 slice[0..std.mem.alignBackwardAnyAlign(usize, slice.len, @sizeOf(class.ElfN().Sym))],
1815 ))),
1816 };
1817}
1818
1819pub const SymPtr = union(std.elf.CLASS) {
1820 NONE: noreturn,
1821 @"32": *std.elf.Elf32.Sym,
1822 @"64": *std.elf.Elf64.Sym,
1823};
1824pub fn symPtr(elf: *Elf, si: Symbol.Index) SymPtr {
1825 return switch (elf.symtabSlice()) {
1826 inline else => |syms, class| @unionInit(SymPtr, @tagName(class), &syms[@intFromEnum(si)]),
1827 };
1828}
1829
1830pub fn dynsymSlice(elf: *Elf) SymtabSlice {
1831 const slice = elf.si.dynsym.node(elf).slice(&elf.mf);
1832 return switch (elf.identClass()) {
1833 .NONE, _ => unreachable,
1834 inline else => |class| @unionInit(SymtabSlice, @tagName(class), @ptrCast(@alignCast(
1835 slice[0..std.mem.alignBackwardAnyAlign(usize, slice.len, @sizeOf(class.ElfN().Sym))],
1836 ))),
1837 };
1838}
1839
1840fn addSymbolAssumeCapacity(elf: *Elf) Symbol.Index {
1841 defer elf.symtab.addOneAssumeCapacity().* = .{
1842 .ni = .none,
1843 .loc_relocs = .none,
1844 .target_relocs = .none,
1845 .unused = 0,
1846 };
1847 return @enumFromInt(elf.symtab.items.len);
1848}2778}
18492779
1850fn initSymbolAssumeCapacity(elf: *Elf, opts: Symbol.Index.InitOptions) !Symbol.Index {2780const SymPtr = union(std.elf.CLASS) {
1851 const si = elf.addSymbolAssumeCapacity();2781 NONE: noreturn,
1852 try si.init(elf, opts);2782 @"32": *std.elf.Elf32.Sym,
1853 return si;2783 @"64": *std.elf.Elf64.Sym,
2784};
2785fn symPtr(elf: *Elf, index: Symbol.Index) SymPtr {
2786 const raw_slice = Section.Index.symtab.get(elf).ni.slice(&elf.mf);
2787 switch (elf.shdrPtr(.symtab)) {
2788 inline else => |shdr, class| {
2789 const size = elf.targetLoad(&shdr.size);
2790 const slice: []class.ElfN().Sym = @ptrCast(@alignCast(raw_slice[0..@intCast(size)]));
2791 return @unionInit(SymPtr, @tagName(class), &slice[@intFromEnum(index)]);
2792 },
2793 }
1854}2794}
18552795fn dynsymPtr(elf: *Elf, index: u32) SymPtr {
1856pub fn globalSymbol(elf: *Elf, opts: struct {2796 const raw_slice = elf.shndx.dynsym.get(elf).ni.slice(&elf.mf);
1857 name: []const u8,2797 switch (elf.shdrPtr(elf.shndx.dynsym)) {
1858 lib_name: ?[]const u8 = null,2798 inline else => |shdr, class| {
1859 type: std.elf.STT,2799 const size = elf.targetLoad(&shdr.size);
1860 bind: std.elf.STB = .GLOBAL,2800 const slice: []class.ElfN().Sym = @ptrCast(@alignCast(raw_slice[0..@intCast(size)]));
1861 visibility: std.elf.STV = .DEFAULT,2801 return @unionInit(SymPtr, @tagName(class), &slice[index]);
1862}) !Symbol.Index {2802 },
1863 const gpa = elf.base.comp.gpa;2803 }
1864 try elf.symtab.ensureUnusedCapacity(gpa, 1);
1865 const global_gop = try elf.globals.getOrPut(gpa, try elf.string(.strtab, opts.name));
1866 if (!global_gop.found_existing) global_gop.value_ptr.* = try elf.initSymbolAssumeCapacity(.{
1867 .name = opts.name,
1868 .lib_name = opts.lib_name,
1869 .type = opts.type,
1870 .bind = opts.bind,
1871 .visibility = opts.visibility,
1872 });
1873 return global_gop.value_ptr.*;
1874}2804}
18752805
1876fn navType(2806fn navType(
...@@ -1885,97 +2815,135 @@ fn navType(...@@ -1885,97 +2815,135 @@ fn navType(
1885 else2815 else
1886 .OBJECT;2816 .OBJECT;
1887}2817}
1888fn namedSection(elf: *const Elf, name: []const u8) ?Symbol.Index {2818fn namedSection(elf: *const Elf, name: []const u8) ?Section.Index {
1889 if (std.mem.eql(u8, name, ".rodata") or2819 if (std.mem.eql(u8, name, ".rodata") or
1890 std.mem.startsWith(u8, name, ".rodata.")) return elf.si.rodata;2820 std.mem.startsWith(u8, name, ".rodata.")) return .rodata;
1891 if (std.mem.eql(u8, name, ".text") or2821 if (std.mem.eql(u8, name, ".text") or
1892 std.mem.startsWith(u8, name, ".text.")) return elf.si.text;2822 std.mem.startsWith(u8, name, ".text.")) return .text;
1893 if (std.mem.eql(u8, name, ".data") or2823 if (std.mem.eql(u8, name, ".data") or
1894 std.mem.startsWith(u8, name, ".data.")) return elf.si.data;2824 std.mem.startsWith(u8, name, ".data.")) return .data;
1895 if (std.mem.eql(u8, name, ".tdata") or2825 if (std.mem.eql(u8, name, ".tdata") or
1896 std.mem.startsWith(u8, name, ".tdata.")) return elf.si.tdata;2826 std.mem.startsWith(u8, name, ".tdata.")) return elf.shndx.tdata;
1897 return null;2827 return null;
1898}2828}
1899fn navSection(
1900 elf: *Elf,
1901 ip: *const InternPool,
1902 nav_resolved: @typeInfo(@FieldType(InternPool.Nav, "resolved")).optional.child,
1903) Symbol.Index {
1904 if (nav_resolved.@"linksection".toSlice(ip)) |@"linksection"|
1905 if (elf.namedSection(@"linksection")) |si| return si;
1906 return switch (navType(
1907 ip,
1908 nav_resolved,
1909 elf.base.comp.config.any_non_single_threaded,
1910 )) {
1911 else => unreachable,
1912 .FUNC => elf.si.text,
1913 .OBJECT => elf.si.data,
1914 .TLS => elf.si.tdata,
1915 };
1916}
1917fn 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 {
1918 const gpa = zcu.gpa;2830 const gpa = zcu.gpa;
1919 const ip = &zcu.intern_pool;2831 const ip = &zcu.intern_pool;
1920 const nav = ip.getNav(nav_index);2832 const nav = ip.getNav(nav_index);
1921 try elf.symtab.ensureUnusedCapacity(gpa, 1);
1922 const nav_gop = try elf.navs.getOrPut(gpa, nav_index);
1923 if (!nav_gop.found_existing) nav_gop.value_ptr.* = try elf.initSymbolAssumeCapacity(.{
1924 .name = nav.fqn.toSlice(ip),
1925 .type = navType(ip, nav.resolved.?, elf.base.comp.config.any_non_single_threaded),
1926 });
1927 return @enumFromInt(nav_gop.index);
1928}
1929pub fn navSymbol(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Symbol.Index {
1930 const ip = &zcu.intern_pool;
1931 const nav = ip.getNav(nav_index);
1932 if (nav.getExtern(ip)) |@"extern"| return elf.globalSymbol(.{
1933 .name = @"extern".name.toSlice(ip),
1934 .lib_name = @"extern".lib_name.toSlice(ip),
1935 .type = navType(ip, nav.resolved.?, elf.base.comp.config.any_non_single_threaded),
1936 .bind = switch (@"extern".linkage) {
1937 .internal => .LOCAL,
1938 .strong => .GLOBAL,
1939 .weak => .WEAK,
1940 .link_once => return error.LinkOnceUnsupported,
1941 },
1942 .visibility = switch (@"extern".visibility) {
1943 .default => .DEFAULT,
1944 .hidden => .HIDDEN,
1945 .protected => .PROTECTED,
1946 },
1947 });
1948 const nmi = try elf.navMapIndex(zcu, nav_index);
1949 return nmi.symbol(elf);
1950}
19512833
1952fn uavMapIndex(elf: *Elf, uav_val: InternPool.Index) !Node.UavMapIndex {2834 try elf.ensureUnusedSymbolCapacity(1, .all_local);
1953 const gpa = elf.base.comp.gpa;2835 try elf.nodes.ensureUnusedCapacity(gpa, 1);
1954 try elf.symtab.ensureUnusedCapacity(gpa, 1);2836 try elf.navs.ensureUnusedCapacity(gpa, 1);
1955 const uav_gop = try elf.uavs.getOrPut(gpa, uav_val);2837
1956 if (!uav_gop.found_existing)2838 const nav_gop = elf.navs.getOrPutAssumeCapacity(nav_index);
1957 uav_gop.value_ptr.* = try elf.initSymbolAssumeCapacity(.{ .type = .OBJECT });2839 const nmi: Node.NavMapIndex = @enumFromInt(nav_gop.index);
1958 return @enumFromInt(uav_gop.index);2840 if (!nav_gop.found_existing) {
1959}2841 const sym_type = navType(ip, nav.resolved.?, elf.base.comp.config.any_non_single_threaded);
1960pub fn uavSymbol(elf: *Elf, uav_val: InternPool.Index) !Symbol.Index {2842 const shndx: Section.Index = section: {
1961 const umi = try elf.uavMapIndex(uav_val);2843 if (nav.resolved.?.@"linksection".toSlice(ip)) |@"linksection"| {
1962 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;
1963}2891}
19642892
1965pub 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 {
1966 const gpa = elf.base.comp.gpa;2898 const gpa = elf.base.comp.gpa;
1967 try elf.symtab.ensureUnusedCapacity(gpa, 1);2899 const zcu = elf.base.comp.zcu.?;
1968 const lazy_gop = try elf.lazy.getPtr(lazy.kind).map.getOrPut(gpa, lazy.ty);2900
1969 if (!lazy_gop.found_existing) {2901 try elf.ensureUnusedSymbolCapacity(1, .all_local);
1970 lazy_gop.value_ptr.* = try elf.initSymbolAssumeCapacity(.{2902 try elf.nodes.ensureUnusedCapacity(gpa, 1);
1971 .type = switch (lazy.kind) {2903 try elf.uavs.ensureUnusedCapacity(gpa, 1);
1972 .code => .FUNC,2904 try elf.pending_uavs.ensureUnusedCapacity(gpa, 1);
1973 .const_data => .OBJECT,2905
1974 },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(),
1975 });2919 });
1976 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 }
1977 }2945 }
1978 return lazy_gop.value_ptr.*;2946 return umi;
1979}2947}
19802948
1981pub fn loadInput(elf: *Elf, input: link.Input) (Io.File.Reader.SizeError ||2949pub fn loadInput(elf: *Elf, input: link.Input) (Io.File.Reader.SizeError ||
...@@ -2080,19 +3048,23 @@ fn loadObject(...@@ -2080,19 +3048,23 @@ fn loadObject(
2080 const diags = &comp.link_diags;3048 const diags = &comp.link_diags;
2081 const r = &fr.interface;3049 const r = &fr.interface;
20823050
2083 const ii: Node.InputIndex = @enumFromInt(elf.inputs.items.len);3051 const input_index: Node.InputIndex = @enumFromInt(elf.inputs.items.len);
2084 log.debug("loadObject({f}{f})", .{ path.fmtEscapeString(), fmtMemberString(member) });3052 log.debug("loadObject({f}{f})", .{ path.fmtEscapeString(), fmtMemberString(member) });
2085 try elf.checkInputIdent(path, r);3053 try elf.checkInputIdent(path, r);
2086 try elf.symtab.ensureUnusedCapacity(gpa, 1);3054 try elf.ensureUnusedSymbolCapacity(1, .all_local);
2087 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 });
2088 elf.inputs.addOneAssumeCapacity().* = .{3064 elf.inputs.addOneAssumeCapacity().* = .{
2089 .path = path,3065 .path = path,
2090 .member = if (member) |m| try gpa.dupe(u8, m) else null,3066 .member = if (member) |m| try gpa.dupe(u8, m) else null,
2091 .si = try elf.initSymbolAssumeCapacity(.{3067 .file_symbol = file_symbol,
2092 .name = std.fs.path.stem(member orelse path.sub_path),
2093 .type = .FILE,
2094 .shndx = .ABS,
2095 }),
2096 };3068 };
2097 const target_endian = elf.targetEndian();3069 const target_endian = elf.targetEndian();
2098 switch (elf.identClass()) {3070 switch (elf.identClass()) {
...@@ -2108,13 +3080,13 @@ fn loadObject(...@@ -2108,13 +3080,13 @@ fn loadObject(
2108 return diags.failParse(path, "bad section header location", .{});3080 return diags.failParse(path, "bad section header location", .{});
2109 if (ehdr.shentsize < @sizeOf(ElfN.Shdr))3081 if (ehdr.shentsize < @sizeOf(ElfN.Shdr))
2110 return diags.failParse(path, "unsupported shentsize", .{});3082 return diags.failParse(path, "unsupported shentsize", .{});
2111 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);
2112 defer gpa.free(sections);3084 defer gpa.free(sections);
2113 try fr.seekTo(fl.offset + ehdr.shoff);3085 try fr.seekTo(fl.offset + ehdr.shoff);
2114 for (sections) |*section| {3086 for (sections) |*section| {
2115 section.* = .{3087 section.* = .{
2116 .shdr = try r.peekStruct(ElfN.Shdr, target_endian),3088 .shdr = try r.peekStruct(ElfN.Shdr, target_endian),
2117 .si = .null,3089 .isi = null,
2118 };3090 };
2119 try r.discardAll(ehdr.shentsize);3091 try r.discardAll(ehdr.shentsize);
2120 switch (section.shdr.type) {3092 switch (section.shdr.type) {
...@@ -2136,42 +3108,49 @@ fn loadObject(...@@ -2136,42 +3108,49 @@ fn loadObject(
2136 };3108 };
2137 defer gpa.free(shstrtab);3109 defer gpa.free(shstrtab);
2138 try elf.nodes.ensureUnusedCapacity(gpa, ehdr.shnum - 1);3110 try elf.nodes.ensureUnusedCapacity(gpa, ehdr.shnum - 1);
2139 try elf.symtab.ensureUnusedCapacity(gpa, ehdr.shnum - 1);
2140 try elf.input_sections.ensureUnusedCapacity(gpa, ehdr.shnum - 1);3111 try elf.input_sections.ensureUnusedCapacity(gpa, ehdr.shnum - 1);
2141 for (sections[1..]) |*section| switch (section.shdr.type) {3112 for (sections[1..]) |*section| switch (section.shdr.type) {
2142 else => {},3113 else => {},
2143 .PROGBITS, .NOBITS => {3114 .PROGBITS, .NOBITS => {
2144 if (section.shdr.name >= shstrtab.len) continue;3115 if (section.shdr.name >= shstrtab.len) continue;
2145 const name = std.mem.sliceTo(shstrtab[section.shdr.name..], 0);3116 const name = std.mem.sliceTo(shstrtab[section.shdr.name..], 0);
2146 const parent_si = elf.namedSection(name) orelse continue;3117 const shndx: Section.Index = elf.namedSection(name) orelse shndx: {
2147 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, .{
2148 .size = section.shdr.size,3127 .size = section.shdr.size,
2149 .alignment = .fromByteUnits(std.math.ceilPowerOfTwoAssert(3128 .alignment = .fromByteUnits(std.math.ceilPowerOfTwoAssert(
2150 usize,3129 usize,
2151 @intCast(@max(section.shdr.addralign, 1)),3130 @intCast(@max(section.shdr.addralign, 1)),
2152 )),3131 )),
2153 .moved = true,3132 .moved = true, // see assert at end of `flushInputSection`
2154 });3133 });
2155 elf.nodes.appendAssumeCapacity(.{3134 elf.nodes.appendAssumeCapacity(.{
2156 .input_section = @enumFromInt(elf.input_sections.items.len),3135 .input_section = @enumFromInt(elf.input_sections.items.len),
2157 });3136 });
2158 section.si = try elf.initSymbolAssumeCapacity(.{3137 section.isi = @enumFromInt(elf.input_sections.items.len);
2159 .type = .SECTION,
2160 .shndx = parent_si.shndx(elf),
2161 });
2162 section.si.get(elf).ni = ni;
2163 elf.input_sections.addOneAssumeCapacity().* = .{3138 elf.input_sections.addOneAssumeCapacity().* = .{
2164 .ii = ii,3139 .input = input_index,
2165 .si = section.si,
2166 .file_location = .{3140 .file_location = .{
2167 .offset = fl.offset + section.shdr.offset,3141 .offset = fl.offset + section.shdr.offset,
2168 .size = section.shdr.size,3142 .size = if (section.shdr.type == .NOBITS) 0 else section.shdr.size,
2169 },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,
2170 };3149 };
2171 elf.synth_prog_node.increaseEstimatedTotalItems(1);3150 elf.synth_prog_node.increaseEstimatedTotalItems(1);
2172 },3151 },
2173 };3152 };
2174 var symmap: std.ArrayList(Symbol.Index) = .empty;3153 var symmap: std.ArrayList(Symbol.Id) = .empty;
2175 defer symmap.deinit(gpa);3154 defer symmap.deinit(gpa);
2176 for (sections[1..], 1..) |*symtab, symtab_shndx| switch (symtab.shdr.type) {3155 for (sections[1..], 1..) |*symtab, symtab_shndx| switch (symtab.shdr.type) {
2177 else => {},3156 else => {},
...@@ -2202,105 +3181,132 @@ fn loadObject(...@@ -2202,105 +3181,132 @@ fn loadObject(
2202 ), 1) catch continue;3181 ), 1) catch continue;
2203 symmap.clearRetainingCapacity();3182 symmap.clearRetainingCapacity();
2204 try symmap.resize(gpa, symnum);3183 try symmap.resize(gpa, symnum);
2205 try elf.symtab.ensureUnusedCapacity(gpa, symnum);3184 try elf.ensureUnusedSymbolCapacity(symnum, .maybe_global);
2206 try elf.globals.ensureUnusedCapacity(gpa, symnum);
2207 try fr.seekTo(fl.offset + symtab.shdr.offset + symtab.shdr.entsize);3185 try fr.seekTo(fl.offset + symtab.shdr.offset + symtab.shdr.entsize);
2208 for (symmap.items) |*si| {3186 for (symmap.items) |*si| {
2209 si.* = .null;3187 si.* = .null;
2210 const input_sym = try r.peekStruct(ElfN.Sym, target_endian);3188 const input_sym = try r.peekStruct(ElfN.Sym, target_endian);
2211 try r.discardAll64(symtab.shdr.entsize);3189 try r.discardAll64(symtab.shdr.entsize);
2212 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;
2213 input_sym.shndx >= ehdr.shnum) continue;3191
2214 switch (input_sym.info.type) {3192 const name = std.mem.sliceTo(strtab[input_sym.name..], 0);
2215 .NOTYPE, .OBJECT, .FUNC => {},3193
2216 .SECTION => {3194 const sym_type: std.elf.STT = switch (input_sym.info.type) {
2217 const section = &sections[input_sym.shndx];3195 .NOTYPE, .OBJECT, .FUNC, .TLS => |t| t,
2218 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 };
2219 continue;3220 continue;
2220 },3221 },
2221 else => continue,3222 };
2222 }3223
2223 const name = std.mem.sliceTo(strtab[input_sym.name..], 0);3224 const input_section_node = (sections[input_sym.shndx].isi orelse continue).node(elf);
2224 const parent_si = sections[input_sym.shndx].si;3225
2225 si.* = try elf.initSymbolAssumeCapacity(.{
2226 .name = name,
2227 .value = input_sym.value,
2228 .size = input_sym.size,
2229 .type = input_sym.info.type,
2230 .bind = input_sym.info.bind,
2231 .visibility = input_sym.other.visibility,
2232 .shndx = parent_si.shndx(elf),
2233 });
2234 si.get(elf).ni = parent_si.get(elf).ni;
2235 switch (input_sym.info.bind) {3226 switch (input_sym.info.bind) {
2236 else => {},3227 _ => |bind| return diags.failParse(
2237 .GLOBAL => {3228 path,
2238 const gop = elf.globals.getOrPutAssumeCapacity(elf.targetLoad(3229 "symbol '{s}' has unsupported binding (0x{x})",
2239 &@field(elf.symPtr(si.*), @tagName(class)).name,3230 .{ name, bind },
2240 ));3231 ),
2241 if (gop.found_existing) switch (elf.targetLoad(3232 .LOCAL => {
2242 switch (elf.symPtr(gop.value_ptr.*)) {3233 const lsi = elf.addLocalSymbolAssumeCapacity(.{
2243 inline else => |sym| &sym.info,3234 .node = input_section_node,
2244 },3235 .name = try elf.string(.strtab, name),
2245 ).bind) {3236 .value = input_sym.value,
2246 else => unreachable,3237 .size = input_sym.size,
2247 .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(
2248 path,3255 path,
2249 "multiple definitions of '{s}'",3256 "multiple definitions of '{s}'",
2250 .{name},3257 .{name},
2251 ),3258 ),
2252 .WEAK => {},
2253 };3259 };
2254 gop.value_ptr.* = si.*;
2255 },
2256 .WEAK => {
2257 const gop = elf.globals.getOrPutAssumeCapacity(elf.targetLoad(
2258 &@field(elf.symPtr(si.*), @tagName(class)).name,
2259 ));
2260 if (!gop.found_existing) gop.value_ptr.* = si.*;
2261 },3260 },
2262 }3261 }
2263 }3262 }
2264 for (sections[1..]) |*rels| switch (rels.shdr.type) {3263 for (sections[1..]) |*rel_sec| switch (rel_sec.shdr.type) {
2265 else => {},3264 else => {},
2266 inline .REL, .RELA => |sht| {3265 inline .REL, .RELA => |sht| {
2267 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
2268 rels.shdr.info >= ehdr.shnum) continue;3267 rel_sec.shdr.info >= ehdr.shnum) continue;
2269 const Rel = switch (sht) {3268 const Rel = switch (sht) {
2270 else => comptime unreachable,3269 else => comptime unreachable,
2271 .REL => ElfN.Rel,3270 .REL => ElfN.Rel,
2272 .RELA => ElfN.Rela,3271 .RELA => ElfN.Rela,
2273 };3272 };
2274 if (rels.shdr.entsize < @sizeOf(Rel))3273 if (rel_sec.shdr.entsize < @sizeOf(Rel))
2275 return diags.failParse(path, "unsupported rel entsize", .{});3274 return diags.failParse(path, "unsupported rel entsize", .{});
22763275
2277 const loc_sec = &sections[rels.shdr.info];3276 const loc_sec = &sections[rel_sec.shdr.info];
2278 if (loc_sec.si == .null) continue;3277 const loc_node = (loc_sec.isi orelse continue).node(elf);
2279 const loc_sym = loc_sec.si.get(elf);3278 elf.resetNodeRelocs(loc_node);
2280 assert(loc_sym.loc_relocs == .none);
2281 loc_sym.loc_relocs = @enumFromInt(elf.relocs.items.len);
22823279
2283 const relnum = std.math.divExact(3280 const relnum = std.math.divExact(
2284 u32,3281 u32,
2285 @intCast(rels.shdr.size),3282 @intCast(rel_sec.shdr.size),
2286 @intCast(rels.shdr.entsize),3283 @intCast(rel_sec.shdr.entsize),
2287 ) catch return diags.failParse(3284 ) catch return diags.failParse(
2288 path,3285 path,
2289 "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})",
2290 .{ rels.shdr.size, rels.shdr.entsize },3287 .{ rel_sec.shdr.size, rel_sec.shdr.entsize },
2291 );3288 );
2292 try elf.ensureUnusedRelocCapacity(loc_sec.si, relnum);3289 try elf.ensureUnusedRelocCapacity(loc_node, relnum);
2293 try fr.seekTo(fl.offset + rels.shdr.offset);3290 try fr.seekTo(fl.offset + rel_sec.shdr.offset);
2294 for (0..relnum) |_| {3291 for (0..relnum) |_| {
2295 const rel = try r.peekStruct(Rel, target_endian);3292 const rel = try r.peekStruct(Rel, target_endian);
2296 try r.discardAll64(rels.shdr.entsize);3293 try r.discardAll64(rel_sec.shdr.entsize);
2297 if (rel.info.sym == 0 or rel.info.sym > symnum) continue;3294 if (rel.info.sym == 0) continue;
2298 const target_si = symmap.items[rel.info.sym - 1];3295 if (rel.info.sym > symnum) return diags.failParse(
2299 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 );
2300 elf.addRelocAssumeCapacity(3306 elf.addRelocAssumeCapacity(
2301 loc_sec.si,3307 loc_node,
2302 rel.offset - loc_sec.shdr.addr,3308 rel.offset - loc_sec.shdr.addr,
2303 target_si,3309 target,
2304 rel.addend,3310 rel.addend,
2305 .wrap(rel.info.type, elf),3311 .wrap(rel.info.type, elf),
2306 );3312 );
...@@ -2386,7 +3392,7 @@ fn loadDso(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) !void {...@@ -2386,7 +3392,7 @@ fn loadDso(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) !void {
2386}3392}
2387fn loadDsoExact(elf: *Elf, name: []const u8) !void {3393fn loadDsoExact(elf: *Elf, name: []const u8) !void {
2388 log.debug("loadDsoExact({f})", .{std.zig.fmtString(name)});3394 log.debug("loadDsoExact({f})", .{std.zig.fmtString(name)});
2389 if (elf.si.dynamic != .null) {3395 if (elf.shndx.dynamic != .UNDEF) {
2390 try elf.needed.put(elf.base.comp.gpa, try elf.string(.dynstr, name), {});3396 try elf.needed.put(elf.base.comp.gpa, try elf.string(.dynstr, name), {});
2391 }3397 }
2392}3398}
...@@ -2454,20 +3460,27 @@ pub fn prelink(elf: *Elf, prog_node: std.Progress.Node) !void {...@@ -2454,20 +3460,27 @@ pub fn prelink(elf: *Elf, prog_node: std.Progress.Node) !void {
2454fn prelinkInner(elf: *Elf) !void {3460fn prelinkInner(elf: *Elf) !void {
2455 const comp = elf.base.comp;3461 const comp = elf.base.comp;
2456 const gpa = comp.gpa;3462 const gpa = comp.gpa;
2457 try elf.symtab.ensureUnusedCapacity(gpa, 1);3463 try elf.ensureUnusedSymbolCapacity(1, .all_local);
2458 try elf.inputs.ensureUnusedCapacity(gpa, 1);3464 try elf.inputs.ensureUnusedCapacity(gpa, 1);
2459 const zcu_name = try std.fmt.allocPrint(gpa, "{s}_zcu", .{3465 const zcu_name = try std.fmt.allocPrint(gpa, "{s}_zcu", .{
2460 std.fs.path.stem(elf.base.emit.sub_path),3466 std.fs.path.stem(elf.base.emit.sub_path),
2461 });3467 });
2462 defer gpa.free(zcu_name);3468 defer gpa.free(zcu_name);
2463 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 });
2464 elf.inputs.addOneAssumeCapacity().* = .{3477 elf.inputs.addOneAssumeCapacity().* = .{
2465 .path = elf.base.emit,3478 .path = elf.base.emit,
2466 .member = null,3479 .member = null,
2467 .si = si,3480 .file_symbol = zcu_file_symbol,
2468 };3481 };
24693482
2470 if (elf.si.dynamic != .null) switch (elf.identClass()) {3483 if (elf.shndx.dynamic != .UNDEF) switch (elf.identClass()) {
2471 .NONE, _ => unreachable,3484 .NONE, _ => unreachable,
2472 inline else => |ct_class| {3485 inline else => |ct_class| {
2473 const ElfN = ct_class.ElfN();3486 const ElfN = ct_class.ElfN();
...@@ -2478,9 +3491,9 @@ fn prelinkInner(elf: *Elf) !void {...@@ -2478,9 +3491,9 @@ fn prelinkInner(elf: *Elf) !void {
2478 @intFromBool(flags != 0) + @intFromBool(flags_1 != 0) +3491 @intFromBool(flags != 0) + @intFromBool(flags_1 != 0) +
2479 @intFromBool(comp.config.output_mode == .Exe) + 12;3492 @intFromBool(comp.config.output_mode == .Exe) + 12;
2480 const dynamic_size: u32 = @intCast(@sizeOf(ElfN.Addr) * 2 * dynamic_len);3493 const dynamic_size: u32 = @intCast(@sizeOf(ElfN.Addr) * 2 * dynamic_len);
2481 const dynamic_ni = elf.si.dynamic.node(elf);3494 const dynamic_ni = elf.shndx.dynamic.get(elf).ni;
2482 try dynamic_ni.resize(&elf.mf, gpa, dynamic_size);3495 try dynamic_ni.resize(&elf.mf, gpa, dynamic_size);
2483 switch (elf.shdrPtr(elf.si.dynamic.shndx(elf))) {3496 switch (elf.shdrPtr(elf.shndx.dynamic)) {
2484 inline else => |shdr| elf.targetStore(&shdr.size, dynamic_size),3497 inline else => |shdr| elf.targetStore(&shdr.size, dynamic_size),
2485 }3498 }
2486 const sec_dynamic = dynamic_ni.slice(&elf.mf);3499 const sec_dynamic = dynamic_ni.slice(&elf.mf);
...@@ -2489,10 +3502,10 @@ fn prelinkInner(elf: *Elf) !void {...@@ -2489,10 +3502,10 @@ fn prelinkInner(elf: *Elf) !void {
2489 for (3502 for (
2490 dynamic_entries[dynamic_index..][0..needed_len],3503 dynamic_entries[dynamic_index..][0..needed_len],
2491 elf.needed.keys(),3504 elf.needed.keys(),
2492 ) |*dynamic_entry, needed| dynamic_entry.* = .{ std.elf.DT_NEEDED, needed };3505 ) |*dynamic_entry, needed| dynamic_entry.* = .{ std.elf.DT_NEEDED, @intFromEnum(needed) };
2493 dynamic_index += needed_len;3506 dynamic_index += needed_len;
2494 if (elf.options.soname) |soname| {3507 if (elf.options.soname) |soname| {
2495 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)) };
2496 dynamic_index += 1;3509 dynamic_index += 1;
2497 }3510 }
2498 if (flags != 0) {3511 if (flags != 0) {
...@@ -2507,25 +3520,25 @@ fn prelinkInner(elf: *Elf) !void {...@@ -2507,25 +3520,25 @@ fn prelinkInner(elf: *Elf) !void {
2507 dynamic_entries[dynamic_index] = .{ std.elf.DT_DEBUG, 0 };3520 dynamic_entries[dynamic_index] = .{ std.elf.DT_DEBUG, 0 };
2508 dynamic_index += 1;3521 dynamic_index += 1;
2509 }3522 }
2510 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;
2511 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;
2512 dynamic_entries[dynamic_index..][0..12].* = .{3525 dynamic_entries[dynamic_index..][0..12].* = .{
2513 .{ 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)) },
2514 .{ std.elf.DT_RELASZ, elf.targetLoad(3527 .{ std.elf.DT_RELASZ, elf.targetLoad(
2515 &@field(elf.shdrPtr(rela_dyn_si.shndx(elf)), @tagName(ct_class)).size,3528 &@field(elf.shdrPtr(rela_dyn_shndx), @tagName(ct_class)).size,
2516 ) },3529 ) },
2517 .{ std.elf.DT_RELAENT, @sizeOf(ElfN.Rela) },3530 .{ std.elf.DT_RELAENT, @sizeOf(ElfN.Rela) },
2518 .{ 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)) },
2519 .{ std.elf.DT_PLTRELSZ, elf.targetLoad(3532 .{ std.elf.DT_PLTRELSZ, elf.targetLoad(
2520 &@field(elf.shdrPtr(rela_plt_si.shndx(elf)), @tagName(ct_class)).size,3533 &@field(elf.shdrPtr(rela_plt_shndx), @tagName(ct_class)).size,
2521 ) },3534 ) },
2522 .{ 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)) },
2523 .{ std.elf.DT_PLTREL, std.elf.DT_RELA },3536 .{ std.elf.DT_PLTREL, std.elf.DT_RELA },
2524 .{ 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)) },
2525 .{ std.elf.DT_SYMENT, @sizeOf(ElfN.Sym) },3538 .{ std.elf.DT_SYMENT, @sizeOf(ElfN.Sym) },
2526 .{ 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)) },
2527 .{ std.elf.DT_STRSZ, elf.targetLoad(3540 .{ std.elf.DT_STRSZ, elf.targetLoad(
2528 &@field(elf.shdrPtr(elf.si.dynstr.shndx(elf)), @tagName(ct_class)).size,3541 &@field(elf.shdrPtr(elf.shndx.dynstr), @tagName(ct_class)).size,
2529 ) },3542 ) },
2530 .{ std.elf.DT_NULL, 0 },3543 .{ std.elf.DT_NULL, 0 },
2531 };3544 };
...@@ -2534,42 +3547,40 @@ fn prelinkInner(elf: *Elf) !void {...@@ -2534,42 +3547,40 @@ fn prelinkInner(elf: *Elf) !void {
2534 if (elf.targetEndian() != native_endian) for (dynamic_entries) |*dynamic_entry|3547 if (elf.targetEndian() != native_endian) for (dynamic_entries) |*dynamic_entry|
2535 std.mem.byteSwapAllFields(@TypeOf(dynamic_entry.*), dynamic_entry);3548 std.mem.byteSwapAllFields(@TypeOf(dynamic_entry.*), dynamic_entry);
25363549
2537 const dynamic_sym = elf.si.dynamic.get(elf);3550 elf.first_dynamic_reloc = @enumFromInt(elf.relocs.items.len);
2538 assert(dynamic_sym.loc_relocs == .none);3551 try elf.ensureUnusedRelocCapacity(dynamic_ni, 5);
2539 dynamic_sym.loc_relocs = @enumFromInt(elf.relocs.items.len);
2540 try elf.ensureUnusedRelocCapacity(elf.si.dynamic, 5);
2541 elf.addRelocAssumeCapacity(3552 elf.addRelocAssumeCapacity(
2542 elf.si.dynamic,3553 dynamic_ni,
2543 @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 12) + 1),3554 @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 12) + 1),
2544 rela_dyn_si,3555 .local(rela_dyn_shndx.get(elf).lsi),
2545 0,3556 0,
2546 .absAddr(elf),3557 .absAddr(elf),
2547 );3558 );
2548 elf.addRelocAssumeCapacity(3559 elf.addRelocAssumeCapacity(
2549 elf.si.dynamic,3560 dynamic_ni,
2550 @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 9) + 1),3561 @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 9) + 1),
2551 rela_plt_si,3562 .local(rela_plt_shndx.get(elf).lsi),
2552 0,3563 0,
2553 .absAddr(elf),3564 .absAddr(elf),
2554 );3565 );
2555 elf.addRelocAssumeCapacity(3566 elf.addRelocAssumeCapacity(
2556 elf.si.dynamic,3567 dynamic_ni,
2557 @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 7) + 1),3568 @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 7) + 1),
2558 elf.si.got_plt,3569 .local(elf.shndx.got_plt.get(elf).lsi),
2559 0,3570 0,
2560 .absAddr(elf),3571 .absAddr(elf),
2561 );3572 );
2562 elf.addRelocAssumeCapacity(3573 elf.addRelocAssumeCapacity(
2563 elf.si.dynamic,3574 dynamic_ni,
2564 @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 5) + 1),3575 @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 5) + 1),
2565 elf.si.dynsym,3576 .local(elf.shndx.dynsym.get(elf).lsi),
2566 0,3577 0,
2567 .absAddr(elf),3578 .absAddr(elf),
2568 );3579 );
2569 elf.addRelocAssumeCapacity(3580 elf.addRelocAssumeCapacity(
2570 elf.si.dynamic,3581 dynamic_ni,
2571 @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 3) + 1),3582 @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 3) + 1),
2572 elf.si.dynstr,3583 .local(elf.shndx.dynstr.get(elf).lsi),
2573 0,3584 0,
2574 .absAddr(elf),3585 .absAddr(elf),
2575 );3586 );
...@@ -2577,36 +3588,6 @@ fn prelinkInner(elf: *Elf) !void {...@@ -2577,36 +3588,6 @@ fn prelinkInner(elf: *Elf) !void {
2577 };3588 };
2578}3589}
25793590
2580pub fn getNavVAddr(
2581 elf: *Elf,
2582 pt: Zcu.PerThread,
2583 nav: InternPool.Nav.Index,
2584 reloc_info: link.File.RelocInfo,
2585) !u64 {
2586 return elf.getVAddr(reloc_info, try elf.navSymbol(pt.zcu, nav));
2587}
2588
2589pub fn getUavVAddr(
2590 elf: *Elf,
2591 uav: InternPool.Index,
2592 reloc_info: link.File.RelocInfo,
2593) !u64 {
2594 return elf.getVAddr(reloc_info, try elf.uavSymbol(uav));
2595}
2596
2597pub fn getVAddr(elf: *Elf, reloc_info: link.File.RelocInfo, target_si: Symbol.Index) !u64 {
2598 try elf.addReloc(
2599 @enumFromInt(reloc_info.parent.atom_index),
2600 reloc_info.offset,
2601 target_si,
2602 reloc_info.addend,
2603 .absAddr(elf),
2604 );
2605 return switch (elf.symPtr(target_si)) {
2606 inline else => |sym| elf.targetLoad(&sym.value),
2607 };
2608}
2609
2610fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {3591fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
2611 name: []const u8 = "",3592 name: []const u8 = "",
2612 type: std.elf.SHT = .NULL,3593 type: std.elf.SHT = .NULL,
...@@ -2618,19 +3599,22 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {...@@ -2618,19 +3599,22 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
2618 entsize: std.elf.Word = 0,3599 entsize: std.elf.Word = 0,
2619 node_align: std.mem.Alignment = .@"1",3600 node_align: std.mem.Alignment = .@"1",
2620 fixed: bool = false,3601 fixed: bool = false,
2621}) !Symbol.Index {3602}) !Section.Index {
2622 switch (opts.type) {3603 switch (opts.type) {
2623 .NULL => assert(opts.size == 0),3604 .NULL => assert(opts.size == 0),
2624 .PROGBITS => assert(opts.size > 0),3605 .PROGBITS => assert(opts.size > 0),
2625 else => {},3606 else => {},
2626 }3607 }
3608 if (opts.flags.ALLOC and elf.ehdrField(.type) != .REL) {
3609 assert(elf.getNode(segment_ni) == .segment);
3610 }
2627 const gpa = elf.base.comp.gpa;3611 const gpa = elf.base.comp.gpa;
2628 try elf.nodes.ensureUnusedCapacity(gpa, 1);3612 try elf.nodes.ensureUnusedCapacity(gpa, 1);
2629 try elf.shdrs.ensureUnusedCapacity(gpa, 1);3613 try elf.shdrs.ensureUnusedCapacity(gpa, 1);
2630 try elf.symtab.ensureUnusedCapacity(gpa, 1);3614 if (opts.flags.ALLOC) try elf.ensureUnusedSymbolCapacity(1, .all_local);
26313615
2632 const shstrtab_entry = try elf.string(.shstrtab, opts.name);3616 const shstrtab_entry = try elf.string(.shstrtab, opts.name);
2633 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()) {
2634 inline else => |ehdr, class| {3618 inline else => |ehdr, class| {
2635 const shndx, const shnum = alloc_shndx: switch (elf.targetLoad(&ehdr.shnum)) {3619 const shndx, const shnum = alloc_shndx: switch (elf.targetLoad(&ehdr.shnum)) {
2636 1...std.elf.SHN_LORESERVE - 2 => |shndx| {3620 1...std.elf.SHN_LORESERVE - 2 => |shndx| {
...@@ -2653,7 +3637,7 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {...@@ -2653,7 +3637,7 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
2653 break :alloc_shndx .{ shndx, shnum };3637 break :alloc_shndx .{ shndx, shnum };
2654 },3638 },
2655 };3639 };
2656 assert(shndx < @intFromEnum(Symbol.Index.Shndx.LORESERVE));3640 assert(shndx < @intFromEnum(Section.Index.LORESERVE));
2657 break :shndx .{ @enumFromInt(shndx), elf.targetLoad(&ehdr.shentsize) * shnum };3641 break :shndx .{ @enumFromInt(shndx), elf.targetLoad(&ehdr.shentsize) * shnum };
2658 },3642 },
2659 };3643 };
...@@ -2670,17 +3654,22 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {...@@ -2670,17 +3654,22 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
2670 .fixed = opts.fixed,3654 .fixed = opts.fixed,
2671 .resized = opts.size > 0,3655 .resized = opts.size > 0,
2672 });3656 });
2673 const si = elf.addSymbolAssumeCapacity();
2674 elf.nodes.appendAssumeCapacity(.{ .section = si });
2675 elf.shdrs.appendAssumeCapacity(.{ .si = si, .rela_si = .null, .rela_free = .none });
2676 si.get(elf).ni = ni;
2677 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 });
2678 const offset = ni.fileLocation(&elf.mf, false).offset;3668 const offset = ni.fileLocation(&elf.mf, false).offset;
2679 try si.init(elf, .{ .value = addr, .type = .SECTION, .shndx = shndx });
2680 switch (elf.shdrPtr(shndx)) {3669 switch (elf.shdrPtr(shndx)) {
2681 inline else => |shdr, class| {3670 inline else => |shdr, class| {
2682 shdr.* = .{3671 shdr.* = .{
2683 .name = shstrtab_entry,3672 .name = @intFromEnum(shstrtab_entry),
2684 .type = opts.type,3673 .type = opts.type,
2685 .flags = .{ .shf = opts.flags },3674 .flags = .{ .shf = opts.flags },
2686 .addr = @intCast(addr),3675 .addr = @intCast(addr),
...@@ -2694,63 +3683,31 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {...@@ -2694,63 +3683,31 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
2694 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);
2695 },3684 },
2696 }3685 }
2697 return si;3686 return shndx;
2698}
2699
2700fn renameSection(elf: *Elf, si: Symbol.Index, name: []const u8) !void {
2701 const shstrtab_entry = try elf.string(.shstrtab, name);
2702 switch (elf.shdrPtr(si.shndx(elf))) {
2703 inline else => |shdr| elf.targetStore(&shdr.name, shstrtab_entry),
2704 }
2705}
2706
2707fn sectionName(elf: *Elf, si: Symbol.Index) [:0]const u8 {
2708 const name = elf.si.shstrtab.node(elf).slice(&elf.mf)[switch (elf.shdrPtr(si.shndx(elf))) {
2709 inline else => |shdr| elf.targetLoad(&shdr.name),
2710 }..];
2711 return name[0..std.mem.indexOfScalar(u8, name, 0).? :0];
2712}
2713
2714fn string(elf: *Elf, comptime section: enum { shstrtab, strtab, dynstr }, key: []const u8) !u32 {
2715 if (key.len == 0) return 0;
2716 return @field(elf, @tagName(section)).get(elf, @field(elf.si, @tagName(section)), key);
2717}3687}
27183688
2719pub fn addReloc(3689fn ensureUnusedRelocCapacity(elf: *Elf, node: MappedFile.Node.Index, len: usize) !void {
2720 elf: *Elf,
2721 loc_si: Symbol.Index,
2722 offset: u64,
2723 target_si: Symbol.Index,
2724 addend: i64,
2725 @"type": Reloc.Type,
2726) !void {
2727 try elf.ensureUnusedRelocCapacity(loc_si, 1);
2728 elf.addRelocAssumeCapacity(loc_si, offset, target_si, addend, @"type");
2729}
2730pub fn ensureUnusedRelocCapacity(elf: *Elf, loc_si: Symbol.Index, len: usize) !void {
2731 if (len == 0) return;3690 if (len == 0) return;
2732 const gpa = elf.base.comp.gpa;3691 const gpa = elf.base.comp.gpa;
2733 try elf.relocs.ensureUnusedCapacity(gpa, len);3692 try elf.relocs.ensureUnusedCapacity(gpa, len);
2734 const class = elf.identClass();3693 const class = elf.identClass();
2735 const rela_si, const rela_len = rela: switch (elf.ehdrField(.type)) {3694 const rela_shndx, const rela_len = rela: switch (elf.ehdrField(.type)) {
2736 .NONE, .CORE, _ => unreachable,3695 .NONE, .CORE, _ => unreachable,
2737 .REL => {3696 .REL => {
2738 const shndx = loc_si.shndx(elf);3697 const shndx = elf.getNodeShndx(node);
2739 const sh = shndx.get(elf);3698 if (shndx.get(elf).rela_shndx == .UNDEF) {
2740 if (sh.rela_si == .null) {
2741 var bfa_buf: [32]u8 = undefined;3699 var bfa_buf: [32]u8 = undefined;
2742 var bfa: std.heap.BufferFirstAllocator = .init(&bfa_buf, gpa);3700 var bfa: std.heap.BufferFirstAllocator = .init(&bfa_buf, gpa);
2743 const allocator = bfa.allocator();3701 const allocator = bfa.allocator();
27443702
2745 const rela_name =3703 const rela_name = try std.fmt.allocPrint(allocator, ".rela{s}", .{shndx.name(elf)});
2746 try std.fmt.allocPrint(allocator, ".rela{s}", .{elf.sectionName(sh.si)});
2747 defer allocator.free(rela_name);3704 defer allocator.free(rela_name);
27483705
2749 sh.rela_si = try elf.addSection(.none, .{3706 const rela_shndx = try elf.addSection(.none, .{
2750 .name = rela_name,3707 .name = rela_name,
2751 .type = .RELA,3708 .type = .RELA,
2752 .link = @intFromEnum(elf.si.symtab.shndx(elf)),3709 .link = @intFromEnum(Section.Index.symtab),
2753 .info = @intFromEnum(shndx),3710 .info = shndx.toSection().?,
2754 .addralign = switch (class) {3711 .addralign = switch (class) {
2755 .NONE, _ => unreachable,3712 .NONE, _ => unreachable,
2756 .@"32" => .@"4",3713 .@"32" => .@"4",
...@@ -2762,14 +3719,15 @@ pub fn ensureUnusedRelocCapacity(elf: *Elf, loc_si: Symbol.Index, len: usize) !v...@@ -2762,14 +3719,15 @@ pub fn ensureUnusedRelocCapacity(elf: *Elf, loc_si: Symbol.Index, len: usize) !v
2762 },3719 },
2763 .node_align = elf.mf.flags.block_size,3720 .node_align = elf.mf.flags.block_size,
2764 });3721 });
3722 shndx.get(elf).rela_shndx = rela_shndx;
2765 }3723 }
2766 break :rela .{ sh.rela_si, len };3724 break :rela .{ shndx.get(elf).rela_shndx, len };
2767 },3725 },
2768 .EXEC, .DYN => switch (elf.got.tlsld) {3726 .EXEC, .DYN => switch (elf.got.tlsld) {
2769 _ => return,3727 _ => return,
2770 .none => if (elf.si.dynamic != .null) {3728 .none => if (elf.shndx.dynamic != .UNDEF) {
2771 try elf.mf.updates.ensureUnusedCapacity(gpa, 1);3729 try elf.mf.updates.ensureUnusedCapacity(gpa, 1);
2772 const got_ni = elf.si.got.node(elf);3730 const got_ni = elf.shndx.got.get(elf).ni;
2773 _, 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);
2774 const got_size = switch (class) {3732 const got_size = switch (class) {
2775 .NONE, _ => unreachable,3733 .NONE, _ => unreachable,
...@@ -2777,43 +3735,52 @@ pub fn ensureUnusedRelocCapacity(elf: *Elf, loc_si: Symbol.Index, len: usize) !v...@@ -2777,43 +3735,52 @@ pub fn ensureUnusedRelocCapacity(elf: *Elf, loc_si: Symbol.Index, len: usize) !v
2777 };3735 };
2778 if (got_size > got_node_size)3736 if (got_size > got_node_size)
2779 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);
2780 break :rela .{ elf.si.got.shndx(elf).get(elf).rela_si, 1 };3738 break :rela .{ elf.shndx.got.get(elf).rela_shndx, 1 };
2781 } else return,3739 } else return,
2782 },3740 },
2783 };3741 };
2784 const rela_ni = rela_si.node(elf);3742 const rela_ni = rela_shndx.get(elf).ni;
2785 _, 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);
2786 const rela_size = switch (elf.shdrPtr(rela_si.shndx(elf))) {3744 const rela_size = switch (elf.shdrPtr(rela_shndx)) {
2787 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,
2788 };3746 };
2789 if (rela_size > rela_node_size)3747 if (rela_size > rela_node_size)
2790 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);
2791}3749}
2792pub fn addRelocAssumeCapacity(3750fn addRelocAssumeCapacity(
2793 elf: *Elf,3751 elf: *Elf,
2794 loc_si: Symbol.Index,3752 node: MappedFile.Node.Index,
2795 offset: u64,3753 offset: u64,
2796 target_si: Symbol.Index,3754 target: Symbol.Id,
2797 addend: i64,3755 addend: i64,
2798 @"type": Reloc.Type,3756 @"type": Reloc.Type,
2799) void {3757) void {
2800 const target = target_si.get(elf);3758 assert(node != .none);
2801 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 }
2802 elf.relocs.addOneAssumeCapacity().* = .{3769 elf.relocs.addOneAssumeCapacity().* = .{
2803 .type = @"type",3770 .type = @"type",
2804 .prev = .none,3771 .prev = .none,
2805 .next = target.target_relocs,3772 .next = next,
2806 .loc = loc_si,3773 .node = node,
2807 .target = target_si,3774 .target = target,
2808 .index = index: switch (elf.ehdrField(.type)) {3775 .index = index: switch (elf.ehdrField(.type)) {
2809 .NONE, .CORE, _ => unreachable,3776 .NONE, .CORE, _ => unreachable,
2810 .REL => {3777 .REL => {
2811 const sh = loc_si.shndx(elf).get(elf);3778 const sh = elf.getNodeShndx(node).get(elf);
2812 switch (elf.shdrPtr(sh.rela_si.shndx(elf))) {3779 switch (elf.shdrPtr(sh.rela_shndx)) {
2813 inline else => |shdr, class| {3780 inline else => |shdr, class| {
2814 const Rela = class.ElfN().Rela;3781 const Rela = class.ElfN().Rela;
2815 const ent_size = elf.targetLoad(&shdr.entsize);3782 const ent_size = elf.targetLoad(&shdr.entsize);
2816 const rela_slice = sh.rela_si.node(elf).slice(&elf.mf);3783 const rela_slice = sh.rela_shndx.get(elf).ni.slice(&elf.mf);
2817 const index: u32 = if (sh.rela_free.unwrap()) |index| alloc_index: {3784 const index: u32 = if (sh.rela_free.unwrap()) |index| alloc_index: {
2818 const rela: *Rela = @ptrCast(@alignCast(3785 const rela: *Rela = @ptrCast(@alignCast(
2819 rela_slice[@intCast(ent_size * index)..][0..@intCast(ent_size)],3786 rela_slice[@intCast(ent_size * index)..][0..@intCast(ent_size)],
...@@ -2829,11 +3796,15 @@ pub fn addRelocAssumeCapacity(...@@ -2829,11 +3796,15 @@ pub fn addRelocAssumeCapacity(
2829 const rela: *Rela = @ptrCast(@alignCast(3796 const rela: *Rela = @ptrCast(@alignCast(
2830 rela_slice[@intCast(ent_size * index)..][0..@intCast(ent_size)],3797 rela_slice[@intCast(ent_size * index)..][0..@intCast(ent_size)],
2831 ));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.
2832 rela.* = .{3803 rela.* = .{
2833 .offset = @intCast(offset),3804 .offset = 0,
2834 .info = .{3805 .info = .{
2835 .type = @intCast(@"type".unwrap(elf)),3806 .type = @intCast(@"type".unwrap(elf)),
2836 .sym = @intCast(@intFromEnum(target_si)),3807 .sym = @intCast(@intFromEnum(target.index(elf))),
2837 },3808 },
2838 .addend = @intCast(addend),3809 .addend = @intCast(addend),
2839 };3810 };
...@@ -2850,25 +3821,25 @@ pub fn addRelocAssumeCapacity(...@@ -2850,25 +3821,25 @@ pub fn addRelocAssumeCapacity(
2850 else => {},3821 else => {},
2851 .TLSLD => switch (elf.got.tlsld) {3822 .TLSLD => switch (elf.got.tlsld) {
2852 _ => {},3823 _ => {},
2853 .none => if (elf.si.dynamic != .null) {3824 .none => if (elf.shndx.dynamic != .UNDEF) {
2854 const tlsld_index = elf.got.len;3825 const tlsld_index = elf.got.len;
2855 elf.got.tlsld = .wrap(tlsld_index);3826 elf.got.tlsld = .wrap(tlsld_index);
2856 elf.got.len = tlsld_index + 2;3827 elf.got.len = tlsld_index + 2;
2857 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)) {
2858 inline else => |shdr, class| {3829 inline else => |shdr, class| {
2859 const addr_size = @sizeOf(class.ElfN().Addr);3830 const addr_size = @sizeOf(class.ElfN().Addr);
2860 const old_size = addr_size * tlsld_index;3831 const old_size = addr_size * tlsld_index;
2861 const new_size = old_size + addr_size * 2;3832 const new_size = old_size + addr_size * 2;
2862 @memset(3833 @memset(
2863 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],
2864 0,3835 0,
2865 );3836 );
2866 break :got_addr elf.targetLoad(&shdr.addr) + old_size;3837 break :got_addr elf.targetLoad(&shdr.addr) + old_size;
2867 },3838 },
2868 };3839 };
2869 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;
2870 const rela_dyn_ni = rela_dyn_si.node(elf);3841 const rela_dyn_ni = rela_dyn_shndx.get(elf).ni;
2871 switch (elf.shdrPtr(rela_dyn_si.shndx(elf))) {3842 switch (elf.shdrPtr(rela_dyn_shndx)) {
2872 inline else => |shdr, class| {3843 inline else => |shdr, class| {
2873 const Rela = class.ElfN().Rela;3844 const Rela = class.ElfN().Rela;
2874 const old_size = elf.targetLoad(&shdr.size);3845 const old_size = elf.targetLoad(&shdr.size);
...@@ -2899,11 +3870,6 @@ pub fn addRelocAssumeCapacity(...@@ -2899,11 +3870,6 @@ pub fn addRelocAssumeCapacity(
2899 .offset = offset,3870 .offset = offset,
2900 .addend = addend,3871 .addend = addend,
2901 };3872 };
2902 switch (target.target_relocs) {
2903 .none => {},
2904 else => |target_ri| target_ri.get(elf).prev = ri,
2905 }
2906 target.target_relocs = ri;
2907}3873}
29083874
2909pub 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 {
...@@ -2925,30 +3891,12 @@ fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index)...@@ -2925,30 +3891,12 @@ fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index)
2925 if (!Type.fromInterned(nav.resolved.?.type).hasRuntimeBits(zcu)) return;3891 if (!Type.fromInterned(nav.resolved.?.type).hasRuntimeBits(zcu)) return;
29263892
2927 const nmi = try elf.navMapIndex(zcu, nav_index);3893 const nmi = try elf.navMapIndex(zcu, nav_index);
2928 const si = nmi.symbol(elf);3894 const ni = nmi.symbol(elf).index().ptr(elf).node;
2929 const ni = ni: {3895 elf.resetNodeRelocs(ni);
2930 const sym = si.get(elf);3896
2931 switch (sym.ni) {3897 // Ensure the NAV is marked as moved so that once we're done, `flushMoved` will eventually be
2932 .none => {3898 // called to apply the NAV's new relocations.
2933 try elf.nodes.ensureUnusedCapacity(gpa, 1);3899 try ni.moved(gpa, &elf.mf);
2934 const sec_si = elf.navSection(ip, nav.resolved.?);
2935 const ni = try elf.mf.addLastChildNode(gpa, sec_si.node(elf), .{
2936 .alignment = zcu.navAlignment(nav_index).toStdMem(),
2937 .moved = true,
2938 });
2939 elf.nodes.appendAssumeCapacity(.{ .nav = nmi });
2940 sym.ni = ni;
2941 switch (elf.symPtr(si)) {
2942 inline else => |sym_ptr, class| sym_ptr.shndx =
2943 @field(elf.symPtr(sec_si), @tagName(class)).shndx,
2944 }
2945 },
2946 else => si.deleteLocationRelocs(elf),
2947 }
2948 assert(sym.loc_relocs == .none);
2949 sym.loc_relocs = @enumFromInt(elf.relocs.items.len);
2950 break :ni sym.ni;
2951 };
29523900
2953 var nw: MappedFile.Node.Writer = undefined;3901 var nw: MappedFile.Node.Writer = undefined;
2954 ni.writer(&elf.mf, gpa, &nw);3902 ni.writer(&elf.mf, gpa, &nw);
...@@ -2959,54 +3907,14 @@ fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index)...@@ -2959,54 +3907,14 @@ fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index)
2959 zcu.navSrcLoc(nav_index),3907 zcu.navSrcLoc(nav_index),
2960 .fromInterned(nav.resolved.?.value),3908 .fromInterned(nav.resolved.?.value),
2961 &nw.interface,3909 &nw.interface,
2962 .{ .atom_index = @intFromEnum(si) },3910 .{ .atom_index = Node.toAtom(ni) },
2963 ) catch |err| switch (err) {3911 ) catch |err| switch (err) {
2964 error.WriteFailed => return error.OutOfMemory,3912 error.WriteFailed => return error.OutOfMemory,
2965 else => |e| return e,3913 else => |e| return e,
2966 };3914 };
2967 switch (elf.symPtr(si)) {3915 switch (elf.symPtr(nmi.symbol(elf).index())) {
2968 inline else => |sym| elf.targetStore(&sym.size, @intCast(nw.interface.end)),3916 inline else => |sym| elf.targetStore(&sym.size, @intCast(nw.interface.end)),
2969 }3917 }
2970 si.applyLocationRelocs(elf);
2971}
2972
2973pub fn lowerUav(
2974 elf: *Elf,
2975 pt: Zcu.PerThread,
2976 uav_val: InternPool.Index,
2977 uav_align: InternPool.Alignment,
2978 src_loc: Zcu.LazySrcLoc,
2979) !codegen.SymbolResult {
2980 const zcu = pt.zcu;
2981 const gpa = zcu.gpa;
2982
2983 try elf.pending_uavs.ensureUnusedCapacity(gpa, 1);
2984 const umi = elf.uavMapIndex(uav_val) catch |err| switch (err) {
2985 error.OutOfMemory => |e| return e,
2986 else => |e| return .{ .fail = try Zcu.ErrorMsg.create(
2987 gpa,
2988 src_loc,
2989 "linker failed to update constant: {s}",
2990 .{@errorName(e)},
2991 ) },
2992 };
2993 const si = umi.symbol(elf);
2994 if (switch (si.get(elf).ni) {
2995 .none => true,
2996 else => |ni| uav_align.toStdMem().order(ni.alignment(&elf.mf)).compare(.gt),
2997 }) {
2998 const gop = elf.pending_uavs.getOrPutAssumeCapacity(umi);
2999 if (gop.found_existing) {
3000 gop.value_ptr.alignment = gop.value_ptr.alignment.max(uav_align);
3001 } else {
3002 gop.value_ptr.* = .{
3003 .alignment = uav_align,
3004 .src_loc = src_loc,
3005 };
3006 elf.const_prog_node.increaseEstimatedTotalItems(1);
3007 }
3008 }
3009 return .{ .sym_index = @intFromEnum(si) };
3010}3918}
30113919
3012pub fn updateFunc(3920pub fn updateFunc(
...@@ -3041,42 +3949,13 @@ fn updateFuncInner(...@@ -3041,42 +3949,13 @@ fn updateFuncInner(
3041 const nav = ip.getNav(func.owner_nav);3949 const nav = ip.getNav(func.owner_nav);
30423950
3043 const nmi = try elf.navMapIndex(zcu, func.owner_nav);3951 const nmi = try elf.navMapIndex(zcu, func.owner_nav);
3044 const si = nmi.symbol(elf);3952 log.debug("updateFunc({f}) = {d}", .{ nav.fqn.fmt(ip), nmi.symbol(elf) });
3045 log.debug("updateFunc({f}) = {d}", .{ nav.fqn.fmt(ip), si });3953 const ni = nmi.symbol(elf).index().ptr(elf).node;
3046 const ni = ni: {3954 elf.resetNodeRelocs(ni);
3047 const sym = si.get(elf);3955
3048 switch (sym.ni) {3956 // Ensure the NAV is marked as moved so that once we're done, `flushMoved` will eventually be
3049 .none => {3957 // called to apply the NAV's new relocations.
3050 try elf.nodes.ensureUnusedCapacity(gpa, 1);3958 try ni.moved(gpa, &elf.mf);
3051 const sec_si = elf.navSection(ip, nav.resolved.?);
3052 const mod = zcu.navFileScope(func.owner_nav).mod.?;
3053 const target = &mod.resolved_target.result;
3054 const ni = try elf.mf.addLastChildNode(gpa, sec_si.node(elf), .{
3055 .alignment = switch (nav.resolved.?.@"align") {
3056 .none => switch (mod.optimize_mode) {
3057 .Debug,
3058 .ReleaseSafe,
3059 .ReleaseFast,
3060 => target_util.defaultFunctionAlignment(target),
3061 .ReleaseSmall => target_util.minFunctionAlignment(target),
3062 },
3063 else => |a| a.maxStrict(target_util.minFunctionAlignment(target)),
3064 }.toStdMem(),
3065 .moved = true,
3066 });
3067 elf.nodes.appendAssumeCapacity(.{ .nav = nmi });
3068 sym.ni = ni;
3069 switch (elf.symPtr(si)) {
3070 inline else => |sym_ptr, class| sym_ptr.shndx =
3071 @field(elf.symPtr(sec_si), @tagName(class)).shndx,
3072 }
3073 },
3074 else => si.deleteLocationRelocs(elf),
3075 }
3076 assert(sym.loc_relocs == .none);
3077 sym.loc_relocs = @enumFromInt(elf.relocs.items.len);
3078 break :ni sym.ni;
3079 };
30803959
3081 var nw: MappedFile.Node.Writer = undefined;3960 var nw: MappedFile.Node.Writer = undefined;
3082 ni.writer(&elf.mf, gpa, &nw);3961 ni.writer(&elf.mf, gpa, &nw);
...@@ -3086,7 +3965,7 @@ fn updateFuncInner(...@@ -3086,7 +3965,7 @@ fn updateFuncInner(
3086 pt,3965 pt,
3087 zcu.navSrcLoc(func.owner_nav),3966 zcu.navSrcLoc(func.owner_nav),
3088 func_index,3967 func_index,
3089 @intFromEnum(si),3968 Node.toAtom(ni),
3090 mir,3969 mir,
3091 &nw.interface,3970 &nw.interface,
3092 .none,3971 .none,
...@@ -3094,10 +3973,9 @@ fn updateFuncInner(...@@ -3094,10 +3973,9 @@ fn updateFuncInner(
3094 error.WriteFailed => return nw.err.?,3973 error.WriteFailed => return nw.err.?,
3095 else => |e| return e,3974 else => |e| return e,
3096 };3975 };
3097 switch (elf.symPtr(si)) {3976 switch (elf.symPtr(nmi.symbol(elf).index())) {
3098 inline else => |sym| elf.targetStore(&sym.size, @intCast(nw.interface.end)),3977 inline else => |sym| elf.targetStore(&sym.size, @intCast(nw.interface.end)),
3099 }3978 }
3100 si.applyLocationRelocs(elf);
3101}3979}
31023980
3103pub fn updateErrorData(elf: *Elf, pt: Zcu.PerThread) !void {3981pub fn updateErrorData(elf: *Elf, pt: Zcu.PerThread) !void {
...@@ -3120,7 +3998,42 @@ pub fn flush(...@@ -3120,7 +3998,42 @@ pub fn flush(
3120 const comp = elf.base.comp;3998 const comp = elf.base.comp;
3121 _ = arena;3999 _ = arena;
3122 _ = 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
3123 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
3124 elf.mf.flush() catch |err| switch (err) {4037 elf.mf.flush() catch |err| switch (err) {
3125 error.Canceled => |e| return e,4038 error.Canceled => |e| return e,
3126 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}),
...@@ -3130,15 +4043,10 @@ pub fn flush(...@@ -3130,15 +4043,10 @@ pub fn flush(
3130pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool {4043pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool {
3131 const comp = elf.base.comp;4044 const comp = elf.base.comp;
3132 task: {4045 task: {
3133 while (elf.pending_uavs.pop()) |pending_uav| {4046 while (elf.pending_uavs.pop()) |umi| {
3134 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 });
3135 defer sub_prog_node.end();4048 defer sub_prog_node.end();
3136 elf.flushUav(4049 elf.flushUav(.{ .zcu = comp.zcu.?, .tid = tid }, umi) catch |err| switch (err) {
3137 .{ .zcu = comp.zcu.?, .tid = tid },
3138 pending_uav.key,
3139 pending_uav.value.alignment,
3140 pending_uav.value.src_loc,
3141 ) catch |err| switch (err) {
3142 error.OutOfMemory => |e| return e,4050 error.OutOfMemory => |e| return e,
3143 else => |e| return comp.link_diags.fail(4051 else => |e| return comp.link_diags.fail(
3144 "linker failed to lower constant: {t}",4052 "linker failed to lower constant: {t}",
...@@ -3175,9 +4083,9 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool {...@@ -3175,9 +4083,9 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool {
3175 break :task;4083 break :task;
3176 };4084 };
3177 if (elf.input_section_pending_index < elf.input_sections.items.len) {4085 if (elf.input_section_pending_index < elf.input_sections.items.len) {
3178 const isi: Node.InputSectionIndex = @enumFromInt(elf.input_section_pending_index);4086 const isi: InputSection.Index = @enumFromInt(elf.input_section_pending_index);
3179 elf.input_section_pending_index += 1;4087 elf.input_section_pending_index += 1;
3180 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)));
3181 defer sub_prog_node.end();4089 defer sub_prog_node.end();
3182 elf.flushInputSection(isi) catch |err| switch (err) {4090 elf.flushInputSection(isi) catch |err| switch (err) {
3183 else => |e| {4091 else => |e| {
...@@ -3185,9 +4093,7 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool {...@@ -3185,9 +4093,7 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool {
3185 return comp.link_diags.fail(4093 return comp.link_diags.fail(
3186 "linker failed to read input section '{s}' from \"{f}{f}\": {t}",4094 "linker failed to read input section '{s}' from \"{f}{f}\": {t}",
3187 .{4095 .{
3188 elf.sectionName(4096 elf.getNode(isi.node(elf).parent(&elf.mf)).section.name(elf),
3189 elf.getNode(isi.symbol(elf).node(elf).parent(&elf.mf)).section,
3190 ),
3191 ii.path(elf).fmtEscapeString(),4097 ii.path(elf).fmtEscapeString(),
3192 fmtMemberString(ii.member(elf)),4098 fmtMemberString(ii.member(elf)),
3193 e,4099 e,
...@@ -3197,6 +4103,20 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool {...@@ -3197,6 +4103,20 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool {
3197 };4103 };
3198 break :task;4104 break :task;
3199 }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 }
3200 while (elf.mf.updates.pop()) |ni| {4120 while (elf.mf.updates.pop()) |ni| {
3201 const clean_moved = ni.cleanMoved(&elf.mf);4121 const clean_moved = ni.cleanMoved(&elf.mf);
3202 const clean_resized = ni.cleanResized(&elf.mf);4122 const clean_resized = ni.cleanResized(&elf.mf);
...@@ -3209,9 +4129,10 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool {...@@ -3209,9 +4129,10 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool {
3209 } else elf.mf.update_prog_node.completeOne();4129 } else elf.mf.update_prog_node.completeOne();
3210 }4130 }
3211 }4131 }
3212 if (elf.pending_uavs.count() > 0) return true;4132 if (elf.pending_uavs.items.len > 0) return true;
3213 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;
3214 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;
3215 if (elf.mf.updates.items.len > 0) return true;4136 if (elf.mf.updates.items.len > 0) return true;
3216 return false;4137 return false;
3217}4138}
...@@ -3225,13 +4146,13 @@ fn idleProgNode(...@@ -3225,13 +4146,13 @@ fn idleProgNode(
3225 var name: [std.Progress.Node.max_name_len]u8 = undefined;4146 var name: [std.Progress.Node.max_name_len]u8 = undefined;
3226 return prog_node.start(name: switch (node) {4147 return prog_node.start(name: switch (node) {
3227 else => |tag| @tagName(tag),4148 else => |tag| @tagName(tag),
3228 .section => |si| elf.sectionName(si),4149 .section => |shndx| shndx.name(elf),
3229 .input_section => |isi| {4150 .input_section => |isi| {
3230 const ii = isi.input(elf);4151 const ii = isi.input(elf);
3231 break :name std.fmt.bufPrint(&name, "{f}{f} {s}", .{4152 break :name std.fmt.bufPrint(&name, "{f}{f} {s}", .{
3232 ii.path(elf).fmtEscapeString(),4153 ii.path(elf).fmtEscapeString(),
3233 fmtMemberString(ii.member(elf)),4154 fmtMemberString(ii.member(elf)),
3234 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),
3235 }) catch &name;4156 }) catch &name;
3236 },4157 },
3237 .nav => |nmi| {4158 .nav => |nmi| {
...@@ -3248,59 +4169,43 @@ fn flushUav(...@@ -3248,59 +4169,43 @@ fn flushUav(
3248 elf: *Elf,4169 elf: *Elf,
3249 pt: Zcu.PerThread,4170 pt: Zcu.PerThread,
3250 umi: Node.UavMapIndex,4171 umi: Node.UavMapIndex,
3251 uav_align: InternPool.Alignment,
3252 src_loc: Zcu.LazySrcLoc,
3253) !void {4172) !void {
4173 const comp = elf.base.comp;
4174 const gpa = comp.gpa;
3254 const zcu = pt.zcu;4175 const zcu = pt.zcu;
3255 const gpa = zcu.gpa;
32564176
3257 const uav_val = umi.uavValue(elf);4177 const uav_val = umi.uavValue(elf);
3258 const si = umi.symbol(elf);4178 const ni = umi.symbol(elf).index().ptr(elf).node;
3259 const ni = ni: {4179 elf.resetNodeRelocs(ni);
3260 const sym = si.get(elf);
3261 switch (sym.ni) {
3262 .none => {
3263 try elf.nodes.ensureUnusedCapacity(gpa, 1);
3264 const sec_si = elf.si.data;
3265 const ni = try elf.mf.addLastChildNode(gpa, sec_si.node(elf), .{
3266 .alignment = uav_align.toStdMem(),
3267 .moved = true,
3268 });
3269 elf.nodes.appendAssumeCapacity(.{ .uav = umi });
3270 sym.ni = ni;
3271 switch (elf.symPtr(si)) {
3272 inline else => |sym_ptr, class| sym_ptr.shndx =
3273 @field(elf.symPtr(sec_si), @tagName(class)).shndx,
3274 }
3275 },
3276 else => {
3277 if (sym.ni.alignment(&elf.mf).order(uav_align.toStdMem()).compare(.gte)) return;
3278 si.deleteLocationRelocs(elf);
3279 },
3280 }
3281 assert(sym.loc_relocs == .none);
3282 sym.loc_relocs = @enumFromInt(elf.relocs.items.len);
3283 break :ni sym.ni;
3284 };
32854180
3286 var nw: MappedFile.Node.Writer = undefined;4181 var nw: MappedFile.Node.Writer = undefined;
3287 ni.writer(&elf.mf, gpa, &nw);4182 ni.writer(&elf.mf, gpa, &nw);
3288 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 };
3289 codegen.generateSymbol(4192 codegen.generateSymbol(
3290 &elf.base,4193 &elf.base,
3291 pt,4194 pt,
3292 src_loc,4195 dummy_src_loc,
3293 .fromInterned(uav_val),4196 .fromInterned(uav_val),
3294 &nw.interface,4197 &nw.interface,
3295 .{ .atom_index = @intFromEnum(si) },4198 .{ .atom_index = Node.toAtom(ni) },
3296 ) catch |err| switch (err) {4199 ) catch |err| switch (err) {
3297 error.WriteFailed => return error.OutOfMemory,4200 error.WriteFailed => return error.OutOfMemory,
3298 else => |e| return e,4201 else => |e| return e,
3299 };4202 };
3300 switch (elf.symPtr(si)) {4203 switch (elf.symPtr(umi.symbol(elf).index())) {
3301 inline else => |sym| elf.targetStore(&sym.size, @intCast(nw.interface.end)),4204 inline else => |sym| elf.targetStore(&sym.size, @intCast(nw.interface.end)),
3302 }4205 }
3303 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));
3304}4209}
33054210
3306fn flushLazy(elf: *Elf, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void {4211fn flushLazy(elf: *Elf, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void {
...@@ -3308,33 +4213,12 @@ fn flushLazy(elf: *Elf, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void {...@@ -3308,33 +4213,12 @@ fn flushLazy(elf: *Elf, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void {
3308 const gpa = zcu.gpa;4213 const gpa = zcu.gpa;
33094214
3310 const lazy = lmr.lazySymbol(elf);4215 const lazy = lmr.lazySymbol(elf);
3311 const si = lmr.symbol(elf);4216 const ni = lmr.symbol(elf).index().ptr(elf).node;
3312 const ni = ni: {4217 elf.resetNodeRelocs(ni);
3313 const sym = si.get(elf);4218
3314 switch (sym.ni) {4219 // Ensure the lazy node is marked as moved so that once we're done, `flushMoved` will eventually
3315 .none => {4220 // be called to apply the lazy node's new relocations.
3316 try elf.nodes.ensureUnusedCapacity(gpa, 1);4221 try ni.moved(gpa, &elf.mf);
3317 const sec_si: Symbol.Index = switch (lazy.kind) {
3318 .code => .text,
3319 .const_data => .rodata,
3320 };
3321 const ni = try elf.mf.addLastChildNode(gpa, sec_si.node(elf), .{ .moved = true });
3322 elf.nodes.appendAssumeCapacity(switch (lazy.kind) {
3323 .code => .{ .lazy_code = @enumFromInt(lmr.index) },
3324 .const_data => .{ .lazy_const_data = @enumFromInt(lmr.index) },
3325 });
3326 sym.ni = ni;
3327 switch (elf.symPtr(si)) {
3328 inline else => |sym_ptr, class| sym_ptr.shndx =
3329 @field(elf.symPtr(sec_si), @tagName(class)).shndx,
3330 }
3331 },
3332 else => si.deleteLocationRelocs(elf),
3333 }
3334 assert(sym.loc_relocs == .none);
3335 sym.loc_relocs = @enumFromInt(elf.relocs.items.len);
3336 break :ni sym.ni;
3337 };
33384222
3339 var required_alignment: InternPool.Alignment = .none;4223 var required_alignment: InternPool.Alignment = .none;
3340 var nw: MappedFile.Node.Writer = undefined;4224 var nw: MappedFile.Node.Writer = undefined;
...@@ -3348,15 +4232,14 @@ fn flushLazy(elf: *Elf, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void {...@@ -3348,15 +4232,14 @@ fn flushLazy(elf: *Elf, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void {
3348 &required_alignment,4232 &required_alignment,
3349 &nw.interface,4233 &nw.interface,
3350 .none,4234 .none,
3351 .{ .atom_index = @intFromEnum(si) },4235 .{ .atom_index = Node.toAtom(ni) },
3352 );4236 );
3353 switch (elf.symPtr(si)) {4237 switch (elf.symPtr(lmr.symbol(elf).index())) {
3354 inline else => |sym| elf.targetStore(&sym.size, @intCast(nw.interface.end)),4238 inline else => |sym| elf.targetStore(&sym.size, @intCast(nw.interface.end)),
3355 }4239 }
3356 si.applyLocationRelocs(elf);
3357}4240}
33584241
3359fn flushInputSection(elf: *Elf, isi: Node.InputSectionIndex) !void {4242fn flushInputSection(elf: *Elf, isi: InputSection.Index) !void {
3360 const file_loc = isi.fileLocation(elf);4243 const file_loc = isi.fileLocation(elf);
3361 if (file_loc.size == 0) return;4244 if (file_loc.size == 0) return;
3362 const comp = elf.base.comp;4245 const comp = elf.base.comp;
...@@ -3369,12 +4252,13 @@ fn flushInputSection(elf: *Elf, isi: Node.InputSectionIndex) !void {...@@ -3369,12 +4252,13 @@ fn flushInputSection(elf: *Elf, isi: Node.InputSectionIndex) !void {
3369 var fr = file.reader(io, &.{});4252 var fr = file.reader(io, &.{});
3370 try fr.seekTo(file_loc.offset);4253 try fr.seekTo(file_loc.offset);
3371 var nw: MappedFile.Node.Writer = undefined;4254 var nw: MappedFile.Node.Writer = undefined;
3372 const si = isi.symbol(elf);4255 isi.node(elf).writer(&elf.mf, gpa, &nw);
3373 si.node(elf).writer(&elf.mf, gpa, &nw);
3374 defer nw.deinit();4256 defer nw.deinit();
3375 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)
3376 return error.EndOfStream;4258 return error.EndOfStream;
3377 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));
3378}4262}
33794263
3380fn flushFileOffset(elf: *Elf, ni: MappedFile.Node.Index) !void {4264fn flushFileOffset(elf: *Elf, ni: MappedFile.Node.Index) !void {
...@@ -3397,7 +4281,7 @@ fn flushFileOffset(elf: *Elf, ni: MappedFile.Node.Index) !void {...@@ -3397,7 +4281,7 @@ fn flushFileOffset(elf: *Elf, ni: MappedFile.Node.Index) !void {
3397 var child_it = ni.children(&elf.mf);4281 var child_it = ni.children(&elf.mf);
3398 while (child_it.next()) |child_ni| try elf.flushFileOffset(child_ni);4282 while (child_it.next()) |child_ni| try elf.flushFileOffset(child_ni);
3399 },4283 },
3400 .section => |si| switch (elf.shdrPtr(si.shndx(elf))) {4284 .section => |shndx| switch (elf.shdrPtr(shndx)) {
3401 inline else => |shdr| elf.targetStore(&shdr.offset, @intCast(4285 inline else => |shdr| elf.targetStore(&shdr.offset, @intCast(
3402 ni.fileLocation(&elf.mf, false).offset,4286 ni.fileLocation(&elf.mf, false).offset,
3403 )),4287 )),
...@@ -3426,22 +4310,21 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {...@@ -3426,22 +4310,21 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {
3426 },4310 },
3427 }4311 }
3428 },4312 },
3429 .section => |si| {4313 .section => |shndx| {
3430 try elf.flushFileOffset(ni);4314 try elf.flushFileOffset(ni);
3431 const addr = elf.computeNodeVAddr(ni);4315 const addr = elf.computeNodeVAddr(ni);
3432 const shndx = si.shndx(elf);
3433 switch (elf.shdrPtr(shndx)) {4316 switch (elf.shdrPtr(shndx)) {
3434 inline else => |shdr, class| {4317 inline else => |shdr, class| {
3435 const flags = elf.targetLoad(&shdr.flags).shf;4318 const flags = elf.targetLoad(&shdr.flags).shf;
3436 if (flags.ALLOC) {4319 if (flags.ALLOC) {
3437 if (elf.si.dynamic != .null) {4320 if (elf.shndx.dynamic != .UNDEF) {
3438 if (si == elf.si.got) {4321 if (shndx == elf.shndx.got) {
3439 const old_addr = elf.targetLoad(&shdr.addr);4322 const old_addr = elf.targetLoad(&shdr.addr);
3440 const rela_dyn_si = shndx.get(elf).rela_si;4323 const rela_dyn_shndx = shndx.get(elf).rela_shndx;
3441 const relas: []class.ElfN().Rela = @ptrCast(@alignCast(4324 const relas: []class.ElfN().Rela = @ptrCast(@alignCast(
3442 rela_dyn_si.node(elf).slice(&elf.mf)[0..@intCast(4325 rela_dyn_shndx.get(elf).ni.slice(&elf.mf)[0..@intCast(
3443 elf.targetLoad(&@field(4326 elf.targetLoad(&@field(
3444 elf.shdrPtr(rela_dyn_si.shndx(elf)),4327 elf.shdrPtr(rela_dyn_shndx),
3445 @tagName(class),4328 @tagName(class),
3446 ).size),4329 ).size),
3447 )],4330 )],
...@@ -3461,19 +4344,19 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {...@@ -3461,19 +4344,19 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {
3461 ),4344 ),
3462 },4345 },
3463 }4346 }
3464 } else if (si == elf.si.got_plt) {4347 } else if (shndx == elf.shndx.got_plt) {
3465 const target_endian = elf.targetEndian();4348 const target_endian = elf.targetEndian();
3466 const old_addr = elf.targetLoad(&shdr.addr);4349 const old_addr = elf.targetLoad(&shdr.addr);
3467 const rela_plt_si = shndx.get(elf).rela_si;4350 const rela_plt_shndx = shndx.get(elf).rela_shndx;
3468 const relas: []class.ElfN().Rela = @ptrCast(@alignCast(4351 const relas: []class.ElfN().Rela = @ptrCast(@alignCast(
3469 rela_plt_si.node(elf).slice(&elf.mf)[0..@intCast(4352 rela_plt_shndx.get(elf).ni.slice(&elf.mf)[0..@intCast(
3470 elf.targetLoad(&@field(4353 elf.targetLoad(&@field(
3471 elf.shdrPtr(rela_plt_si.shndx(elf)),4354 elf.shdrPtr(rela_plt_shndx),
3472 @tagName(class),4355 @tagName(class),
3473 ).size),4356 ).size),
3474 )],4357 )],
3475 ));4358 ));
3476 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);
3477 switch (elf.ehdrField(.machine)) {4360 switch (elf.ehdrField(.machine)) {
3478 else => |machine| @panic(@tagName(machine)),4361 else => |machine| @panic(@tagName(machine)),
3479 .AARCH64, .PPC64, .RISCV => {},4362 .AARCH64, .PPC64, .RISCV => {},
...@@ -3502,7 +4385,7 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {...@@ -3502,7 +4385,7 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {
3502 }4385 }
3503 },4386 },
3504 }4387 }
3505 } else if (si == elf.si.plt_sec) {4388 } else if (shndx == elf.shndx.plt_sec) {
3506 const target_endian = elf.targetEndian();4389 const target_endian = elf.targetEndian();
3507 const old_addr = elf.targetLoad(&shdr.addr);4390 const old_addr = elf.targetLoad(&shdr.addr);
3508 const plt_sec_slice = ni.slice(&elf.mf);4391 const plt_sec_slice = ni.slice(&elf.mf);
...@@ -3525,34 +4408,72 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {...@@ -3525,34 +4408,72 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {
3525 }4408 }
3526 }4409 }
3527 elf.targetStore(&shdr.addr, @intCast(addr));4410 elf.targetStore(&shdr.addr, @intCast(addr));
3528 @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);
3529 }4418 }
3530 },4419 },
3531 }4420 }
3532 si.flushMoved(elf, addr);
3533 },4421 },
3534 .input_section => |isi| {4422 .input_section => |isi| {
3535 const old_addr = switch (elf.symPtr(isi.symbol(elf))) {4423 const old_section_addr = isi.ptr(elf).vaddr;
3536 inline else => |sym| elf.targetLoad(&sym.value),4424 const new_section_addr = elf.computeNodeVAddr(ni);
3537 };4425 isi.ptr(elf).vaddr = new_section_addr;
3538 const new_addr = elf.computeNodeVAddr(ni);4426
4427 // Update local symbols
3539 const ii = isi.input(elf);4428 const ii = isi.input(elf);
3540 var si = ii.symbol(elf);4429 var lsi, const end_lsi = ii.localSymbolRange(elf);
3541 const end_si = ii.endSymbol(elf);4430 while (lsi != end_lsi) : (lsi = @enumFromInt(@intFromEnum(lsi) + 1)) {
3542 while (cond: {4431 if (lsi.index().ptr(elf).node != ni) continue;
3543 si = si.next();4432 const old_sym_addr: u64 = switch (elf.symPtr(lsi.index())) {
3544 break :cond si != end_si;4433 inline else => |sym| switch (elf.targetLoad(&sym.other).visibility) {
3545 }) {4434 .HIDDEN, .INTERNAL => {
3546 if (si.get(elf).ni != ni) continue;4435 // This is actually a global symbol which got demoted to STB_LOCAL due
3547 si.flushMoved(elf, switch (elf.symPtr(si)) {4436 // to its visibility. It will be handled in the global symbols pass
3548 inline else => |sym| elf.targetLoad(&sym.value),4437 // below; don't touch it now.
3549 } - 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 }
3550 }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));
3551 },4476 },
3552 inline .nav, .uav, .lazy_code, .lazy_const_data => |mi| mi.symbol(elf).flushMoved(
3553 elf,
3554 elf.computeNodeVAddr(ni),
3555 ),
3556 }4477 }
3557 try ni.childrenMoved(elf.base.comp.gpa, &elf.mf);4478 try ni.childrenMoved(elf.base.comp.gpa, &elf.mf);
3558}4479}
...@@ -3590,7 +4511,7 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void {...@@ -3590,7 +4511,7 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void {
3590 switch (elf.targetLoad(&next_ph.type)) {4511 switch (elf.targetLoad(&next_ph.type)) {
3591 else => unreachable,4512 else => unreachable,
3592 .NULL, .LOAD => {},4513 .NULL, .LOAD => {},
3593 .DYNAMIC, .INTERP, .PHDR, .TLS => break,4514 .DYNAMIC, .INTERP, .PHDR, .TLS, std.elf.PT.GNU_RELRO => break,
3594 }4515 }
3595 const next_vaddr = elf.targetLoad(&next_ph.vaddr);4516 const next_vaddr = elf.targetLoad(&next_ph.vaddr);
3596 if (vaddr + memsz <= next_vaddr) break;4517 if (vaddr + memsz <= next_vaddr) break;
...@@ -3612,7 +4533,7 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void {...@@ -3612,7 +4533,7 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void {
3612 }4533 }
3613 },4534 },
3614 },4535 },
3615 .section => |si| switch (elf.shdrPtr(si.shndx(elf))) {4536 .section => |shndx| switch (elf.shdrPtr(shndx)) {
3616 inline else => |shdr, class| {4537 inline else => |shdr, class| {
3617 switch (elf.targetLoad(&shdr.type)) {4538 switch (elf.targetLoad(&shdr.type)) {
3618 else => unreachable,4539 else => unreachable,
...@@ -3620,10 +4541,10 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void {...@@ -3620,10 +4541,10 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void {
3620 .PROGBITS => if (size == 0) elf.targetStore(&shdr.type, .NULL),4541 .PROGBITS => if (size == 0) elf.targetStore(&shdr.type, .NULL),
3621 .SYMTAB, .DYNAMIC, .REL, .DYNSYM => return,4542 .SYMTAB, .DYNAMIC, .REL, .DYNSYM => return,
3622 .STRTAB => {4543 .STRTAB => {
3623 if (elf.si.dynamic != .null) {4544 if (elf.shndx.dynamic != .UNDEF) {
3624 if (si == elf.si.dynstr) {4545 if (shndx == elf.shndx.dynstr) {
3625 const dynamic_entries: [][2]class.ElfN().Addr = @ptrCast(@alignCast(4546 const dynamic_entries: [][2]class.ElfN().Addr = @ptrCast(@alignCast(
3626 elf.si.dynamic.node(elf).slice(&elf.mf),4547 elf.shndx.dynamic.get(elf).ni.slice(&elf.mf),
3627 ));4548 ));
3628 for (dynamic_entries) |*dynamic_entry|4549 for (dynamic_entries) |*dynamic_entry|
3629 switch (elf.targetLoad(&dynamic_entry[0])) {4550 switch (elf.targetLoad(&dynamic_entry[0])) {
...@@ -3635,19 +4556,19 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void {...@@ -3635,19 +4556,19 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void {
3635 return;4556 return;
3636 },4557 },
3637 .RELA => {4558 .RELA => {
3638 if (elf.si.dynamic != .null) {4559 if (elf.shndx.dynamic != .UNDEF) {
3639 if (si == elf.si.got.shndx(elf).get(elf).rela_si) {4560 if (shndx == elf.shndx.got.get(elf).rela_shndx) {
3640 const dynamic_entries: [][2]class.ElfN().Addr = @ptrCast(@alignCast(4561 const dynamic_entries: [][2]class.ElfN().Addr = @ptrCast(@alignCast(
3641 elf.si.dynamic.node(elf).slice(&elf.mf),4562 elf.shndx.dynamic.get(elf).ni.slice(&elf.mf),
3642 ));4563 ));
3643 for (dynamic_entries) |*dynamic_entry|4564 for (dynamic_entries) |*dynamic_entry|
3644 switch (elf.targetLoad(&dynamic_entry[0])) {4565 switch (elf.targetLoad(&dynamic_entry[0])) {
3645 else => {},4566 else => {},
3646 std.elf.DT_RELASZ => dynamic_entry[1] = shdr.size,4567 std.elf.DT_RELASZ => dynamic_entry[1] = shdr.size,
3647 };4568 };
3648 } 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) {
3649 const dynamic_entries: [][2]class.ElfN().Addr = @ptrCast(@alignCast(4570 const dynamic_entries: [][2]class.ElfN().Addr = @ptrCast(@alignCast(
3650 elf.si.dynamic.node(elf).slice(&elf.mf),4571 elf.shndx.dynamic.get(elf).ni.slice(&elf.mf),
3651 ));4572 ));
3652 for (dynamic_entries) |*dynamic_entry|4573 for (dynamic_entries) |*dynamic_entry|
3653 switch (elf.targetLoad(&dynamic_entry[0])) {4574 switch (elf.targetLoad(&dynamic_entry[0])) {
...@@ -3659,7 +4580,9 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void {...@@ -3659,7 +4580,9 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void {
3659 return;4580 return;
3660 },4581 },
3661 }4582 }
3662 elf.targetStore(&shdr.size, @intCast(size));4583 if (shndx != elf.shndx.plt) {
4584 elf.targetStore(&shdr.size, @intCast(size));
4585 }
3663 },4586 },
3664 },4587 },
3665 .input_section, .nav, .uav, .lazy_code, .lazy_const_data => {},4588 .input_section, .nav, .uav, .lazy_code, .lazy_const_data => {},
...@@ -3690,7 +4613,6 @@ fn updateExportsInner(...@@ -3690,7 +4613,6 @@ fn updateExportsInner(
3690 export_indices: []const Zcu.Export.Index,4613 export_indices: []const Zcu.Export.Index,
3691) !void {4614) !void {
3692 const zcu = pt.zcu;4615 const zcu = pt.zcu;
3693 const gpa = zcu.gpa;
3694 const ip = &zcu.intern_pool;4616 const ip = &zcu.intern_pool;
36954617
3696 switch (exported) {4618 switch (exported) {
...@@ -3700,44 +4622,35 @@ fn updateExportsInner(...@@ -3700,44 +4622,35 @@ fn updateExportsInner(
3700 Value.fromInterned(uav).fmtValue(pt),4622 Value.fromInterned(uav).fmtValue(pt),
3701 }),4623 }),
3702 }4624 }
3703 try elf.symtab.ensureUnusedCapacity(gpa, export_indices.len);4625 try elf.ensureUnusedSymbolCapacity(@intCast(export_indices.len), .maybe_global);
3704 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) {
3705 .nav => |nav| .{4627 .nav => |nav| .{
3706 try elf.navSymbol(zcu, nav),4628 (try elf.navMapIndex(zcu, nav)).symbol(elf),
3707 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),
3708 },4630 },
3709 .uav => |uav| .{ @enumFromInt(switch (try elf.lowerUav(4631 .uav => |uav| .{ (try elf.uavMapIndex(uav, .none)).symbol(elf), .OBJECT },
3710 pt,
3711 uav,
3712 Type.fromInterned(ip.typeOf(uav)).abiAlignment(zcu),
3713 export_indices[0].ptr(zcu).src,
3714 )) {
3715 .sym_index => |si| si,
3716 .fail => |em| {
3717 defer em.destroy(gpa);
3718 return elf.base.comp.link_diags.fail("{s}", .{em.msg});
3719 },
3720 }), .OBJECT },
3721 };4632 };
3722 while (try elf.idle(pt.tid)) {}4633 while (try elf.idle(pt.tid)) {}
3723 const exported_ni = exported_si.node(elf);4634 const value: u64, const size: u64, const shndx: Section.Index = switch (elf.symPtr(exported_lsi.index())) {
3724 const value, const size, const shndx = switch (elf.symPtr(exported_si)) {
3725 inline else => |exported_sym| .{4635 inline else => |exported_sym| .{
3726 elf.targetLoad(&exported_sym.value),4636 elf.targetLoad(&exported_sym.value),
3727 exported_sym.size,4637 elf.targetLoad(&exported_sym.size),
3728 exported_sym.shndx,4638 .fromSection(elf.targetLoad(&exported_sym.shndx)),
3729 },4639 },
3730 };4640 };
3731 for (export_indices) |export_index| {4641 for (export_indices) |export_index| {
3732 const @"export" = export_index.ptr(zcu);4642 const @"export" = export_index.ptr(zcu);
3733 const name = @"export".opts.name.toSlice(ip);4643 const name = @"export".opts.name.toSlice(ip);
3734 const export_si = try elf.globalSymbol(.{4644 _ = elf.addGlobalSymbolAssumeCapacity(.{
3735 .name = name,4645 .node = .none,
4646 .name = try .string(elf, name),
4647 .value = value,
4648 .size = @intCast(size),
3736 .type = @"type",4649 .type = @"type",
3737 .bind = switch (@"export".opts.linkage) {4650 .bind = switch (@"export".opts.linkage) {
3738 .internal => .LOCAL,4651 .internal => @panic("TODO internal linkage"),
3739 .strong => .GLOBAL,4652 .strong => .strong,
3740 .weak => .WEAK,4653 .weak => .weak,
3741 .link_once => return error.LinkOnceUnsupported,4654 .link_once => return error.LinkOnceUnsupported,
3742 },4655 },
3743 .visibility = switch (@"export".opts.visibility) {4656 .visibility = switch (@"export".opts.visibility) {
...@@ -3745,15 +4658,23 @@ fn updateExportsInner(...@@ -3745,15 +4658,23 @@ fn updateExportsInner(
3745 .hidden => .HIDDEN,4658 .hidden => .HIDDEN,
3746 .protected => .PROTECTED,4659 .protected => .PROTECTED,
3747 },4660 },
3748 });4661 .shndx = shndx,
3749 export_si.get(elf).ni = exported_ni;4662 }) catch |err| switch (err) {
3750 switch (elf.symPtr(export_si)) {4663 error.MultipleDefinitions => {
3751 inline else => |export_sym| {4664 // HACK: because we currently don't/can't delete these exports, we would typically
3752 export_sym.size = @intCast(size);4665 // get these errors on every non-initial incremental update. Hack around that by
3753 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 }
3754 },4676 },
3755 }4677 };
3756 export_si.flushMoved(elf, value);
3757 }4678 }
3758}4679}
37594680
...@@ -3807,13 +4728,13 @@ pub fn printNode(...@@ -3807,13 +4728,13 @@ pub fn printNode(
3807 try w.writeByte(')');4728 try w.writeByte(')');
3808 },4729 },
3809 },4730 },
3810 .section => |si| try w.print("({s})", .{elf.sectionName(si)}),4731 .section => |shndx| try w.print("({s})", .{shndx.name(elf)}),
3811 .input_section => |isi| {4732 .input_section => |isi| {
3812 const ii = isi.input(elf);4733 const ii = isi.input(elf);
3813 try w.print("({f}{f}, {s})", .{4734 try w.print("({f}{f}, {s})", .{
3814 ii.path(elf).fmtEscapeString(),4735 ii.path(elf).fmtEscapeString(),
3815 fmtMemberString(ii.member(elf)),4736 fmtMemberString(ii.member(elf)),
3816 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),
3817 });4738 });
3818 },4739 },
3819 .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,