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(
178178 pt: Zcu.PerThread,
179179 src_loc: Zcu.LazySrcLoc,
180180 func_index: InternPool.Index,
181 atom_index: u32,
181 atom_id: link.File.AtomId,
182182 any_mir: *const AnyMir,
183183 w: *std.Io.Writer,
184184 debug_output: link.File.DebugInfoOutput,
......@@ -195,7 +195,7 @@ pub fn emitFunction(
195195 => |backend| {
196196 dev.check(devFeatureForBackend(backend));
197197 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);
199199 },
200200 }
201201}
......@@ -205,7 +205,7 @@ pub fn generateLazyFunction(
205205 pt: Zcu.PerThread,
206206 src_loc: Zcu.LazySrcLoc,
207207 lazy_sym: link.File.LazySymbol,
208 atom_index: u32,
208 atom_id: link.File.AtomId,
209209 w: *std.Io.Writer,
210210 debug_output: link.File.DebugInfoOutput,
211211) (CodeGenError || std.Io.Writer.Error)!void {
......@@ -218,7 +218,7 @@ pub fn generateLazyFunction(
218218 else => unreachable,
219219 inline .stage2_riscv64, .stage2_x86_64 => |backend| {
220220 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);
222222 },
223223 }
224224}
......@@ -852,20 +852,7 @@ fn lowerNavRef(
852852 }
853853}
854854
855/// Helper struct to denote that the value is in memory but requires a linker relocation fixup:
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 };
855pub const SymbolResult = union(enum) { sym_index: link.File.SymbolId, fail: *ErrorMsg };
869856
870857pub fn genNavRef(
871858 lf: *link.File,
......@@ -890,7 +877,7 @@ pub fn genNavRef(
890877 .internal => {
891878 const sym_index = try zo.getOrCreateMetadataForNav(zcu, nav_index);
892879 if (is_threadlocal) zo.symbol(sym_index).flags.is_tls = true;
893 return .{ .sym_index = sym_index };
880 return .{ .sym_index = @enumFromInt(sym_index) };
894881 },
895882 .strong, .weak => {
896883 const sym_index = try elf_file.getGlobalSymbol(nav.name.toSlice(ip), lib_name.toSlice(ip));
......@@ -901,12 +888,12 @@ pub fn genNavRef(
901888 .link_once => unreachable,
902889 }
903890 if (is_threadlocal) zo.symbol(sym_index).flags.is_tls = true;
904 return .{ .sym_index = sym_index };
891 return .{ .sym_index = @enumFromInt(sym_index) };
905892 },
906893 .link_once => unreachable,
907894 }
908895 } 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) {
910897 error.OutOfMemory => |e| return e,
911898 else => |e| return .{ .fail = try ErrorMsg.create(
912899 zcu.gpa,
......@@ -914,14 +901,14 @@ pub fn genNavRef(
914901 "linker failed to create a nav: {t}",
915902 .{e},
916903 ) },
917 }) };
904 } };
918905 } else if (lf.cast(.macho)) |macho_file| {
919906 const zo = macho_file.getZigObject().?;
920907 switch (linkage) {
921908 .internal => {
922909 const sym_index = try zo.getOrCreateMetadataForNav(macho_file, nav_index);
923910 if (is_threadlocal) zo.symbols.items[sym_index].flags.tlv = true;
924 return .{ .sym_index = sym_index };
911 return .{ .sym_index = @enumFromInt(sym_index) };
925912 },
926913 .strong, .weak => {
927914 const sym_index = try macho_file.getGlobalSymbol(nav.name.toSlice(ip), lib_name.toSlice(ip));
......@@ -932,12 +919,12 @@ pub fn genNavRef(
932919 .link_once => unreachable,
933920 }
934921 if (is_threadlocal) zo.symbols.items[sym_index].flags.tlv = true;
935 return .{ .sym_index = sym_index };
922 return .{ .sym_index = @enumFromInt(sym_index) };
936923 },
937924 .link_once => unreachable,
938925 }
939926 } 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))) };
941928 } else {
942929 const msg = try ErrorMsg.create(zcu.gpa, src_loc, "TODO genNavRef for target {}", .{target});
943930 return .{ .fail = msg };
......@@ -957,22 +944,22 @@ pub const GenResult = union(enum) {
957944 immediate: u64,
958945 /// Decl with address deferred until the linker allocates everything in virtual memory.
959946 /// Payload is a symbol index.
960 load_direct: u32,
947 load_direct: link.File.SymbolId,
961948 /// Decl with address deferred until the linker allocates everything in virtual memory.
962949 /// Payload is a symbol index.
963 lea_direct: u32,
950 lea_direct: link.File.SymbolId,
964951 /// Decl referenced via GOT with address deferred until the linker allocates
965952 /// everything in virtual memory.
966953 /// Payload is a symbol index.
967 load_got: u32,
954 load_got: link.File.SymbolId,
968955 /// Direct by-address reference to memory location.
969956 memory: u64,
970957 /// Reference to memory location but deferred until linker allocated the Decl in memory.
971958 /// Traditionally, this corresponds to emitting a relocation in a relocatable object file.
972 load_symbol: u32,
959 load_symbol: link.File.SymbolId,
973960 /// Reference to memory location but deferred until linker allocated the Decl in memory.
974961 /// Traditionally, this corresponds to emitting a relocation in a relocatable object file.
975 lea_symbol: u32,
962 lea_symbol: link.File.SymbolId,
976963 };
977964};
978965
src/codegen/aarch64/Mir.zig+26-26
......@@ -56,7 +56,7 @@ pub fn emit(
5656 pt: Zcu.PerThread,
5757 src_loc: Zcu.LazySrcLoc,
5858 func_index: InternPool.Index,
59 atom_index: u32,
59 atom_index: link.File.AtomId,
6060 w: *std.Io.Writer,
6161 debug_output: link.File.DebugInfoOutput,
6262) !void {
......@@ -132,11 +132,11 @@ pub fn emit(
132132 zcu,
133133 atom_index,
134134 if (lf.cast(.elf)) |ef|
135 ef.zigObjectPtr().?.getOrCreateMetadataForLazySymbol(ef, pt, lazy_reloc.symbol) catch |err|
136 return zcu.codegenFail(func.owner_nav, "{s} creating lazy symbol", .{@errorName(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)}))
137137 else if (lf.cast(.macho)) |mf|
138 mf.getZigObject().?.getOrCreateMetadataForLazySymbol(mf, pt, lazy_reloc.symbol) catch |err|
139 return zcu.codegenFail(func.owner_nav, "{s} creating lazy symbol", .{@errorName(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)}))
140140 else
141141 return zcu.codegenFail(func.owner_nav, "external symbols unimplemented for {t}", .{lf.tag}),
142142 mir.body[lazy_reloc.reloc.label],
......@@ -149,9 +149,9 @@ pub fn emit(
149149 zcu,
150150 atom_index,
151151 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))
153153 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))
155155 else
156156 return zcu.codegenFail(func.owner_nav, "external symbols unimplemented for {t}", .{lf.tag}),
157157 mir.body[global_reloc.reloc.label],
......@@ -187,8 +187,8 @@ fn emitInstruction(w: *std.Io.Writer, instruction: Instruction) !void {
187187fn emitReloc(
188188 lf: *link.File,
189189 zcu: *Zcu,
190 atom_index: u32,
191 sym_index: u32,
190 atom_index: link.File.AtomId,
191 sym_index: link.File.SymbolId,
192192 instruction: Instruction,
193193 offset: u32,
194194 addend: u64,
......@@ -199,7 +199,7 @@ fn emitReloc(
199199 else => unreachable,
200200 .data_processing_immediate => |decoded| if (lf.cast(.elf)) |ef| {
201201 const zo = ef.zigObjectPtr().?;
202 const atom = zo.symbol(atom_index).atom(ef).?;
202 const atom = zo.symbol(@intFromEnum(atom_index)).atom(ef).?;
203203 const r_type: std.elf.R_AARCH64 = switch (decoded.decode()) {
204204 else => unreachable,
205205 .pc_relative_addressing => |pc_relative_addressing| switch (pc_relative_addressing.group.op) {
......@@ -222,12 +222,12 @@ fn emitReloc(
222222 };
223223 try atom.addReloc(gpa, .{
224224 .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),
226226 .r_addend = @bitCast(addend),
227227 }, zo);
228228 } else if (lf.cast(.macho)) |mf| {
229229 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).?;
231231 switch (decoded.decode()) {
232232 else => unreachable,
233233 .pc_relative_addressing => |pc_relative_addressing| switch (pc_relative_addressing.group.op) {
......@@ -235,7 +235,7 @@ fn emitReloc(
235235 .adrp => try atom.addReloc(mf, .{
236236 .tag = .@"extern",
237237 .offset = offset,
238 .target = sym_index,
238 .target = @intFromEnum(sym_index),
239239 .addend = @bitCast(addend),
240240 .type = switch (kind) {
241241 .direct => .page,
......@@ -245,7 +245,7 @@ fn emitReloc(
245245 .pcrel = true,
246246 .has_subtractor = false,
247247 .length = 2,
248 .symbolnum = @intCast(sym_index),
248 .symbolnum = @intCast(@intFromEnum(sym_index)),
249249 },
250250 }),
251251 },
......@@ -253,7 +253,7 @@ fn emitReloc(
253253 .add => try atom.addReloc(mf, .{
254254 .tag = .@"extern",
255255 .offset = offset,
256 .target = sym_index,
256 .target = @intFromEnum(sym_index),
257257 .addend = @bitCast(addend),
258258 .type = switch (kind) {
259259 .direct => .pageoff,
......@@ -263,7 +263,7 @@ fn emitReloc(
263263 .pcrel = false,
264264 .has_subtractor = false,
265265 .length = 2,
266 .symbolnum = @intCast(sym_index),
266 .symbolnum = @intCast(@intFromEnum(sym_index)),
267267 },
268268 }),
269269 .sub => unreachable,
......@@ -272,36 +272,36 @@ fn emitReloc(
272272 },
273273 .branch_exception_generating_system => |decoded| if (lf.cast(.elf)) |ef| {
274274 const zo = ef.zigObjectPtr().?;
275 const atom = zo.symbol(atom_index).atom(ef).?;
275 const atom = zo.symbol(@intFromEnum(atom_index)).atom(ef).?;
276276 const r_type: std.elf.R_AARCH64 = switch (decoded.decode().unconditional_branch_immediate.group.op) {
277277 .b => .JUMP26,
278278 .bl => .CALL26,
279279 };
280280 try atom.addReloc(gpa, .{
281281 .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),
283283 .r_addend = @bitCast(addend),
284284 }, zo);
285285 } else if (lf.cast(.macho)) |mf| {
286286 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).?;
288288 try atom.addReloc(mf, .{
289289 .tag = .@"extern",
290290 .offset = offset,
291 .target = sym_index,
291 .target = @intFromEnum(sym_index),
292292 .addend = @bitCast(addend),
293293 .type = .branch,
294294 .meta = .{
295295 .pcrel = true,
296296 .has_subtractor = false,
297297 .length = 2,
298 .symbolnum = @intCast(sym_index),
298 .symbolnum = @intCast(@intFromEnum(sym_index)),
299299 },
300300 });
301301 },
302302 .load_store => |decoded| if (lf.cast(.elf)) |ef| {
303303 const zo = ef.zigObjectPtr().?;
304 const atom = zo.symbol(atom_index).atom(ef).?;
304 const atom = zo.symbol(@intFromEnum(atom_index)).atom(ef).?;
305305 const r_type: std.elf.R_AARCH64 = switch (decoded.decode().register_unsigned_immediate.decode()) {
306306 .integer => |integer| switch (integer.decode()) {
307307 .unallocated, .prfm => unreachable,
......@@ -342,16 +342,16 @@ fn emitReloc(
342342 };
343343 try atom.addReloc(gpa, .{
344344 .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),
346346 .r_addend = @bitCast(addend),
347347 }, zo);
348348 } else if (lf.cast(.macho)) |mf| {
349349 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).?;
351351 try atom.addReloc(mf, .{
352352 .tag = .@"extern",
353353 .offset = offset,
354 .target = sym_index,
354 .target = @intFromEnum(sym_index),
355355 .addend = @bitCast(addend),
356356 .type = switch (kind) {
357357 .direct => .pageoff,
......@@ -361,7 +361,7 @@ fn emitReloc(
361361 .pcrel = false,
362362 .has_subtractor = false,
363363 .length = 2,
364 .symbolnum = @intCast(sym_index),
364 .symbolnum = @intCast(@intFromEnum(sym_index)),
365365 },
366366 });
367367 },
src/codegen/riscv64/CodeGen.zig+13-13
......@@ -130,7 +130,7 @@ air_bookkeeping: @TypeOf(air_bookkeeping_init) = air_bookkeeping_init,
130130
131131const 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 };
134134const RegisterOffset = struct { reg: Register, off: i32 = 0 };
135135pub const FrameAddr = struct { index: FrameIndex, off: i32 = 0 };
136136
......@@ -166,7 +166,7 @@ const MCValue = union(enum) {
166166 dead: u32,
167167 /// The value is undefined. Contains a symbol index to an undefined constant. Null means
168168 /// set the undefined value via immediate instead of a load.
169 undef: ?u32,
169 undef: ?link.File.SymbolId,
170170 /// A pointer-sized integer that fits in a register.
171171 /// If the type is a pointer, this is the pointer address in virtual address space.
172172 immediate: u64,
......@@ -859,7 +859,7 @@ pub fn generateLazy(
859859 pt: Zcu.PerThread,
860860 src_loc: Zcu.LazySrcLoc,
861861 lazy_sym: link.File.LazySymbol,
862 atom_index: u32,
862 atom_index: link.File.AtomId,
863863 w: *std.Io.Writer,
864864 debug_output: link.File.DebugInfoOutput,
865865) (CodeGenError || std.Io.Writer.Error)!void {
......@@ -1305,7 +1305,7 @@ fn genLazy(func: *Func, lazy_sym: link.File.LazySymbol) InnerError!void {
13051305 }) catch |err|
13061306 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
13101310 const cmp_reg, const cmp_lock = try func.allocReg(.int);
13111311 defer func.register_manager.unlockReg(cmp_lock);
......@@ -3595,8 +3595,8 @@ fn airRuntimeNavPtr(func: *Func, inst: Air.Inst.Index) !void {
35953595 .tag = .pseudo_load_tlv,
35963596 .data = .{ .reloc = .{
35973597 .register = dest_mcv.getReg().?,
3598 .atom_index = try func.owner.getSymbolIndex(func),
3599 .sym_index = tlv_sym_index,
3598 .atom_index = @enumFromInt(try func.owner.getSymbolIndex(func)),
3599 .sym_index = @enumFromInt(tlv_sym_index),
36003600 } },
36013601 });
36023602 } else {
......@@ -3606,8 +3606,8 @@ fn airRuntimeNavPtr(func: *Func, inst: Air.Inst.Index) !void {
36063606 .tag = .pseudo_load_tlv,
36073607 .data = .{ .reloc = .{
36083608 .register = tmp_reg,
3609 .atom_index = try func.owner.getSymbolIndex(func),
3610 .sym_index = tlv_sym_index,
3609 .atom_index = @enumFromInt(try func.owner.getSymbolIndex(func)),
3610 .sym_index = @enumFromInt(tlv_sym_index),
36113611 } },
36123612 });
36133613 try func.genCopy(ptr_ty, dest_mcv, .{ .register = tmp_reg });
......@@ -4958,7 +4958,7 @@ fn genCall(
49584958 .func => |func_val| {
49594959 if (func.bin_file.cast(.elf)) |elf_file| {
49604960 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
49634963 if (func.mod.pic) {
49644964 return func.fail("TODO: genCall pic", .{});
......@@ -4978,7 +4978,7 @@ fn genCall(
49784978 .@"extern" => |@"extern"| {
49794979 const lib_name = @"extern".lib_name.toSlice(&zcu.intern_pool);
49804980 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
49834983 const elf_file = func.bin_file.cast(.elf).?;
49844984 _ = try func.addInst(.{
......@@ -4986,7 +4986,7 @@ fn genCall(
49864986 .data = .{ .reloc = .{
49874987 .register = .ra,
49884988 .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)),
49904990 } },
49914991 });
49924992 },
......@@ -6405,7 +6405,7 @@ fn airAsm(func: *Func, inst: Air.Inst.Index) !void {
64056405 .tag = .pseudo_extern_fn_reloc,
64066406 .data = .{ .reloc = .{
64076407 .register = random_link_reg,
6408 .atom_index = try func.owner.getSymbolIndex(func),
6408 .atom_index = @enumFromInt(try func.owner.getSymbolIndex(func)),
64096409 .sym_index = sym_offset.sym,
64106410 } },
64116411 });
......@@ -7036,7 +7036,7 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
70367036 },
70377037 .lea_symbol => |sym_off| {
70387038 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
70417041 _ = try func.addInst(.{
70427042 .tag = .pseudo_load_symbol,
src/codegen/riscv64/Emit.zig+10-10
......@@ -47,8 +47,8 @@ pub fn emitMir(emit: *Emit) Error!void {
4747 const elf_file = emit.bin_file.cast(.elf).?;
4848 const zo = elf_file.zigObjectPtr().?;
4949
50 const atom_ptr = zo.symbol(symbol.atom_index).atom(elf_file).?;
51 const sym = zo.symbol(symbol.sym_index);
50 const atom_ptr = zo.symbol(@intFromEnum(symbol.atom_index)).atom(elf_file).?;
51 const sym = zo.symbol(@intFromEnum(symbol.sym_index));
5252
5353 if (emit.lower.pic) {
5454 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 {
5959
6060 try atom_ptr.addReloc(gpa, .{
6161 .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,
6363 .r_addend = 0,
6464 }, zo);
6565
6666 try atom_ptr.addReloc(gpa, .{
6767 .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,
6969 .r_addend = 0,
7070 }, zo);
7171 },
......@@ -73,38 +73,38 @@ pub fn emitMir(emit: *Emit) Error!void {
7373 const elf_file = emit.bin_file.cast(.elf).?;
7474 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
7878 const R_RISCV = std.elf.R_RISCV;
7979
8080 try atom_ptr.addReloc(gpa, .{
8181 .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),
8383 .r_addend = 0,
8484 }, zo);
8585
8686 try atom_ptr.addReloc(gpa, .{
8787 .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),
8989 .r_addend = 0,
9090 }, zo);
9191
9292 try atom_ptr.addReloc(gpa, .{
9393 .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),
9595 .r_addend = 0,
9696 }, zo);
9797 },
9898 .call_extern_fn_reloc => |symbol| {
9999 const elf_file = emit.bin_file.cast(.elf).?;
100100 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
103103 const r_type: u32 = @intFromEnum(std.elf.R_RISCV.CALL_PLT);
104104
105105 try atom_ptr.addReloc(gpa, .{
106106 .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,
108108 .r_addend = 0,
109109 }, zo);
110110 },
src/codegen/riscv64/Mir.zig+5-5
......@@ -67,8 +67,8 @@ pub const Inst = struct {
6767 },
6868 reloc: struct {
6969 register: Register,
70 atom_index: u32,
71 sym_index: u32,
70 atom_index: link.File.AtomId,
71 sym_index: link.File.SymbolId,
7272 },
7373 fence: struct {
7474 pred: Barrier,
......@@ -109,7 +109,7 @@ pub fn emit(
109109 pt: Zcu.PerThread,
110110 src_loc: Zcu.LazySrcLoc,
111111 func_index: InternPool.Index,
112 atom_index: u32,
112 atom_index: link.File.AtomId,
113113 w: *std.Io.Writer,
114114 debug_output: link.File.DebugInfoOutput,
115115) (codegen.CodeGenError || std.Io.Writer.Error)!void {
......@@ -183,8 +183,8 @@ pub const FcvtOp = enum(u5) {
183183
184184pub const LoadSymbolPayload = struct {
185185 register: u32,
186 atom_index: u32,
187 sym_index: u32,
186 atom_index: link.File.AtomId,
187 sym_index: link.File.SymbolId,
188188};
189189
190190/// 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;
44const Target = std.Target;
55
66const Zcu = @import("../../Zcu.zig");
7const link = @import("../../link.zig");
78const Mir = @import("Mir.zig");
89const abi = @import("abi.zig");
910
......@@ -260,9 +261,9 @@ pub const FrameIndex = enum(u32) {
260261/// A linker symbol not yet allocated in VM.
261262pub const Symbol = struct {
262263 /// Index of the containing atom.
263 atom_index: u32,
264 atom_index: link.File.AtomId,
264265 /// Index into the linker's symbol table.
265 sym_index: u32,
266 sym_index: link.File.SymbolId,
266267};
267268
268269pub const VType = packed struct(u8) {
src/codegen/sparc64/Mir.zig+1-1
......@@ -380,7 +380,7 @@ pub fn emit(
380380 pt: Zcu.PerThread,
381381 src_loc: Zcu.LazySrcLoc,
382382 func_index: InternPool.Index,
383 atom_index: u32,
383 atom_index: link.File.AtomId,
384384 w: *std.Io.Writer,
385385 debug_output: link.File.DebugInfoOutput,
386386) (codegen.CodeGenError || std.Io.Writer.Error)!void {
src/codegen/x86_64/CodeGen.zig+2-2
......@@ -1029,7 +1029,7 @@ pub fn generateLazy(
10291029 pt: Zcu.PerThread,
10301030 src_loc: Zcu.LazySrcLoc,
10311031 lazy_sym: link.File.LazySymbol,
1032 atom_index: u32,
1032 atom_id: link.File.AtomId,
10331033 w: *std.Io.Writer,
10341034 debug_output: link.File.DebugInfoOutput,
10351035) codegen.CodeGenError!void {
......@@ -1073,7 +1073,7 @@ pub fn generateLazy(
10731073 else => |e| return e,
10741074 };
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);
10771077}
10781078
10791079const FormatNavData = struct {
src/codegen/x86_64/Emit.zig+133-134
......@@ -4,7 +4,7 @@ lower: Lower,
44bin_file: *link.File,
55pt: Zcu.PerThread,
66pic: bool,
7atom_index: u32,
7atom_id: link.File.AtomId,
88debug_output: link.File.DebugInfoOutput,
99w: *std.Io.Writer,
1010
......@@ -98,53 +98,48 @@ pub fn emitMir(emit: *Emit) Error!void {
9898 .op_index = lowered_relocs[0].op_index,
9999 .off = lowered_relocs[0].off,
100100 .target = target: switch (lowered_relocs[0].target) {
101 .inst => |inst| .{ .index = inst, .is_extern = false, .type = .inst },
102 .table => .{ .index = undefined, .is_extern = false, .type = .table },
101 .inst => |inst| .{ .inst = inst },
102 .table => .table,
103103 .nav => |nav| {
104 const sym_index = switch (try codegen.genNavRef(
104 const symbol_id = switch (try codegen.genNavRef(
105105 emit.bin_file,
106106 emit.pt,
107107 emit.lower.src_loc,
108108 nav,
109109 emit.lower.target,
110110 )) {
111 .sym_index => |sym_index| sym_index,
111 .sym_index => |symbol_id| symbol_id,
112112 .fail => |em| {
113113 assert(emit.lower.err_msg == null);
114114 emit.lower.err_msg = em;
115115 return error.EmitFail;
116116 },
117117 };
118 const resolved_nav = ip.getNav(nav).resolved.?;
119 if (resolved_nav.value != .none) switch (ip.indexToKey(resolved_nav.value)) {
120 .@"extern" => |@"extern"| break :target .{
121 .index = sym_index,
122 .is_extern = switch (@"extern".visibility) {
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 },
118 const target_symbol: RelocInfo.Target.Symbol = if (ip.getNav(nav).getExtern(ip)) |@"extern"| .{
119 .symbol = symbol_id,
120 .is_extern = switch (@"extern".visibility) {
121 .default => true,
122 .hidden, .protected => false,
131123 },
132 else => {},
133 };
134 break :target .{
135 .index = sym_index,
136 .is_extern = false,
137 .type = if (resolved_nav.@"threadlocal" and comp.config.any_non_single_threaded) .tlv else .symbol,
138 };
124 .force_pcrel_direct = switch (@"extern".relocation) {
125 .any => false,
126 .pcrel => true,
127 },
128 } else .{ .symbol = symbol_id, .is_extern = false };
129 if (ip.getNav(nav).resolved.?.@"threadlocal" and comp.config.any_non_single_threaded) {
130 break :target .{ .tlv = target_symbol };
131 } else {
132 break :target .{ .symbol = target_symbol };
133 }
139134 },
140 .uav => |uav| .{
141 .index = switch (try emit.bin_file.lowerUav(
135 .uav => |uav| .{ .symbol = .{
136 .symbol = switch (try emit.bin_file.lowerUav(
142137 emit.pt,
143138 uav.val,
144139 Type.fromInterned(uav.orig_ty).ptrAlignment(emit.pt.zcu),
145140 emit.lower.src_loc,
146141 )) {
147 .sym_index => |sym_index| sym_index,
142 .sym_index => |symbol_id| symbol_id,
148143 .fail => |em| {
149144 assert(emit.lower.err_msg == null);
150145 emit.lower.err_msg = em;
......@@ -152,55 +147,57 @@ pub fn emitMir(emit: *Emit) Error!void {
152147 },
153148 },
154149 .is_extern = false,
155 .type = .symbol,
156 },
157 .lazy_sym => |lazy_sym| .{
158 .index = if (emit.bin_file.cast(.elf)) |elf_file|
159 elf_file.zigObjectPtr().?.getOrCreateMetadataForLazySymbol(elf_file, emit.pt, lazy_sym) catch |err|
160 return emit.fail("{s} creating lazy symbol", .{@errorName(err)})
150 } },
151 .lazy_sym => |lazy_sym| .{ .symbol = .{
152 .symbol = if (emit.bin_file.cast(.elf)) |elf_file|
153 @enumFromInt(
154 elf_file.zigObjectPtr().?.getOrCreateMetadataForLazySymbol(elf_file, emit.pt, lazy_sym) catch |err|
155 return emit.fail("{s} creating lazy symbol", .{@errorName(err)}),
156 )
161157 else if (emit.bin_file.cast(.elf2)) |elf|
162 @intFromEnum(try elf.lazySymbol(lazy_sym))
158 try elf.lazySymbol(lazy_sym)
163159 else if (emit.bin_file.cast(.macho)) |macho_file|
164 macho_file.getZigObject().?.getOrCreateMetadataForLazySymbol(macho_file, emit.pt, lazy_sym) catch |err|
165 return emit.fail("{s} creating lazy symbol", .{@errorName(err)})
166 else if (emit.bin_file.cast(.coff2)) |elf|
167 @intFromEnum(try elf.lazySymbol(lazy_sym))
160 @enumFromInt(macho_file.getZigObject().?.getOrCreateMetadataForLazySymbol(macho_file, emit.pt, lazy_sym) catch |err|
161 return emit.fail("{s} creating lazy symbol", .{@errorName(err)}))
162 else if (emit.bin_file.cast(.coff2)) |coff|
163 @enumFromInt(@intFromEnum(try coff.lazySymbol(lazy_sym)))
168164 else
169165 return emit.fail("lazy symbols unimplemented for {s}", .{@tagName(emit.bin_file.tag)}),
170166 .is_extern = false,
171 .type = .symbol,
172 },
173 .extern_func => |extern_func| .{
174 .index = if (emit.bin_file.cast(.elf)) |elf_file|
175 try elf_file.getGlobalSymbol(extern_func.toSlice(&emit.lower.mir).?, null)
176 else if (emit.bin_file.cast(.elf2)) |elf| @intFromEnum(try elf.globalSymbol(.{
167 } },
168 .extern_func => |extern_func| .{ .symbol = .{
169 .symbol = if (emit.bin_file.cast(.elf)) |elf_file|
170 @enumFromInt(try elf_file.getGlobalSymbol(extern_func.toSlice(&emit.lower.mir).?, null))
171 else if (emit.bin_file.cast(.elf2)) |elf| elf.externSymbol(.{
177172 .name = extern_func.toSlice(&emit.lower.mir).?,
178173 .lib_name = switch (comp.compiler_rt_strat) {
179174 .none, .lib, .obj, .zcu => null,
180175 .dyn_lib => "compiler_rt",
181176 },
182177 .type = .FUNC,
183 })) else if (emit.bin_file.cast(.macho)) |macho_file|
184 try macho_file.getGlobalSymbol(extern_func.toSlice(&emit.lower.mir).?, null)
185 else if (emit.bin_file.cast(.coff2)) |coff| @intFromEnum(try coff.globalSymbol(
178 }) catch |err| switch (err) {
179 error.LinkOnceUnsupported => unreachable,
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(
186184 extern_func.toSlice(&emit.lower.mir).?,
187185 switch (comp.compiler_rt_strat) {
188186 .none, .lib, .obj, .zcu => null,
189187 .dyn_lib => "compiler_rt",
190188 },
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)}),
192190 .is_extern = true,
193 .type = .symbol,
194 },
191 } },
195192 },
196193 };
197194 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) {
199196 .inst, .table => {},
200 .symbol => {
197 .symbol => |target| {
201198 switch (lowered_inst.encoding.mnemonic) {
202199 .call => {
203 reloc.target.type = .branch;
200 reloc.target = .{ .branch = target };
204201 try emit.encodeInst(lowered_inst, reloc_info);
205202 continue :lowered_inst;
206203 },
......@@ -217,7 +214,7 @@ pub fn emitMir(emit: *Emit) Error!void {
217214 .{ .mem = .initSib(lowered_inst.ops[reloc.op_index].mem.sib.ptr_size, .{}) },
218215 }, emit.lower.target), reloc_info),
219216 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) {
221218 .lea => try emit.encodeInst(try .new(.none, .mov, &.{
222219 lowered_inst.ops[0],
223220 .{ .mem = .initRip(.ptr, 0) },
......@@ -247,7 +244,7 @@ pub fn emitMir(emit: *Emit) Error!void {
247244 else => unreachable,
248245 }
249246 } 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) {
251248 .lea => try emit.encodeInst(try .new(.none, .mov, &.{
252249 lowered_inst.ops[0],
253250 .{ .mem = .initRip(.ptr, 0) },
......@@ -294,7 +291,7 @@ pub fn emitMir(emit: *Emit) Error!void {
294291 continue :lowered_inst;
295292 },
296293 .branch, .tls => unreachable,
297 .tlv => {
294 .tlv => |target| {
298295 if (emit.bin_file.cast(.elf) != null or emit.bin_file.cast(.elf2) != null) {
299296 // TODO handle extern TLS vars, i.e., emit GD model
300297 if (emit.pic) switch (lowered_inst.encoding.mnemonic) {
......@@ -306,28 +303,26 @@ pub fn emitMir(emit: *Emit) Error!void {
306303 .{ .mem = .initRip(.none, 0) },
307304 }, emit.lower.target), &.{.{
308305 .op_index = 1,
309 .target = .{
310 .index = reloc.target.index,
311 .is_extern = false,
312 .type = .tls,
313 },
306 .target = .{ .tls = target.symbol },
314307 }});
315308 try emit.encodeInst(try .new(.none, .call, &.{
316309 .{ .imm = .s(0) },
317310 }, emit.lower.target), &.{.{
318311 .op_index = 0,
319 .target = .{
320 .index = if (emit.bin_file.cast(.elf)) |elf_file| try elf_file.getGlobalSymbol(
312 .target = .{ .branch = .{
313 .symbol = if (emit.bin_file.cast(.elf)) |elf_file| @enumFromInt(try elf_file.getGlobalSymbol(
321314 "__tls_get_addr",
322315 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(.{
324317 .name = "__tls_get_addr",
325318 .lib_name = if (comp.config.link_libc) "c" else null,
326319 .type = .FUNC,
327 })) else unreachable,
320 }) catch |err| switch (err) {
321 error.LinkOnceUnsupported => unreachable,
322 else => |e| return e,
323 } else unreachable,
328324 .is_extern = true,
329 .type = .branch,
330 },
325 } },
331326 }});
332327 try emit.encodeInst(try .new(.none, lowered_inst.encoding.mnemonic, &.{
333328 lowered_inst.ops[0],
......@@ -399,13 +394,12 @@ pub fn emitMir(emit: *Emit) Error!void {
399394 .{ .mem = .initSib(.dword, .{}) },
400395 }, emit.lower.target), &.{.{
401396 .op_index = 1,
402 .target = .{
403 .index = @intFromEnum(
397 .target = .{ .symbol = .{
398 .symbol = @enumFromInt(@intFromEnum(
404399 try coff.globalSymbol("__tls_index", null),
405 ),
400 )),
406401 .is_extern = false,
407 .type = .symbol,
408 },
402 } },
409403 }});
410404 try emit.encodeInst(try .new(.none, .mov, &.{
411405 .{ .reg = .eax },
......@@ -435,13 +429,12 @@ pub fn emitMir(emit: *Emit) Error!void {
435429 .{ .mem = .initRip(.dword, 0) },
436430 }, emit.lower.target), &.{.{
437431 .op_index = 1,
438 .target = .{
439 .index = @intFromEnum(
432 .target = .{ .symbol = .{
433 .symbol = @enumFromInt(@intFromEnum(
440434 try coff.globalSymbol("_tls_index", null),
441 ),
435 )),
442436 .is_extern = false,
443 .type = .symbol,
444 },
437 } },
445438 }});
446439 try emit.encodeInst(try .new(.none, .mov, &.{
447440 .{ .reg = .rax },
......@@ -713,17 +706,17 @@ pub fn emitMir(emit: *Emit) Error!void {
713706 var table_offset = std.mem.alignForward(u32, @intCast(emit.w.end), ptr_size);
714707 if (emit.bin_file.cast(.elf)) |elf_file| {
715708 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
718711 for (emit.table_relocs.items) |table_reloc| try atom.addReloc(gpa, .{
719712 .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"),
721714 .r_addend = @as(i64, table_offset) + table_reloc.target_offset,
722715 }, zo);
723716 for (emit.lower.mir.table) |entry| {
724717 try atom.addReloc(gpa, .{
725718 .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"),
727720 .r_addend = emit.code_offset_mapping.items[entry],
728721 }, zo);
729722 table_offset += ptr_size;
......@@ -731,17 +724,17 @@ pub fn emitMir(emit: *Emit) Error!void {
731724 try emit.w.splatByteAll(0, table_offset - emit.w.end);
732725 } else if (emit.bin_file.cast(.elf2)) |elf| {
733726 for (emit.table_relocs.items) |table_reloc| try elf.addReloc(
734 @enumFromInt(emit.atom_index),
727 emit.atom_id,
735728 table_reloc.source_offset,
736 @enumFromInt(emit.atom_index),
729 elf.symbolForAtom(emit.atom_id),
737730 @as(i64, table_offset) + table_reloc.target_offset,
738731 .{ .X86_64 = .@"32S" },
739732 );
740733 for (emit.lower.mir.table) |entry| {
741734 try elf.addReloc(
742 @enumFromInt(emit.atom_index),
735 emit.atom_id,
743736 table_offset,
744 @enumFromInt(emit.atom_index),
737 elf.symbolForAtom(emit.atom_id),
745738 emit.code_offset_mapping.items[entry],
746739 .{ .X86_64 = .@"64" },
747740 );
......@@ -765,13 +758,19 @@ const RelocInfo = struct {
765758 off: i32 = 0,
766759 target: Target,
767760
768 const Target = struct {
769 index: u32,
770 is_extern: bool,
771 type: Target.Type,
772 force_pcrel_direct: bool = false,
761 const Target = union(enum) {
762 inst: Mir.Inst.Index,
763 table,
764 branch: Symbol,
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 };
775774 };
776775};
777776
......@@ -784,8 +783,8 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI
784783 else => |e| return e,
785784 };
786785 const end_offset: u32 = @intCast(emit.w.end);
787 for (reloc_info) |reloc| switch (reloc.target.type) {
788 .inst => {
786 for (reloc_info) |reloc| switch (reloc.target) {
787 .inst => |target_inst| {
789788 const inst_length: u4 = @intCast(end_offset - start_offset);
790789 const reloc_offset, const reloc_length = reloc_offset_length: {
791790 var reloc_offset = inst_length;
......@@ -809,7 +808,7 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI
809808 .inst_length = inst_length,
810809 .source_offset = reloc_offset,
811810 .source_length = reloc_length,
812 .target = reloc.target.index,
811 .target = target_inst,
813812 .target_offset = reloc.off,
814813 });
815814 },
......@@ -817,146 +816,146 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI
817816 .source_offset = end_offset - 4,
818817 .target_offset = reloc.off,
819818 }),
820 .symbol => if (emit.bin_file.cast(.elf)) |elf_file| {
819 .symbol => |target| if (emit.bin_file.cast(.elf)) |elf_file| {
821820 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).?;
823822 const r_type: std.elf.R_X86_64 = if (!emit.pic)
824823 .@"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)
826825 .GOTPCREL
827826 else
828827 .PC32;
829828 try atom.addReloc(gpa, .{
830829 .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),
832831 .r_addend = if (emit.pic) reloc.off - 4 else reloc.off,
833832 }, zo);
834833 } else if (emit.bin_file.cast(.macho)) |macho_file| {
835834 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).?;
837836 try atom.addReloc(macho_file, .{
838837 .tag = .@"extern",
839838 .offset = end_offset - 4,
840 .target = reloc.target.index,
839 .target = @intFromEnum(target.symbol),
841840 .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,
843842 .meta = .{
844843 .pcrel = true,
845844 .has_subtractor = false,
846845 .length = 2,
847 .symbolnum = @intCast(reloc.target.index),
846 .symbolnum = @intCast(@intFromEnum(target.symbol)),
848847 },
849848 });
850849 } else if (emit.bin_file.cast(.elf2)) |elf| try elf.addReloc(
851 @enumFromInt(emit.atom_index),
850 emit.atom_id,
852851 end_offset - 4,
853 @enumFromInt(reloc.target.index),
852 target.symbol,
854853 reloc.off,
855854 .{ .X86_64 = .@"32S" },
856855 ) else if (emit.bin_file.cast(.coff2)) |coff| try coff.addReloc(
857 @enumFromInt(emit.atom_index),
856 @enumFromInt(@intFromEnum(emit.atom_id)),
858857 end_offset - 4,
859 @enumFromInt(reloc.target.index),
858 @enumFromInt(@intFromEnum(target.symbol)),
860859 reloc.off,
861860 .{ .AMD64 = .REL32 },
862861 ) else unreachable,
863 .branch => if (emit.bin_file.cast(.elf)) |elf_file| {
862 .branch => |target| if (emit.bin_file.cast(.elf)) |elf_file| {
864863 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).?;
866865 const r_type: std.elf.R_X86_64 = .PLT32;
867866 try atom.addReloc(gpa, .{
868867 .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),
870869 .r_addend = reloc.off - 4,
871870 }, zo);
872871 } else if (emit.bin_file.cast(.elf2)) |elf| try elf.addReloc(
873 @enumFromInt(emit.atom_index),
872 emit.atom_id,
874873 end_offset - 4,
875 @enumFromInt(reloc.target.index),
874 target.symbol,
876875 reloc.off - 4,
877876 .{ .X86_64 = .PLT32 },
878877 ) else if (emit.bin_file.cast(.macho)) |macho_file| {
879878 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).?;
881880 try atom.addReloc(macho_file, .{
882881 .tag = .@"extern",
883882 .offset = end_offset - 4,
884 .target = reloc.target.index,
883 .target = @intFromEnum(target.symbol),
885884 .addend = reloc.off,
886885 .type = .branch,
887886 .meta = .{
888887 .pcrel = true,
889888 .has_subtractor = false,
890889 .length = 2,
891 .symbolnum = @intCast(reloc.target.index),
890 .symbolnum = @intCast(@intFromEnum(target.symbol)),
892891 },
893892 });
894893 } else if (emit.bin_file.cast(.coff2)) |coff| try coff.addReloc(
895 @enumFromInt(emit.atom_index),
894 @enumFromInt(@intFromEnum(emit.atom_id)),
896895 end_offset - 4,
897 @enumFromInt(reloc.target.index),
896 @enumFromInt(@intFromEnum(target.symbol)),
898897 reloc.off,
899898 .{ .AMD64 = .REL32 },
900899 ) 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),
902901 }),
903 .tls => if (emit.bin_file.cast(.elf)) |elf_file| {
902 .tls => |target_symbol| if (emit.bin_file.cast(.elf)) |elf_file| {
904903 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).?;
906905 const r_type: std.elf.R_X86_64 = if (emit.pic) .TLSLD else unreachable;
907906 try atom.addReloc(gpa, .{
908907 .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),
910909 .r_addend = reloc.off - 4,
911910 }, zo);
912911 } else if (emit.bin_file.cast(.elf2)) |elf| try elf.addReloc(
913 @enumFromInt(emit.atom_index),
912 emit.atom_id,
914913 end_offset - 4,
915 @enumFromInt(reloc.target.index),
914 target_symbol,
916915 reloc.off - 4,
917916 .{ .X86_64 = if (emit.pic) .TLSLD else unreachable },
918917 ) 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),
920919 }),
921 .tlv => if (emit.bin_file.cast(.elf)) |elf_file| {
920 .tlv => |target| if (emit.bin_file.cast(.elf)) |elf_file| {
922921 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).?;
924923 const r_type: std.elf.R_X86_64 = if (emit.pic) .DTPOFF32 else .TPOFF32;
925924 try atom.addReloc(gpa, .{
926925 .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),
928927 .r_addend = reloc.off,
929928 }, zo);
930929 } else if (emit.bin_file.cast(.elf2)) |elf| try elf.addReloc(
931 @enumFromInt(emit.atom_index),
930 emit.atom_id,
932931 end_offset - 4,
933 @enumFromInt(reloc.target.index),
932 target.symbol,
934933 reloc.off,
935934 .{ .X86_64 = if (emit.pic) .DTPOFF32 else .TPOFF32 },
936935 ) else if (emit.bin_file.cast(.macho)) |macho_file| {
937936 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).?;
939938 try atom.addReloc(macho_file, .{
940939 .tag = .@"extern",
941940 .offset = end_offset - 4,
942 .target = reloc.target.index,
941 .target = @intFromEnum(target.symbol),
943942 .addend = reloc.off,
944943 .type = .tlv,
945944 .meta = .{
946945 .pcrel = true,
947946 .has_subtractor = false,
948947 .length = 2,
949 .symbolnum = @intCast(reloc.target.index),
948 .symbolnum = @intCast(@intFromEnum(target.symbol)),
950949 },
951950 });
952951 } else if (emit.bin_file.cast(.coff2)) |coff| try coff.addReloc(
953 @enumFromInt(emit.atom_index),
952 @enumFromInt(@intFromEnum(emit.atom_id)),
954953 end_offset - 4,
955 @enumFromInt(reloc.target.index),
954 @enumFromInt(@intFromEnum(target.symbol)),
956955 reloc.off,
957956 .{ .AMD64 = .SECREL },
958957 ) 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),
960959 }),
961960 };
962961}
src/codegen/x86_64/Mir.zig+4-4
......@@ -1976,7 +1976,7 @@ pub fn emit(
19761976 pt: Zcu.PerThread,
19771977 src_loc: Zcu.LazySrcLoc,
19781978 func_index: InternPool.Index,
1979 atom_index: u32,
1979 atom_id: link.File.AtomId,
19801980 w: *std.Io.Writer,
19811981 debug_output: link.File.DebugInfoOutput,
19821982) codegen.CodeGenError!void {
......@@ -1998,7 +1998,7 @@ pub fn emit(
19981998 .bin_file = lf,
19991999 .pt = pt,
20002000 .pic = mod.pic,
2001 .atom_index = atom_index,
2001 .atom_id = atom_id,
20022002 .debug_output = debug_output,
20032003 .w = w,
20042004
......@@ -2030,7 +2030,7 @@ pub fn emitLazy(
20302030 pt: Zcu.PerThread,
20312031 src_loc: Zcu.LazySrcLoc,
20322032 lazy_sym: link.File.LazySymbol,
2033 atom_index: u32,
2033 atom_id: link.File.AtomId,
20342034 w: *std.Io.Writer,
20352035 debug_output: link.File.DebugInfoOutput,
20362036) codegen.CodeGenError!void {
......@@ -2049,7 +2049,7 @@ pub fn emitLazy(
20492049 .bin_file = lf,
20502050 .pt = pt,
20512051 .pic = mod.pic,
2052 .atom_index = atom_index,
2052 .atom_id = atom_id,
20532053 .debug_output = debug_output,
20542054 .w = w,
20552055
src/link.zig+14-2
......@@ -759,12 +759,24 @@ pub const File = struct {
759759 /// must be attached to `Zcu.failed_codegen` rather than `Compilation.link_diags`.
760760 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
762774 /// Called from within CodeGen to retrieve the symbol index of a global symbol.
763775 /// If no symbol exists yet with this name, a new undefined global symbol will
764776 /// be created. This symbol may get resolved once all relocatables are (re-)linked.
765777 /// Optionally, it is possible to specify where to expect the symbol defined if it
766778 /// 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 {
768780 log.debug("getGlobalSymbol '{s}' (expected in '{?s}')", .{ name, lib_name });
769781 switch (base.tag) {
770782 .lld => unreachable,
......@@ -1008,7 +1020,7 @@ pub const File = struct {
10081020
10091021 pub const Parent = union(enum) {
10101022 none,
1011 atom_index: u32,
1023 atom_index: AtomId,
10121024 debug_output: DebugInfoOutput,
10131025 };
10141026 };
src/link/Coff.zig+8-8
......@@ -1328,7 +1328,7 @@ pub fn getUavVAddr(
13281328
13291329pub fn getVAddr(coff: *Coff, reloc_info: link.File.RelocInfo, target_si: Symbol.Index) !u64 {
13301330 try coff.addReloc(
1331 @enumFromInt(reloc_info.parent.atom_index),
1331 @enumFromInt(@intFromEnum(reloc_info.parent.atom_index)),
13321332 reloc_info.offset,
13331333 target_si,
13341334 reloc_info.addend,
......@@ -1581,7 +1581,7 @@ fn updateNavInner(coff: *Coff, pt: Zcu.PerThread, nav_index: InternPool.Nav.Inde
15811581 zcu.navSrcLoc(nav_index),
15821582 .fromInterned(nav.resolved.?.value),
15831583 &nw.interface,
1584 .{ .atom_index = @intFromEnum(si) },
1584 .{ .atom_index = @enumFromInt(@intFromEnum(si)) },
15851585 ) catch |err| switch (err) {
15861586 error.WriteFailed => return error.OutOfMemory,
15871587 else => |e| return e,
......@@ -1637,7 +1637,7 @@ pub fn lowerUav(
16371637 coff.const_prog_node.increaseEstimatedTotalItems(1);
16381638 }
16391639 }
1640 return .{ .sym_index = @intFromEnum(si) };
1640 return .{ .sym_index = @enumFromInt(@intFromEnum(si)) };
16411641}
16421642
16431643pub fn updateFunc(
......@@ -1715,7 +1715,7 @@ fn updateFuncInner(
17151715 pt,
17161716 zcu.navSrcLoc(func.owner_nav),
17171717 func_index,
1718 @intFromEnum(si),
1718 @enumFromInt(@intFromEnum(si)),
17191719 mir,
17201720 &nw.interface,
17211721 .none,
......@@ -1930,7 +1930,7 @@ fn flushUav(
19301930 src_loc,
19311931 .fromInterned(uav_val),
19321932 &nw.interface,
1933 .{ .atom_index = @intFromEnum(si) },
1933 .{ .atom_index = @enumFromInt(@intFromEnum(si)) },
19341934 ) catch |err| switch (err) {
19351935 error.WriteFailed => return error.OutOfMemory,
19361936 else => |e| return e,
......@@ -2146,7 +2146,7 @@ fn flushLazy(coff: *Coff, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void {
21462146 &required_alignment,
21472147 &nw.interface,
21482148 .none,
2149 .{ .atom_index = @intFromEnum(si) },
2149 .{ .atom_index = @enumFromInt(@intFromEnum(si)) },
21502150 );
21512151 si.get(coff).size = @intCast(nw.interface.end);
21522152 si.applyLocationRelocs(coff);
......@@ -2339,7 +2339,7 @@ fn updateExportsInner(
23392339 try coff.symbol_table.ensureUnusedCapacity(gpa, export_indices.len);
23402340 const exported_si: Symbol.Index = switch (exported) {
23412341 .nav => |nav| try coff.navSymbol(zcu, nav),
2342 .uav => |uav| @enumFromInt(switch (try coff.lowerUav(
2342 .uav => |uav| @enumFromInt(@intFromEnum(switch (try coff.lowerUav(
23432343 pt,
23442344 uav,
23452345 Type.fromInterned(ip.typeOf(uav)).abiAlignment(zcu),
......@@ -2350,7 +2350,7 @@ fn updateExportsInner(
23502350 defer em.destroy(gpa);
23512351 return coff.base.comp.link_diags.fail("{s}", .{em.msg});
23522352 },
2353 }),
2353 })),
23542354 };
23552355 while (try coff.idle(pt.tid)) {}
23562356 const exported_ni = exported_si.node(coff);
src/link/Dwarf.zig+10-10
......@@ -1151,13 +1151,13 @@ const CrossSectionReloc = struct {
11511151};
11521152const ExternalReloc = struct {
11531153 source_off: u32 = 0,
1154 target_sym: u32,
1154 target_sym: link.File.SymbolId,
11551155 target_off: u64 = 0,
11561156};
11571157
11581158pub const Loc = union(enum) {
11591159 empty,
1160 addr_reloc: u32,
1160 addr_reloc: link.File.SymbolId,
11611161 deref: *const Loc,
11621162 constu: u64,
11631163 consts: i64,
......@@ -1506,7 +1506,7 @@ pub const WipNav = struct {
15061506 entry: Entry.Index,
15071507 any_children: bool,
15081508 func: InternPool.Index,
1509 func_sym_index: u32,
1509 func_sym_index: link.File.SymbolId,
15101510 func_high_pc: u32,
15111511 blocks: std.ArrayList(struct {
15121512 abbrev_code: u32,
......@@ -1966,7 +1966,7 @@ pub const WipNav = struct {
19661966 fn endian(_: ExprLocCounter) std.lang.Endian {
19671967 return @import("builtin").cpu.arch.endian();
19681968 }
1969 fn addrSym(counter: *ExprLocCounter, _: u32) Writer.Error!void {
1969 fn addrSym(counter: *ExprLocCounter, _: link.File.SymbolId) Writer.Error!void {
19701970 try counter.dw.writer.splatByteAll(undefined, @intFromEnum(counter.address_size));
19711971 }
19721972 fn infoEntry(counter: *ExprLocCounter, _: Unit.Index, _: Entry.Index) Writer.Error!void {
......@@ -1987,7 +1987,7 @@ pub const WipNav = struct {
19871987 fn endian(ctx: @This()) std.lang.Endian {
19881988 return ctx.wip_nav.dwarf.endian;
19891989 }
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 {
19911991 try ctx.wip_nav.infoAddrSym(sym_index, 0);
19921992 }
19931993 fn infoEntry(
......@@ -2004,7 +2004,7 @@ pub const WipNav = struct {
20042004
20052005 fn infoAddrSym(
20062006 wip_nav: *WipNav,
2007 sym_index: u32,
2007 sym_index: link.File.SymbolId,
20082008 sym_off: u64,
20092009 ) (UpdateError || Writer.Error)!void {
20102010 const diw = &wip_nav.debug_info.writer;
......@@ -2029,7 +2029,7 @@ pub const WipNav = struct {
20292029 fn endian(ctx: @This()) std.lang.Endian {
20302030 return ctx.wip_nav.dwarf.endian;
20312031 }
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 {
20332033 try ctx.wip_nav.frameAddrSym(sym_index, 0);
20342034 }
20352035 fn infoEntry(
......@@ -2046,7 +2046,7 @@ pub const WipNav = struct {
20462046
20472047 fn frameAddrSym(
20482048 wip_nav: *WipNav,
2049 sym_index: u32,
2049 sym_index: link.File.SymbolId,
20502050 sym_off: u64,
20512051 ) (UpdateError || Writer.Error)!void {
20522052 const dfw = &wip_nav.debug_frame.writer;
......@@ -2591,7 +2591,7 @@ pub fn initWipNav(
25912591 dwarf: *Dwarf,
25922592 pt: Zcu.PerThread,
25932593 nav_index: InternPool.Nav.Index,
2594 sym_index: u32,
2594 sym_index: link.File.SymbolId,
25952595) error{ OutOfMemory, CodegenFail }!WipNav {
25962596 return initWipNavInner(dwarf, pt, nav_index, sym_index) catch |err| switch (err) {
25972597 error.OutOfMemory => error.OutOfMemory,
......@@ -2603,7 +2603,7 @@ fn initWipNavInner(
26032603 dwarf: *Dwarf,
26042604 pt: Zcu.PerThread,
26052605 nav_index: InternPool.Nav.Index,
2606 sym_index: u32,
2606 sym_index: link.File.SymbolId,
26072607) !WipNav {
26082608 const zcu = pt.zcu;
26092609 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 {
461461 }, self);
462462 }
463463 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));
465465 const r_offset = entry_off + reloc.source_off;
466466 const r_addend: i64 = @intCast(reloc.target_off);
467467 const r_type = relocation.dwarf.externalRelocType(target_sym.*, sect_index, dwarf.address_size, cpu_arch);
468468 atom_ptr.addRelocAssumeCapacity(.{
469469 .r_offset = r_offset,
470470 .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,
472472 }, self);
473473 }
474474 }
......@@ -941,7 +941,7 @@ pub fn getNavVAddr(
941941 switch (reloc_info.parent) {
942942 .none => unreachable,
943943 .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).?;
945945 const r_type = relocation.encode(.abs, elf_file.getTarget().cpu.arch);
946946 try parent_atom.addReloc(elf_file.base.comp.gpa, .{
947947 .r_offset = reloc_info.offset,
......@@ -952,7 +952,7 @@ pub fn getNavVAddr(
952952 .debug_output => |debug_output| switch (debug_output) {
953953 .dwarf => |wip_nav| try wip_nav.infoExternalReloc(.{
954954 .source_off = @intCast(reloc_info.offset),
955 .target_sym = this_sym_index,
955 .target_sym = @enumFromInt(this_sym_index),
956956 .target_off = reloc_info.addend,
957957 }),
958958 .none => unreachable,
......@@ -973,7 +973,7 @@ pub fn getUavVAddr(
973973 switch (reloc_info.parent) {
974974 .none => unreachable,
975975 .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).?;
977977 const r_type = relocation.encode(.abs, elf_file.getTarget().cpu.arch);
978978 try parent_atom.addReloc(elf_file.base.comp.gpa, .{
979979 .r_offset = reloc_info.offset,
......@@ -984,7 +984,7 @@ pub fn getUavVAddr(
984984 .debug_output => |debug_output| switch (debug_output) {
985985 .dwarf => |wip_nav| try wip_nav.infoExternalReloc(.{
986986 .source_off = @intCast(reloc_info.offset),
987 .target_sym = sym_index,
987 .target_sym = @enumFromInt(sym_index),
988988 .target_off = reloc_info.addend,
989989 }),
990990 .none => unreachable,
......@@ -1013,7 +1013,7 @@ pub fn lowerUav(
10131013 const sym = self.symbol(metadata.symbol_index);
10141014 const existing_alignment = sym.atom(elf_file).?.alignment;
10151015 if (uav_alignment.order(existing_alignment).compare(.lte))
1016 return .{ .sym_index = metadata.symbol_index };
1016 return .{ .sym_index = @enumFromInt(metadata.symbol_index) };
10171017 }
10181018
10191019 const osec = if (self.data_relro_index) |sym_index|
......@@ -1051,7 +1051,10 @@ pub fn lowerUav(
10511051 ) },
10521052 };
10531053 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 }),
10551058 .fail => {},
10561059 }
10571060 return res;
......@@ -1545,7 +1548,11 @@ pub fn updateFunc(
15451548 var aw: std.Io.Writer.Allocating = .init(gpa);
15461549 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;
15491556 defer if (debug_wip_nav) |*wip_nav| wip_nav.deinit();
15501557
15511558 codegen.emitFunction(
......@@ -1553,7 +1560,7 @@ pub fn updateFunc(
15531560 pt,
15541561 zcu.navSrcLoc(func.owner_nav),
15551562 func_index,
1556 sym_index,
1563 @enumFromInt(sym_index),
15571564 mir,
15581565 &aw.writer,
15591566 if (debug_wip_nav) |*dn| .{ .dwarf = dn } else .none,
......@@ -1660,7 +1667,7 @@ pub fn updateNav(
16601667 self.symbol(sym_index).flags.is_tls = true;
16611668 }
16621669 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));
16641671 defer debug_wip_nav.deinit();
16651672 dwarf.finishWipNav(pt, nav_index, &debug_wip_nav) catch |err| switch (err) {
16661673 error.OutOfMemory, error.Overflow => |e| return e,
......@@ -1678,7 +1685,7 @@ pub fn updateNav(
16781685 var aw: std.Io.Writer.Allocating = .init(zcu.gpa);
16791686 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;
16821689 defer if (debug_wip_nav) |*wip_nav| wip_nav.deinit();
16831690
16841691 codegen.generateSymbol(
......@@ -1687,7 +1694,7 @@ pub fn updateNav(
16871694 zcu.navSrcLoc(nav_index),
16881695 .fromInterned(nav.resolved.?.value),
16891696 &aw.writer,
1690 .{ .atom_index = sym_index },
1697 .{ .atom_index = @enumFromInt(sym_index) },
16911698 ) catch |err| switch (err) {
16921699 error.WriteFailed => return error.OutOfMemory,
16931700 else => |e| return e,
......@@ -1757,7 +1764,7 @@ fn updateLazySymbol(
17571764 &required_alignment,
17581765 &aw.writer,
17591766 .none,
1760 .{ .atom_index = symbol_index },
1767 .{ .atom_index = @enumFromInt(symbol_index) },
17611768 ) catch |err| switch (err) {
17621769 error.WriteFailed => return error.OutOfMemory,
17631770 else => |e| return e,
......@@ -1836,7 +1843,7 @@ fn lowerConst(
18361843 src_loc,
18371844 val,
18381845 &aw.writer,
1839 .{ .atom_index = sym_index },
1846 .{ .atom_index = @enumFromInt(sym_index) },
18401847 ) catch |err| switch (err) {
18411848 error.WriteFailed => return error.OutOfMemory,
18421849 else => |e| return e,
......@@ -1858,7 +1865,7 @@ fn lowerConst(
18581865
18591866 try elf_file.pwriteAll(code, atom_ptr.offset(elf_file));
18601867
1861 return .{ .sym_index = sym_index };
1868 return .{ .sym_index = @enumFromInt(sym_index) };
18621869}
18631870
18641871pub fn updateExports(
src/link/Elf2.zig+2112-1191
......@@ -25,55 +25,102 @@ ni: Node.Known,
2525nodes: std.MultiArrayList(Node),
2626shdrs: std.ArrayList(Section),
2727phdrs: 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},
2938symtab: 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)),
3053shstrtab: StringTable,
3154strtab: StringTable,
32dynsym: std.AutoArrayHashMapUnmanaged(Symbol.Index, void),
3355dynstr: StringTable,
3456got: struct {
3557 len: u32,
3658 tlsld: GotIndex,
37 plt: std.AutoArrayHashMapUnmanaged(Symbol.Index, void),
59 plt: std.AutoArrayHashMapUnmanaged(Symbol.Id, void),
3860},
39needed: std.AutoArrayHashMapUnmanaged(u32, void),
61first_plt_reloc: Reloc.Index,
62first_dynamic_reloc: Reloc.Index,
63needed: std.AutoArrayHashMapUnmanaged(String(.dynstr), void),
4064inputs: std.ArrayList(struct {
4165 path: std.Build.Cache.Path,
4266 member: ?[]const u8,
43 si: Symbol.Index,
44}),
45input_sections: std.ArrayList(struct {
46 ii: Node.InputIndex,
47 file_location: MappedFile.Node.FileLocation,
48 si: Symbol.Index,
67 file_symbol: Symbol.LocalIndex,
4968}),
69input_sections: std.ArrayList(InputSection),
5070input_section_pending_index: u32,
51globals: std.AutoArrayHashMapUnmanaged(u32, Symbol.Index),
52navs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, Symbol.Index),
53uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, Symbol.Index),
71navs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, struct {
72 /// The start index of the contiguous sequence of relocations in this NAV.
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}),
5481lazy: 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 }),
5687 pending_index: u32,
5788}),
58pending_uavs: std.AutoArrayHashMapUnmanaged(Node.UavMapIndex, struct {
59 alignment: InternPool.Alignment,
60 src_loc: Zcu.LazySrcLoc,
61}),
89pending_uavs: std.ArrayList(Node.UavMapIndex),
6290relocs: 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
6396const_prog_node: std.Progress.Node,
6497synth_prog_node: std.Progress.Node,
6598input_prog_node: std.Progress.Node,
6699
67pub const Node = union(enum) {
100const Node = union(enum) {
101 /// Cannot contain relocations.
68102 file,
103 /// Cannot contain relocations.
69104 ehdr,
105 /// Cannot contain relocations.
70106 shdr,
107 /// Cannot contain relocations.
71108 segment: u32,
72 section: Symbol.Index,
73 input_section: InputSectionIndex,
109 /// The section '.plt' may contain relocations via `elf.first_plt_reloc`.
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`.
74118 nav: NavMapIndex,
119 /// May contain relocations through the `first_reloc` field in `elf.uavs`.
75120 uav: UavMapIndex,
121 /// May contain relocations through the `first_reloc` field in `elf.lazy.map`.
76122 lazy_code: LazyMapRef.Index(.code),
123 /// May contain relocations through the `first_reloc` field in `elf.lazy.map`.
77124 lazy_const_data: LazyMapRef.Index(.const_data),
78125
79126 pub const InputIndex = enum(u32) {
......@@ -87,32 +134,20 @@ pub const Node = union(enum) {
87134 return elf.inputs.items[@intFromEnum(ii)].member;
88135 }
89136
90 pub fn symbol(ii: InputIndex, elf: *const Elf) Symbol.Index {
91 return elf.inputs.items[@intFromEnum(ii)].si;
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;
137 pub fn fileSymbol(ii: InputIndex, elf: *const Elf) Symbol.LocalIndex {
138 return elf.inputs.items[@intFromEnum(ii)].file_symbol;
112139 }
113140
114 pub fn symbol(isi: InputSectionIndex, elf: *const Elf) Symbol.Index {
115 return elf.input_sections.items[@intFromEnum(isi)].si;
141 pub fn localSymbolRange(ii: InputIndex, elf: *Elf) [2]Symbol.LocalIndex {
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 }
116151 }
117152 };
118153
......@@ -123,8 +158,12 @@ pub const Node = union(enum) {
123158 return elf.navs.keys()[@intFromEnum(nmi)];
124159 }
125160
126 pub fn symbol(nmi: NavMapIndex, elf: *const Elf) Symbol.Index {
127 return elf.navs.values()[@intFromEnum(nmi)];
161 pub fn symbol(nmi: NavMapIndex, elf: *const Elf) Symbol.LocalIndex {
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;
128167 }
129168 };
130169
......@@ -135,8 +174,12 @@ pub const Node = union(enum) {
135174 return elf.uavs.keys()[@intFromEnum(umi)];
136175 }
137176
138 pub fn symbol(umi: UavMapIndex, elf: *const Elf) Symbol.Index {
139 return elf.uavs.values()[@intFromEnum(umi)];
177 pub fn symbol(umi: UavMapIndex, elf: *const Elf) Symbol.LocalIndex {
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;
140183 }
141184 };
142185
......@@ -156,9 +199,13 @@ pub const Node = union(enum) {
156199 return lmi.ref().lazySymbol(elf);
157200 }
158201
159 pub fn symbol(lmi: @This(), elf: *const Elf) Symbol.Index {
202 pub fn symbol(lmi: @This(), elf: *const Elf) Symbol.LocalIndex {
160203 return lmi.ref().symbol(elf);
161204 }
205
206 fn firstReloc(lmi: @This(), elf: *const Elf) Reloc.Index {
207 return lmi.ref().firstReloc(elf);
208 }
162209 };
163210 }
164211
......@@ -166,8 +213,12 @@ pub const Node = union(enum) {
166213 return .{ .kind = lmr.kind, .ty = elf.lazy.getPtrConst(lmr.kind).map.keys()[lmr.index] };
167214 }
168215
169 pub fn symbol(lmr: LazyMapRef, elf: *const Elf) Symbol.Index {
170 return elf.lazy.getPtrConst(lmr.kind).map.values()[lmr.index];
216 pub fn symbol(lmr: LazyMapRef, elf: *const Elf) Symbol.LocalIndex {
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;
171222 }
172223 };
173224
......@@ -180,17 +231,66 @@ pub const Node = union(enum) {
180231 comptime text: MappedFile.Node.Index = @enumFromInt(5),
181232 comptime data: MappedFile.Node.Index = @enumFromInt(6),
182233 comptime data_rel_ro: MappedFile.Node.Index = @enumFromInt(7),
234
183235 tls: MappedFile.Node.Index,
184236 };
185237
186238 comptime {
187239 if (!std.debug.runtime_safety) std.debug.assert(@sizeOf(Node) == 8);
188240 }
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 }
189250};
190251
191pub const Section = struct {
192 si: Symbol.Index,
193 rela_si: Symbol.Index,
252const InputSection = struct {
253 input: Node.InputIndex,
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,
194294 rela_free: RelIndex,
195295
196296 pub const RelIndex = enum(u32) {
......@@ -207,394 +307,1165 @@ pub const Section = struct {
207307 };
208308 }
209309 };
210};
211310
212pub const Symbol = struct {
213 ni: MappedFile.Node.Index,
214 /// Relocations contained within this symbol
215 loc_relocs: Reloc.Index,
216 /// Relocations targeting this symbol
217 target_relocs: Reloc.Index,
218 unused: u32,
311 pub const Index = enum(Tag) {
312 UNDEF = std.elf.SHN_UNDEF,
313 LIVEPATCH = reserve(std.elf.SHN_LIVEPATCH),
314 ABS = reserve(std.elf.SHN_ABS),
315 COMMON = reserve(std.elf.SHN_COMMON),
219316
220 pub const Index = enum(u32) {
221 null,
222 symtab,
317 symtab = 1,
223318 shstrtab,
224319 strtab,
225320 rodata,
226321 text,
227322 data,
228323 data_rel_ro,
229 got,
230 got_plt,
231 plt,
232 plt_sec,
324
233325 _,
234326
235 pub fn get(si: Symbol.Index, elf: *Elf) *Symbol {
236 return &elf.symtab.items[@intFromEnum(si)];
327 pub const Tag = u32;
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));
237333 }
238334
239 pub fn node(si: Symbol.Index, elf: *Elf) MappedFile.Node.Index {
240 const ni = si.get(elf).ni;
241 assert(ni != .none);
242 return ni;
335 fn reserve(sec: std.elf.Section) Tag {
336 assert(sec >= std.elf.SHN_LORESERVE and sec <= std.elf.SHN_HIRESERVE);
337 return @as(Tag, std.math.maxInt(Tag) - std.elf.SHN_HIRESERVE) + sec;
243338 }
244339
245 pub fn next(si: Symbol.Index) Symbol.Index {
246 return @enumFromInt(@intFromEnum(si) + 1);
340 pub fn fromSection(sec: std.elf.Section) Index {
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 };
247354 }
248355
249 pub const Shndx = enum(Tag) {
250 UNDEF = std.elf.SHN_UNDEF,
251 LIVEPATCH = reserve(std.elf.SHN_LIVEPATCH),
252 ABS = reserve(std.elf.SHN_ABS),
253 COMMON = reserve(std.elf.SHN_COMMON),
254 _,
356 fn get(s: Index, elf: *Elf) *Section {
357 return &elf.shdrs.items[@intFromEnum(s)];
358 }
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);
259 pub const HIRESERVE: Shndx = .fromSection(std.elf.SHN_HIRESERVE);
260 comptime {
261 assert(@intFromEnum(HIRESERVE) == std.math.maxInt(Tag));
262 }
367 fn vaddr(s: Index, elf: *Elf) u64 {
368 return switch (s.get(elf).lsi) {
369 .null => 0,
370 else => |lsi| Symbol.Id.local(lsi).value(elf),
371 };
372 }
263373
264 fn reserve(sec: std.elf.Section) Tag {
265 assert(sec >= std.elf.SHN_LORESERVE and sec <= std.elf.SHN_HIRESERVE);
266 return @as(Tag, std.math.maxInt(Tag) - std.elf.SHN_HIRESERVE) + sec;
374 fn rename(shndx: Index, elf: *Elf, new_name: []const u8) !void {
375 const shstrtab_entry = try elf.string(.shstrtab, new_name);
376 switch (elf.shdrPtr(shndx)) {
377 inline else => |shdr| elf.targetStore(&shdr.name, @intFromEnum(shstrtab_entry)),
267378 }
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 {
270 return switch (sec) {
271 std.elf.SHN_UNDEF...std.elf.SHN_LORESERVE - 1 => @enumFromInt(sec),
272 std.elf.SHN_LORESERVE...std.elf.SHN_HIRESERVE => @enumFromInt(reserve(sec)),
416 try elf.node_global_symbols.ensureUnusedCapacity(gpa, len);
417
418 if (elf.shndx.dynsym != .UNDEF) {
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),
273422 };
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 }
274478 }
275 pub fn toSection(s: Shndx) ?std.elf.Section {
276 return switch (@intFromEnum(s)) {
277 std.elf.SHN_UNDEF...std.elf.SHN_LORESERVE - 1 => |sec| @intCast(sec),
278 std.elf.SHN_LORESERVE...reserve(std.elf.SHN_LORESERVE) - 1 => null,
279 reserve(std.elf.SHN_LORESERVE)...reserve(std.elf.SHN_HIRESERVE) => |sec| @intCast(
280 sec - reserve(std.elf.SHN_LORESERVE) + std.elf.SHN_LORESERVE,
281 ),
282 };
479 },
480 }
481}
482
483const AddLocalSymbolOptions = struct {
484 node: MappedFile.Node.Index,
485 name: String(.strtab),
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 }
283527 }
284528
285 pub fn get(s: Shndx, elf: *Elf) *Section {
286 return &elf.shdrs.items[@intFromEnum(s)];
529 target_index.ptr(elf).* = .{
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);
287544 }
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 {
296 name: []const u8 = "",
297 lib_name: ?[]const u8 = null,
298 value: u64 = 0,
299 size: u64 = 0,
300 type: std.elf.STT,
301 bind: std.elf.STB = .LOCAL,
302 visibility: std.elf.STV = .DEFAULT,
303 shndx: Shndx = .UNDEF,
304 };
305 pub fn init(si: Symbol.Index, elf: *Elf, opts: InitOptions) !void {
306 const comp = elf.base.comp;
307 const gpa = comp.gpa;
308 const target_endian = elf.targetEndian();
309 const name_strtab_entry = try elf.string(.strtab, opts.name);
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 }
546 return @enumFromInt(@intFromEnum(target_index));
547 },
548 }
549}
550
551const AddGlobalSymbolOptions = struct {
552 const Name = struct {
553 strtab: String(.strtab),
554 dynstr: String(.dynstr),
555 fn string(elf: *Elf, slice: []const u8) !Name {
556 return .{
557 .strtab = try elf.string(.strtab, slice),
558 .dynstr = switch (elf.shndx.dynsym) {
559 .UNDEF => .empty,
560 else => try elf.string(.dynstr, slice),
325561 },
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);
326614 }
327 switch (elf.symPtr(si)) {
328 inline else => |sym, class| {
615 const gop = elf.globals.weak_def.getOrPutAssumeCapacity(opts.name.strtab);
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| {
329741 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));
330748 sym.* = .{
331 .name = name_strtab_entry,
749 .name = @intFromEnum(opts.name.dynstr),
332750 .value = @intCast(opts.value),
333751 .size = @intCast(opts.size),
334 .info = .{ .type = opts.type, .bind = opts.bind },
752 .info = .{ .type = opts.type, .bind = bind },
335753 .other = .{ .visibility = opts.visibility },
336754 .shndx = opts.shndx.toSection().?,
337755 };
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,
339922 },
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);
340931 }
341 switch (elf.shdrPtr(elf.si.symtab.shndx(elf))) {
342 inline else => |shdr| elf.targetStore(&shdr.info, @max(
343 elf.targetLoad(&shdr.info),
344 @intFromEnum(si) + 1,
345 )),
932 },
933 }
934 if (demote_to_local) {
935 // When demoting a global to STB_LOCAL, we need to move its symtab index so that it is with
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;
346961 }
347962
348 if (opts.bind == .LOCAL) return;
349 no_entry: {
350 if (std.mem.eql(u8, opts.name, entry: switch (elf.options.entry) {
351 .default => switch (comp.config.output_mode) {
352 .Exe => continue :entry .enabled,
353 .Lib, .Obj => continue :entry .disabled,
963 const src_sym_ptr = @field(elf.symPtr(src_index), @tagName(class));
964 const dest_sym_ptr = @field(elf.symPtr(dest_index), @tagName(class));
965
966 const this_name: String(.strtab) = @enumFromInt(elf.targetLoad(&src_sym_ptr.name));
967 assert(elf.globalByName(this_name).? == global_ptr);
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,
3541004 },
355 .disabled => break :no_entry,
356 .enabled => "_start",
357 .named => |named| named,
358 })) {
359 elf.si.entry = si;
360 switch (elf.ehdrPtr()) {
361 inline else => |ehdr| elf.targetStore(&ehdr.entry, @intCast(opts.value)),
362 }
1005 // SHN_UNDEF is important: we mustn't define this symbol for other DSOs.
1006 .shndx = std.elf.SHN_UNDEF,
1007 .other = .{ .visibility = .DEFAULT },
1008 };
1009 if (elf.targetEndian() != native_endian) {
1010 std.mem.byteSwapAllFields(class.ElfN().Sym, dynsym);
3631011 }
3641012 }
365
366 if (elf.si.dynsym == .null) return;
367 const dsi = elf.dynsym.count();
368 try elf.dynsym.putNoClobber(gpa, si, {});
369 const name_dynstr_entry = try elf.string(.dynstr, opts.name);
370 switch (elf.shdrPtr(elf.si.dynsym.shndx(elf))) {
1013 },
1014 }
1015}
1016fn addPltEntry(elf: *Elf, global_name: String(.strtab), dynsym_index: u32) void {
1017 const target_endian = elf.targetEndian();
1018 const plt_index: u32 = @intCast(elf.got.plt.count());
1019 elf.got.plt.putAssumeCapacityNoClobber(.global(global_name), {});
1020 switch (elf.ehdrField(.machine)) {
1021 else => |machine| @panic(@tagName(machine)),
1022 .X86_64 => {
1023 const plt_ni = elf.shndx.plt.get(elf).ni;
1024 const plt_addr = plt_addr: switch (elf.shdrPtr(elf.shndx.plt)) {
3711025 inline else => |shdr| {
372 const old_size = elf.targetLoad(&shdr.size);
373 const ent_size = elf.targetLoad(&shdr.entsize);
374 const new_size = ent_size * elf.dynsym.count();
375 if (new_size > old_size) {
376 elf.targetStore(&shdr.size, @intCast(new_size));
377 const dynsym_ni = elf.si.dynsym.node(elf);
378 _, const node_size = dynsym_ni.location(&elf.mf).resolve(&elf.mf);
379 if (new_size > node_size) try dynsym_ni.resize(
380 &elf.mf,
381 gpa,
382 new_size +| new_size / MappedFile.growth_factor,
383 );
384 }
1026 const old_size = 16 * (1 + plt_index);
1027 assert(elf.targetLoad(&shdr.size) == old_size);
1028 elf.targetStore(&shdr.size, old_size + 16);
1029 const plt_slice = plt_ni.slice(&elf.mf)[old_size..][0..16];
1030 @memcpy(plt_slice, &[16]u8{
1031 0xf3, 0x0f, 0x1e, 0xfa, // endbr64
1032 0x68, 0x00, 0x00, 0x00, 0x00, // push $0x0
1033 0xe9, 0x00, 0x00, 0x00, 0x00, // jmp 0
1034 0x66, 0x90, // xchg %ax,%ax
1035 });
1036 std.mem.writeInt(u32, plt_slice[5..][0..4], plt_index, target_endian);
1037 std.mem.writeInt(
1038 i32,
1039 plt_slice[10..][0..4],
1040 -@as(i32, @intCast(old_size + 14)),
1041 target_endian,
1042 );
1043 break :plt_addr elf.targetLoad(&shdr.addr) + old_size;
3851044 },
386 }
387 switch (elf.dynsymSlice()) {
388 inline else => |dynsyms, class| {
389 const Sym = class.ElfN().Sym;
390 const dynsym = &dynsyms[dsi];
391 dynsym.* = .{
392 .name = name_dynstr_entry,
393 .value = @intCast(opts.value),
394 .size = @intCast(opts.size),
395 .info = .{ .type = opts.type, .bind = opts.bind },
396 .other = .{ .visibility = opts.visibility },
397 .shndx = opts.shndx.toSection().?,
398 };
399 if (target_endian != native_endian) std.mem.byteSwapAllFields(Sym, dynsym);
1045 };
1046
1047 const got_plt_shndx = elf.shndx.got_plt;
1048 const got_plt_ni = elf.shndx.got_plt.get(elf).ni;
1049 const got_plt_addr = got_plt_addr: switch (elf.shdrPtr(got_plt_shndx)) {
1050 inline else => |shdr, class| {
1051 const ent_size = @sizeOf(class.ElfN().Addr);
1052 const old_size = ent_size * (3 + plt_index);
1053 elf.targetStore(&shdr.size, old_size + ent_size);
1054 std.mem.writeInt(
1055 class.ElfN().Addr,
1056 got_plt_ni.slice(&elf.mf)[old_size..][0..ent_size],
1057 @intCast(plt_addr),
1058 target_endian,
1059 );
1060 break :got_plt_addr elf.targetLoad(&shdr.addr) + old_size;
1061 },
1062 };
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 );
4001083 },
4011084 }
4021085
403 if (opts.type != .FUNC or opts.shndx != .UNDEF) return;
404 const plt_index: u32 = @intCast(elf.got.plt.count());
405 try elf.got.plt.putNoClobber(gpa, si, {});
406 switch (elf.ehdrField(.machine)) {
407 else => |machine| @panic(@tagName(machine)),
408 .X86_64 => {
409 const plt_ni = elf.si.plt.node(elf);
410 _, const plt_node_size = plt_ni.location(&elf.mf).resolve(&elf.mf);
411 const plt_addr = plt_addr: switch (elf.shdrPtr(elf.si.plt.shndx(elf))) {
412 inline else => |shdr| {
413 const old_size = 16 * (1 + plt_index);
414 const new_size = old_size + 16;
415 elf.targetStore(&shdr.size, new_size);
416 if (new_size > plt_node_size) try plt_ni.resize(
417 &elf.mf,
418 gpa,
419 new_size +| new_size / MappedFile.growth_factor,
420 );
421 const plt_slice = plt_ni.slice(&elf.mf)[old_size..new_size];
422 @memcpy(plt_slice, &[16]u8{
423 0xf3, 0x0f, 0x1e, 0xfa, // endbr64
424 0x68, 0x00, 0x00, 0x00, 0x00, // push $0x0
425 0xe9, 0x00, 0x00, 0x00, 0x00, // jmp 0
426 0x66, 0x90, // xchg %ax,%ax
427 });
428 std.mem.writeInt(u32, plt_slice[5..][0..4], plt_index, target_endian);
429 std.mem.writeInt(
430 i32,
431 plt_slice[10..][0..4],
432 2 - @as(i32, @intCast(new_size)),
433 target_endian,
434 );
435 break :plt_addr elf.targetLoad(&shdr.addr) + old_size;
436 },
437 };
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;
1086 const rela_plt_shndx = got_plt_shndx.get(elf).rela_shndx;
1087 const rela_plt_ni = rela_plt_shndx.get(elf).ni;
1088 switch (elf.shdrPtr(rela_plt_shndx)) {
1089 inline else => |shdr, class| {
1090 const Rela = class.ElfN().Rela;
1091 const rela_size = elf.targetLoad(&shdr.entsize);
1092 const old_size = rela_size * plt_index;
1093 const new_size = old_size + rela_size;
1094 elf.targetStore(&shdr.size, new_size);
1095 const rela: *Rela = @ptrCast(@alignCast(
1096 rela_plt_ni.slice(&elf.mf)[@intCast(old_size)..@intCast(new_size)],
1097 ));
1098 rela.* = .{
1099 .offset = @intCast(got_plt_addr),
1100 .info = .{
1101 .type = @intFromEnum(std.elf.R_X86_64.JUMP_SLOT),
1102 .sym = @intCast(dynsym_index),
4611103 },
1104 .addend = 0,
4621105 };
463
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);
1106 if (target_endian != native_endian) std.mem.byteSwapAllFields(Rela, rela);
5231107 },
5241108 }
525 }
1109 },
1110 }
1111}
5261112
527 pub fn flushMoved(si: Symbol.Index, elf: *Elf, value: u64) void {
528 switch (elf.symPtr(si)) {
529 inline else => |sym, class| {
530 elf.targetStore(&sym.value, @intCast(value));
531 if (si == elf.si.entry) {
532 @branchHint(.unlikely);
533 @field(elf.ehdrPtr(), @tagName(class)).entry = sym.value;
534 }
535 },
1113const Symbol = struct {
1114 /// The node which this symbol's value is defined relative to. Possible values are:
1115 /// * `.none` for a SHN_ABS or SHN_UNDEF symbol
1116 /// * A section (the symbol's value is that section's vaddr)
1117 /// * An input section (the symbol's value is some vaddr in that input section)
1118 /// * A NAV, UAV, or lazy code/data (the symbol's value is exactly the vaddr of that node)
1119 node: MappedFile.Node.Index,
1120
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 }
5361147 }
537 si.applyLocationRelocs(elf);
538 si.applyTargetRelocs(elf);
5391148 }
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 {
542 if (elf.ehdrField(.type) == .REL) return;
543 switch (si.get(elf).loc_relocs) {
544 .none => {},
545 else => |loc_relocs| for (elf.relocs.items[@intFromEnum(loc_relocs)..]) |*reloc| {
546 if (reloc.loc != si) break;
1161 fn flushMoved(si: Symbol.Index, elf: *Elf, value: u64) void {
1162 switch (elf.symPtr(si)) {
1163 inline else => |sym| elf.targetStore(&sym.value, @intCast(value)),
1164 }
1165 if (elf.ehdrField(.type) != .REL) {
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);
5471170 reloc.apply(elf);
548 },
1171 ri = reloc.next;
1172 }
5491173 }
5501174 }
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 {
553 if (elf.ehdrField(.type) == .REL) return;
554 var ri = si.get(elf).target_relocs;
555 while (ri != .none) {
556 const reloc = ri.get(elf);
557 assert(reloc.target == si);
558 reloc.apply(elf);
559 ri = reloc.next;
560 }
1199 /// Opaque, stable identifier for a symbol. Does not necessarily equal the index into the symtab.
1200 const Id = packed struct(u32) {
1201 kind: enum(u1) { local, global },
1202 raw: u31,
1203
1204 const @"null": Symbol.Id = .local(.null);
1205
1206 fn local(lsi: Symbol.LocalIndex) Symbol.Id {
1207 return .{ .kind = .local, .raw = @intCast(@intFromEnum(lsi)) };
1208 }
1209 fn global(name: String(.strtab)) Symbol.Id {
1210 return .{ .kind = .global, .raw = @intCast(@intFromEnum(name)) };
1211 }
1212 fn unwrap(s: Symbol.Id) union(enum) {
1213 local: Symbol.LocalIndex,
1214 global: String(.strtab),
1215 } {
1216 return switch (s.kind) {
1217 .local => .{ .local = @enumFromInt(s.raw) },
1218 .global => .{ .global = @enumFromInt(s.raw) },
1219 };
5611220 }
5621221
563 pub fn deleteLocationRelocs(si: Symbol.Index, elf: *Elf) void {
564 const sym = si.get(elf);
565 for (elf.relocs.items[@intFromEnum(sym.loc_relocs)..]) |*reloc| {
566 if (reloc.loc != si) break;
567 reloc.delete(elf);
568 }
569 sym.loc_relocs = .none;
1222 fn toTypeErased(s: Symbol.Id) link.File.SymbolId {
1223 return @enumFromInt(@as(u32, @bitCast(s)));
1224 }
1225 fn fromTypeErased(s: link.File.SymbolId) Symbol.Id {
1226 return @bitCast(@intFromEnum(s));
1227 }
1228
1229 fn index(s: Symbol.Id, elf: *const Elf) Symbol.Index {
1230 return switch (s.unwrap()) {
1231 .local => |lsi| lsi.index(),
1232 .global => |name| elf.globalByName(name).?.symtab_index,
1233 };
1234 }
1235
1236 fn value(s: Symbol.Id, elf: *Elf) u64 {
1237 return switch (elf.symPtr(s.index(elf))) {
1238 inline else => |sym| elf.targetLoad(&sym.value),
1239 };
1240 }
1241
1242 /// Returns `true` if the target of `s` has moved, meaning the symbol's value will change at
1243 /// some point due to a call to `flushMoved`.
1244 fn hasMoved(s: Symbol.Id, elf: *Elf) bool {
1245 const node = s.index(elf).ptr(elf).node;
1246 if (node == .none) return false;
1247 return node.hasMoved(&elf.mf);
5701248 }
5711249 };
1250};
5721251
573 pub const Known = struct {
574 comptime symtab: Symbol.Index = .symtab,
575 comptime shstrtab: Symbol.Index = .shstrtab,
576 comptime strtab: Symbol.Index = .strtab,
577 comptime rodata: Symbol.Index = .rodata,
578 comptime text: Symbol.Index = .text,
579 comptime data: Symbol.Index = .data,
580 comptime data_rel_ro: Symbol.Index = .data_rel_ro,
581 comptime got: Symbol.Index = .got,
582 comptime got_plt: Symbol.Index = .got_plt,
583 comptime plt: Symbol.Index = .plt,
584 comptime plt_sec: Symbol.Index = .plt_sec,
585 dynsym: Symbol.Index,
586 dynstr: Symbol.Index,
587 dynamic: Symbol.Index,
588 tdata: Symbol.Index,
589 entry: Symbol.Index,
1252fn globalByName(elf: *const Elf, name: String(.strtab)) ?*Symbol.Global {
1253 if (elf.globals.strong_def.getPtr(name)) |ptr| return ptr;
1254 if (elf.globals.weak_def.getPtr(name)) |ptr| return ptr;
1255 if (elf.globals.strong_undef.getPtr(name)) |ptr| return ptr;
1256 if (elf.globals.weak_undef.getPtr(name)) |ptr| return ptr;
1257 return null;
1258}
1259
1260pub fn symbolForAtom(elf: *Elf, atom: link.File.AtomId) link.File.SymbolId {
1261 const lsi: Symbol.LocalIndex = switch (elf.getNode(Node.fromAtom(atom))) {
1262 .file,
1263 .ehdr,
1264 .shdr,
1265 .segment,
1266 .section,
1267 .input_section,
1268 => unreachable,
1269
1270 inline .nav,
1271 .uav,
1272 .lazy_code,
1273 .lazy_const_data,
1274 => |i| i.symbol(elf),
5901275 };
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 {
593 if (!std.debug.runtime_safety) std.debug.assert(@sizeOf(Symbol) == 16);
1282 try elf.ensureUnusedSymbolCapacity(1, .all_local);
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 };
5941449 }
5951450};
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 {
5981469 map: std.HashMapUnmanaged(u32, void, StringTable.Context, std.hash_map.default_max_load_percentage),
5991470
6001471 const Context = struct {
......@@ -623,9 +1494,13 @@ pub const StringTable = struct {
6231494 }
6241495 };
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
6271502 const gpa = elf.base.comp.gpa;
628 const ni = si.node(elf);
1503 const ni = shndx.get(elf).ni;
6291504 const slice_const = ni.sliceConst(&elf.mf);
6301505 const gop = try st.map.getOrPutContextAdapted(
6311506 gpa,
......@@ -635,7 +1510,7 @@ pub const StringTable = struct {
6351510 );
6361511 if (gop.found_existing) return gop.key_ptr.*;
6371512 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)) {
6391514 inline else => |shdr| {
6401515 const old_size: u32 = @intCast(elf.targetLoad(&shdr.size));
6411516 const new_size: u32 = @intCast(old_size + key.len + 1);
......@@ -654,7 +1529,7 @@ pub const StringTable = struct {
6541529 }
6551530};
6561531
657pub const GotIndex = enum(u32) {
1532const GotIndex = enum(u32) {
6581533 none = std.math.maxInt(u32),
6591534 _,
6601535
......@@ -671,12 +1546,12 @@ pub const GotIndex = enum(u32) {
6711546 }
6721547};
6731548
674pub const Reloc = extern struct {
1549const Reloc = extern struct {
6751550 type: Reloc.Type,
6761551 prev: Reloc.Index,
6771552 next: Reloc.Index,
678 loc: Symbol.Index,
679 target: Symbol.Index,
1553 node: MappedFile.Node.Index,
1554 target: Symbol.Id,
6801555 index: Section.RelIndex,
6811556 offset: u64,
6821557 addend: i64,
......@@ -745,85 +1620,86 @@ pub const Reloc = extern struct {
7451620
7461621 pub fn apply(reloc: *const Reloc, elf: *Elf) void {
7471622 assert(elf.ehdrField(.type) != .REL);
748 const loc_ni = reloc.loc.get(elf).ni;
749 switch (loc_ni) {
750 .none => return,
751 else => |ni| if (ni.hasMoved(&elf.mf)) return,
752 }
753 switch (reloc.target.get(elf).ni) {
754 .none => {},
755 else => |ni| if (ni.hasMoved(&elf.mf)) return,
1623 assert(reloc.node != .none);
1624 if (reloc.node.hasMoved(&elf.mf) or reloc.target.hasMoved(elf)) {
1625 // There's no point applying the relocation now, because it will be re-applied by
1626 // `flushMoved` at some point anyway.
1627 return;
7561628 }
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)..];
7581644 const target_endian = elf.targetEndian();
759 switch (elf.symtabSlice()) {
760 inline else => |symtab, class| {
761 const loc_sym = &symtab[@intFromEnum(reloc.loc)];
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));
1645 switch (elf.symPtr(reloc.target.index(elf))) {
1646 inline else => |target_sym, class| {
1647 const target_value = elf.targetLoad(&target_sym.value) +% @as(u64, @bitCast(reloc.addend));
7671648 switch (elf.ehdrField(.machine)) {
7681649 else => |machine| @panic(@tagName(machine)),
7691650 .X86_64 => switch (reloc.type.X86_64) {
7701651 else => |kind| @panic(@tagName(kind)),
7711652 .@"64" => std.mem.writeInt(
7721653 u64,
773 loc_slice[0..8],
1654 dest_slice[0..8],
7741655 target_value,
7751656 target_endian,
7761657 ),
7771658 .PC32 => std.mem.writeInt(
7781659 i32,
779 loc_slice[0..4],
780 @intCast(@as(i64, @bitCast(target_value -%
781 (elf.targetLoad(&loc_sym.value) + reloc.offset)))),
1660 dest_slice[0..4],
1661 @intCast(@as(i64, @bitCast(target_value -% dest_vaddr))),
7821662 target_endian,
7831663 ),
7841664 .PLT32 => std.mem.writeInt(
7851665 i32,
786 loc_slice[0..4],
787 @intCast(@as(i64, @bitCast(
788 if (elf.got.plt.getIndex(reloc.target)) |plt_index|
789 elf.targetLoad(&@field(
790 elf.shdrPtr(elf.si.plt_sec.shndx(elf)),
791 @tagName(class),
792 ).addr) +% 16 * plt_index +%
793 @as(u64, @bitCast(reloc.addend)) -%
794 (elf.targetLoad(&loc_sym.value) + reloc.offset)
795 else
796 target_value -%
797 (elf.targetLoad(&loc_sym.value) + reloc.offset),
798 ))),
1666 dest_slice[0..4],
1667 @intCast(@as(i64, @bitCast(if (elf.got.plt.getIndex(reloc.target)) |plt_index|
1668 elf.targetLoad(&@field(
1669 elf.shdrPtr(elf.shndx.plt_sec),
1670 @tagName(class),
1671 ).addr) +% 16 * plt_index +%
1672 @as(u64, @bitCast(reloc.addend)) -% dest_vaddr
1673 else
1674 target_value -% dest_vaddr))),
7991675 target_endian,
8001676 ),
8011677 .@"32" => std.mem.writeInt(
8021678 u32,
803 loc_slice[0..4],
1679 dest_slice[0..4],
8041680 @intCast(target_value),
8051681 target_endian,
8061682 ),
8071683 .@"32S" => std.mem.writeInt(
8081684 i32,
809 loc_slice[0..4],
1685 dest_slice[0..4],
8101686 @intCast(@as(i64, @bitCast(target_value))),
8111687 target_endian,
8121688 ),
8131689 .TLSLD => std.mem.writeInt(
8141690 i32,
815 loc_slice[0..4],
1691 dest_slice[0..4],
8161692 @intCast(@as(i64, @bitCast(
817 elf.targetLoad(&symtab[@intFromEnum(elf.si.got)].value) +%
1693 elf.shndx.got.vaddr(elf) +%
8181694 @as(u64, @bitCast(reloc.addend)) +%
8191695 @as(u64, 8) * elf.got.tlsld.unwrap().? -%
820 (elf.targetLoad(&loc_sym.value) + reloc.offset),
1696 dest_vaddr,
8211697 ))),
8221698 target_endian,
8231699 ),
8241700 .DTPOFF32 => std.mem.writeInt(
8251701 i32,
826 loc_slice[0..4],
1702 dest_slice[0..4],
8271703 @intCast(@as(i64, @bitCast(target_value))),
8281704 target_endian,
8291705 ),
......@@ -833,14 +1709,14 @@ pub const Reloc = extern struct {
8331709 assert(elf.targetLoad(&ph.type) == .TLS);
8341710 std.mem.writeInt(
8351711 i32,
836 loc_slice[0..4],
1712 dest_slice[0..4],
8371713 @intCast(@as(i64, @bitCast(target_value -% elf.targetLoad(&ph.memsz)))),
8381714 target_endian,
8391715 );
8401716 },
8411717 .SIZE32 => std.mem.writeInt(
8421718 u32,
843 loc_slice[0..4],
1719 dest_slice[0..4],
8441720 @intCast(
8451721 elf.targetLoad(&target_sym.size) +% @as(u64, @bitCast(reloc.addend)),
8461722 ),
......@@ -848,7 +1724,7 @@ pub const Reloc = extern struct {
8481724 ),
8491725 .SIZE64 => std.mem.writeInt(
8501726 u64,
851 loc_slice[0..8],
1727 dest_slice[0..8],
8521728 elf.targetLoad(&target_sym.size) +% @as(u64, @bitCast(reloc.addend)),
8531729 target_endian,
8541730 ),
......@@ -861,9 +1737,9 @@ pub const Reloc = extern struct {
8611737 pub fn delete(reloc: *Reloc, elf: *Elf) void {
8621738 switch (reloc.prev) {
8631739 .none => {
864 const target = reloc.target.get(elf);
865 assert(target.target_relocs.get(elf) == reloc);
866 target.target_relocs = reloc.next;
1740 const target_ptr = reloc.target.index(elf).ptr(elf);
1741 assert(target_ptr.first_target_reloc.get(elf) == reloc);
1742 target_ptr.first_target_reloc = reloc.next;
8671743 },
8681744 else => |prev| prev.get(elf).next = reloc.next,
8691745 }
......@@ -874,13 +1750,13 @@ pub const Reloc = extern struct {
8741750 switch (elf.ehdrField(.type)) {
8751751 .NONE, .CORE, _ => unreachable,
8761752 .REL => {
877 const sh = reloc.loc.shndx(elf).get(elf);
878 switch (elf.shdrPtr(sh.rela_si.shndx(elf))) {
1753 const sh = elf.getNodeShndx(reloc.node).get(elf);
1754 switch (elf.shdrPtr(sh.rela_shndx)) {
8791755 inline else => |shdr, class| {
8801756 const Rela = class.ElfN().Rela;
8811757 const ent_size = elf.targetLoad(&shdr.entsize);
8821758 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);
8841760 const rela: *Rela = @ptrCast(@alignCast(
8851761 rela_slice[@intCast(start)..][0..@intCast(ent_size)],
8861762 ));
......@@ -901,6 +1777,38 @@ pub const Reloc = extern struct {
9011777 reloc.* = undefined;
9021778 }
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
9041812 comptime {
9051813 if (!std.debug.runtime_safety) std.debug.assert(@sizeOf(Reloc) == 40);
9061814 }
......@@ -1001,34 +1909,38 @@ fn create(
10011909 .nodes = .empty,
10021910 .shdrs = .empty,
10031911 .phdrs = .empty,
1004 .si = .{
1005 .dynsym = .null,
1006 .dynstr = .null,
1007 .dynamic = .null,
1008 .tdata = .null,
1009 .entry = .null,
1912 .shndx = .{
1913 .got = .UNDEF,
1914 .got_plt = .UNDEF,
1915 .plt = .UNDEF,
1916 .plt_sec = .UNDEF,
1917 .dynsym = .UNDEF,
1918 .dynstr = .UNDEF,
1919 .dynamic = .UNDEF,
1920 .tdata = .UNDEF,
10101921 },
10111922 .symtab = .empty,
1012 .shstrtab = .{
1013 .map = .empty,
1014 },
1015 .strtab = .{
1016 .map = .empty,
1017 },
1018 .dynsym = .empty,
1019 .dynstr = .{
1020 .map = .empty,
1923 .globals = .{
1924 .strong_def = .empty,
1925 .weak_def = .empty,
1926 .strong_undef = .empty,
1927 .weak_undef = .empty,
10211928 },
1929 .node_global_symbols = .empty,
1930 .shstrtab = .{ .map = .empty },
1931 .strtab = .{ .map = .empty },
1932 .dynstr = .{ .map = .empty },
10221933 .got = .{
10231934 .len = 0,
10241935 .tlsld = .none,
10251936 .plt = .empty,
10261937 },
1938 .first_plt_reloc = .none,
1939 .first_dynamic_reloc = .none,
10271940 .needed = .empty,
10281941 .inputs = .empty,
10291942 .input_sections = .empty,
10301943 .input_section_pending_index = 0,
1031 .globals = .empty,
10321944 .navs = .empty,
10331945 .uavs = .empty,
10341946 .lazy = comptime .initFill(.{
......@@ -1037,6 +1949,7 @@ fn create(
10371949 }),
10381950 .pending_uavs = .empty,
10391951 .relocs = .empty,
1952 .changed_symtab_index = .empty,
10401953 .const_prog_node = .none,
10411954 .synth_prog_node = .none,
10421955 .input_prog_node = .none,
......@@ -1054,21 +1967,25 @@ pub fn deinit(elf: *Elf) void {
10541967 elf.shdrs.deinit(gpa);
10551968 elf.phdrs.deinit(gpa);
10561969 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);
10571975 elf.shstrtab.map.deinit(gpa);
10581976 elf.strtab.map.deinit(gpa);
1059 elf.dynsym.deinit(gpa);
10601977 elf.dynstr.map.deinit(gpa);
10611978 elf.got.plt.deinit(gpa);
10621979 elf.needed.deinit(gpa);
10631980 for (elf.inputs.items) |input| if (input.member) |m| gpa.free(m);
10641981 elf.inputs.deinit(gpa);
10651982 elf.input_sections.deinit(gpa);
1066 elf.globals.deinit(gpa);
10671983 elf.navs.deinit(gpa);
10681984 elf.uavs.deinit(gpa);
10691985 for (&elf.lazy.values) |*lazy| lazy.map.deinit(gpa);
10701986 elf.pending_uavs.deinit(gpa);
10711987 elf.relocs.deinit(gpa);
1988 elf.changed_symtab_index.deinit(gpa);
10721989 elf.* = undefined;
10731990}
10741991
......@@ -1135,7 +2052,6 @@ fn initHeaders(
11352052 try elf.shdrs.ensureTotalCapacity(gpa, shnum);
11362053 try elf.phdrs.resize(gpa, phnum);
11372054 try elf.symtab.ensureTotalCapacity(gpa, 1);
1138 if (have_dynamic_section) try elf.dynsym.ensureTotalCapacity(gpa, 1);
11392055 elf.nodes.appendAssumeCapacity(.file);
11402056
11412057 switch (class) {
......@@ -1365,7 +2281,7 @@ fn initHeaders(
13652281
13662282 const sh_undef: *ElfN.Shdr = @ptrCast(@alignCast(elf.ni.shdr.slice(&elf.mf)));
13672283 sh_undef.* = .{
1368 .name = try elf.string(.shstrtab, ""),
2284 .name = @intFromEnum(String(.shstrtab).empty),
13692285 .type = .NULL,
13702286 .flags = .{ .shf = .{} },
13712287 .addr = 0,
......@@ -1377,24 +2293,23 @@ fn initHeaders(
13772293 .entsize = 0,
13782294 };
13792295 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
13822298 elf.symtab.addOneAssumeCapacity().* = .{
1383 .ni = .none,
1384 .loc_relocs = .none,
1385 .target_relocs = .none,
1386 .unused = 0,
2299 .node = .none,
2300 .first_target_reloc = .none,
13872301 };
1388 assert(elf.si.symtab == try elf.addSection(elf.ni.file, .{
2302 assert(.symtab == try elf.addSection(elf.ni.file, .{
13892303 .type = .SYMTAB,
13902304 .size = @sizeOf(ElfN.Sym) * 1,
13912305 .addralign = addr_align,
13922306 .entsize = @sizeOf(ElfN.Sym),
13932307 .node_align = elf.mf.flags.block_size,
2308 .info = 1, // index of first non-local symbol
13942309 }));
13952310 const symtab_null = @field(elf.symPtr(.null), @tagName(ct_class));
13962311 symtab_null.* = .{
1397 .name = try elf.string(.strtab, ""),
2312 .name = @intFromEnum(String(.strtab).empty),
13982313 .value = 0,
13992314 .size = 0,
14002315 .info = .{ .type = .NOTYPE, .bind = .LOCAL },
......@@ -1407,55 +2322,56 @@ fn initHeaders(
14072322 ehdr.shstrndx = ehdr.shnum;
14082323 },
14092324 }
1410 assert(elf.si.shstrtab == try elf.addSection(elf.ni.file, .{
2325 assert(.shstrtab == try elf.addSection(elf.ni.file, .{
14112326 .type = .STRTAB,
14122327 .size = 1,
14132328 .entsize = 1,
14142329 .node_align = elf.mf.flags.block_size,
14152330 }));
1416 try elf.renameSection(.symtab, ".symtab");
1417 try elf.renameSection(.shstrtab, ".shstrtab");
1418 elf.si.shstrtab.node(elf).slice(&elf.mf)[0] = 0;
2331 Section.Index.get(.shstrtab, elf).ni.slice(&elf.mf)[0] = 0;
2332
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, .{
14212337 .name = ".strtab",
14222338 .type = .STRTAB,
14232339 .size = 1,
14242340 .entsize = 1,
14252341 .node_align = elf.mf.flags.block_size,
14262342 }));
1427 switch (elf.shdrPtr(elf.si.symtab.shndx(elf))) {
1428 inline else => |shdr| elf.targetStore(&shdr.link, @intFromEnum(elf.si.strtab.shndx(elf))),
2343 Section.Index.get(.strtab, elf).ni.slice(&elf.mf)[0] = 0;
2344 switch (elf.shdrPtr(.symtab)) {
2345 inline else => |shdr| elf.targetStore(&shdr.link, @intFromEnum(Section.Index.strtab)),
14292346 }
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, .{
14332349 .name = ".rodata",
14342350 .flags = .{ .ALLOC = true },
14352351 .addralign = elf.mf.flags.block_size,
14362352 }));
1437 assert(elf.si.text == try elf.addSection(elf.ni.text, .{
2353 assert(.text == try elf.addSection(elf.ni.text, .{
14382354 .name = ".text",
14392355 .flags = .{ .ALLOC = true, .EXECINSTR = true },
14402356 .addralign = elf.mf.flags.block_size,
14412357 }));
1442 assert(elf.si.data == try elf.addSection(elf.ni.data, .{
2358 assert(.data == try elf.addSection(elf.ni.data, .{
14432359 .name = ".data",
14442360 .flags = .{ .WRITE = true, .ALLOC = true },
14452361 .addralign = elf.mf.flags.block_size,
14462362 }));
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, .{
14482364 .name = ".data.rel.ro",
14492365 .flags = .{ .WRITE = true, .ALLOC = true },
14502366 .addralign = elf.mf.flags.block_size,
14512367 }));
14522368 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, .{
14542370 .name = ".got",
14552371 .flags = .{ .WRITE = true, .ALLOC = true },
14562372 .addralign = addr_align,
1457 }));
1458 assert(elf.si.got_plt == try elf.addSection(
2373 });
2374 elf.shndx.got_plt = try elf.addSection(
14592375 if (elf.options.z_now) elf.ni.data_rel_ro else elf.ni.data,
14602376 .{
14612377 .name = ".got.plt",
......@@ -1468,26 +2384,26 @@ fn initHeaders(
14682384 },
14692385 .addralign = addr_align,
14702386 },
1471 ));
2387 );
14722388 const plt_size: std.elf.Xword, const plt_align: std.mem.Alignment, const plt_sec =
14732389 switch (machine) {
14742390 else => @panic(@tagName(machine)),
14752391 .X86_64 => .{ 16, .@"16", true },
14762392 };
1477 assert(elf.si.plt == try elf.addSection(elf.ni.text, .{
2393 elf.shndx.plt = try elf.addSection(elf.ni.text, .{
14782394 .name = ".plt",
14792395 .type = .PROGBITS,
14802396 .flags = .{ .ALLOC = true, .EXECINSTR = true },
14812397 .size = plt_size,
14822398 .addralign = plt_align,
14832399 .node_align = elf.mf.flags.block_size,
1484 }));
1485 if (plt_sec) assert(elf.si.plt_sec == try elf.addSection(elf.ni.text, .{
2400 });
2401 if (plt_sec) elf.shndx.plt_sec = try elf.addSection(elf.ni.text, .{
14862402 .name = ".plt.sec",
14872403 .flags = .{ .ALLOC = true, .EXECINSTR = true },
14882404 .addralign = plt_align,
14892405 .node_align = elf.mf.flags.block_size,
1490 }));
2406 });
14912407 if (maybe_interp) |interp| {
14922408 const interp_ni = try elf.mf.addLastChildNode(gpa, elf.ni.rodata, .{
14932409 .size = interp.len + 1,
......@@ -1498,13 +2414,13 @@ fn initHeaders(
14982414 elf.nodes.appendAssumeCapacity(.{ .segment = interp_phndx });
14992415 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, .{
15022418 .name = ".interp",
15032419 .type = .PROGBITS,
15042420 .flags = .{ .ALLOC = true },
15052421 .size = @intCast(interp.len + 1),
15062422 });
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);
15082424 @memcpy(sec_interp[0..interp.len], interp);
15092425 sec_interp[interp.len] = 0;
15102426 }
......@@ -1517,7 +2433,7 @@ fn initHeaders(
15172433 elf.nodes.appendAssumeCapacity(.{ .segment = dynamic_phndx });
15182434 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, .{
15212437 .name = ".dynstr",
15222438 .type = .STRTAB,
15232439 .flags = .{ .ALLOC = true },
......@@ -1525,26 +2441,27 @@ fn initHeaders(
15252441 .entsize = 1,
15262442 .node_align = elf.mf.flags.block_size,
15272443 });
1528 const dynstr_shndx = elf.si.dynstr.shndx(elf);
1529 elf.dynsym.putAssumeCapacityNoClobber(.null, {});
2444 dynstr_shndx.get(elf).ni.slice(&elf.mf)[0] = 0;
2445 elf.shndx.dynstr = dynstr_shndx;
2446
15302447 switch (class) {
15312448 .NONE, _ => unreachable,
15322449 inline else => |ct_class| {
15332450 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, .{
15352452 .name = ".dynsym",
15362453 .type = .DYNSYM,
15372454 .flags = .{ .ALLOC = true },
15382455 .size = @sizeOf(Sym) * 1,
1539 .link = @intFromEnum(dynstr_shndx),
2456 .link = dynstr_shndx.toSection().?,
15402457 .info = 1,
15412458 .addralign = addr_align,
15422459 .entsize = @sizeOf(Sym),
15432460 .node_align = elf.mf.flags.block_size,
15442461 });
1545 const dynsym_null = &@field(elf.dynsymSlice(), @tagName(ct_class))[0];
2462 const dynsym_null = @field(elf.dynsymPtr(0), @tagName(ct_class));
15462463 dynsym_null.* = .{
1547 .name = try elf.string(.dynstr, ""),
2464 .name = @intFromEnum(String(.dynstr).empty),
15482465 .value = 0,
15492466 .size = 0,
15502467 .info = .{ .type = .NOTYPE, .bind = .LOCAL },
......@@ -1561,57 +2478,57 @@ fn initHeaders(
15612478 .NONE, _ => unreachable,
15622479 inline else => |ct_class| @sizeOf(ct_class.ElfN().Rela),
15632480 };
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, .{
15652482 .name = ".rela.dyn",
15662483 .type = .RELA,
15672484 .flags = .{ .ALLOC = true },
1568 .link = @intFromEnum(elf.si.dynsym.shndx(elf)),
2485 .link = elf.shndx.dynsym.toSection().?,
15692486 .addralign = addr_align,
15702487 .entsize = rela_size,
15712488 .node_align = elf.mf.flags.block_size,
15722489 });
1573 const got_plt_shndx = elf.si.got_plt.shndx(elf);
1574 got_plt_shndx.get(elf).rela_si = try elf.addSection(elf.ni.rodata, .{
2490 const got_plt_shndx = elf.shndx.got_plt;
2491 got_plt_shndx.get(elf).rela_shndx = try elf.addSection(elf.ni.rodata, .{
15752492 .name = ".rela.plt",
15762493 .type = .RELA,
15772494 .flags = .{ .ALLOC = true, .INFO_LINK = true },
1578 .link = @intFromEnum(elf.si.dynsym.shndx(elf)),
1579 .info = @intFromEnum(got_plt_shndx),
2495 .link = elf.shndx.dynsym.toSection().?,
2496 .info = got_plt_shndx.toSection().?,
15802497 .addralign = addr_align,
15812498 .entsize = rela_size,
15822499 .node_align = elf.mf.flags.block_size,
15832500 });
1584 elf.si.dynamic = try elf.addSection(dynamic_ni, .{
2501 elf.shndx.dynamic = try elf.addSection(dynamic_ni, .{
15852502 .name = ".dynamic",
15862503 .type = .DYNAMIC,
15872504 .flags = .{ .ALLOC = true, .WRITE = true },
1588 .link = @intFromEnum(dynstr_shndx),
2505 .link = dynstr_shndx.toSection().?,
15892506 .entsize = @intCast(addr_align.toByteUnits() * 2),
15902507 .node_align = addr_align,
15912508 });
15922509 switch (machine) {
15932510 else => @panic(@tagName(machine)),
15942511 .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{
15962515 0xff, 0x35, 0x00, 0x00, 0x00, 0x00, // push 0x0(%rip)
15972516 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *0x0(%rip)
15982517 0x0f, 0x1f, 0x40, 0x00, // nopl 0x0(%rax)
15992518 });
1600 const plt_sym = elf.si.plt.get(elf);
1601 assert(plt_sym.loc_relocs == .none);
1602 plt_sym.loc_relocs = @enumFromInt(elf.relocs.items.len);
1603 try elf.ensureUnusedRelocCapacity(elf.si.plt, 2);
2519 elf.first_plt_reloc = @enumFromInt(elf.relocs.items.len);
2520 try elf.ensureUnusedRelocCapacity(plt_ni, 2);
16042521 elf.addRelocAssumeCapacity(
1605 elf.si.plt,
2522 plt_ni,
16062523 2,
1607 elf.si.got_plt,
2524 got_plt_sym,
16082525 8 * 1 - 4,
16092526 .{ .X86_64 = .PC32 },
16102527 );
16112528 elf.addRelocAssumeCapacity(
1612 elf.si.plt,
2529 plt_ni,
16132530 8,
1614 elf.si.got_plt,
2531 got_plt_sym,
16152532 8 * 2 - 4,
16162533 .{ .X86_64 = .PC32 },
16172534 );
......@@ -1631,7 +2548,7 @@ fn initHeaders(
16312548 assert(maybe_interp == null);
16322549 assert(!have_dynamic_section);
16332550 }
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, .{
16352552 .name = ".tdata",
16362553 .flags = .{ .WRITE = true, .ALLOC = true, .TLS = true },
16372554 .addralign = elf.mf.flags.block_size,
......@@ -1641,7 +2558,7 @@ fn initHeaders(
16412558
16422559pub fn startProgress(elf: *Elf, prog_node: std.Progress.Node) void {
16432560 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);
16452562 elf.synth_prog_node = prog_node.start("Synthetics", count: {
16462563 var count: usize = 0;
16472564 for (&elf.lazy.values) |*lazy| count += lazy.map.count() - lazy.pending_index;
......@@ -1668,35 +2585,105 @@ pub fn endProgress(elf: *Elf) void {
16682585fn getNode(elf: *const Elf, ni: MappedFile.Node.Index) Node {
16692586 return elf.nodes.get(@intFromEnum(ni));
16702587}
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}
16712606fn computeNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 {
1672 const parent_vaddr = parent_vaddr: {
1673 const parent_ni = ni.parent(&elf.mf);
1674 const parent_si = switch (elf.getNode(parent_ni)) {
1675 .file => return 0,
1676 .ehdr, .shdr => unreachable,
1677 .segment => |phndx| break :parent_vaddr switch (elf.phdrSlice()) {
1678 inline else => |phdr| elf.targetLoad(&phdr[phndx].vaddr),
1679 },
1680 .section => |si| si,
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 };
2607 const parent_vaddr = switch (elf.getNode(ni.parent(&elf.mf))) {
2608 .file => return 0,
2609 .ehdr, .shdr => unreachable,
2610 .segment => |phndx| switch (elf.phdrSlice()) {
2611 inline else => |phdr| elf.targetLoad(&phdr[phndx].vaddr),
2612 },
2613 .section => |shndx| if (shndx == elf.shndx.tdata) 0 else shndx.vaddr(elf),
2614 .input_section => unreachable,
2615 inline .nav, .uav, .lazy_code, .lazy_const_data => |i| Symbol.Id.local(i.symbol(elf)).value(elf),
16872616 };
16882617 const offset, _ = ni.location(&elf.mf).resolve(&elf.mf);
16892618 return parent_vaddr + offset;
16902619}
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 {
16932680 return @enumFromInt(elf.mf.memory_map.memory[std.elf.EI.CLASS]);
16942681}
1695pub fn identData(elf: *const Elf) std.elf.DATA {
2682fn identData(elf: *const Elf) std.elf.DATA {
16962683 return @enumFromInt(elf.mf.memory_map.memory[std.elf.EI.DATA]);
16972684}
16982685
1699pub fn targetEndian(elf: *const Elf) std.lang.Endian {
2686fn targetEndian(elf: *const Elf) std.lang.Endian {
17002687 return switch (elf.identData()) {
17012688 .NONE, _ => unreachable,
17022689 .@"2LSB" => .little,
......@@ -1730,12 +2717,12 @@ fn targetStore(elf: *const Elf, ptr: anytype, val: @typeInfo(@TypeOf(ptr)).point
17302717 };
17312718}
17322719
1733pub const EhdrPtr = union(std.elf.CLASS) {
2720const EhdrPtr = union(std.elf.CLASS) {
17342721 NONE: noreturn,
17352722 @"32": *std.elf.Elf32.Ehdr,
17362723 @"64": *std.elf.Elf64.Ehdr,
17372724};
1738pub fn ehdrPtr(elf: *Elf) EhdrPtr {
2725fn ehdrPtr(elf: *Elf) EhdrPtr {
17392726 const slice = elf.ni.ehdr.slice(&elf.mf);
17402727 return switch (elf.identClass()) {
17412728 .NONE, _ => unreachable,
......@@ -1746,7 +2733,7 @@ pub fn ehdrPtr(elf: *Elf) EhdrPtr {
17462733 ),
17472734 };
17482735}
1749pub fn ehdrField(
2736fn ehdrField(
17502737 elf: *Elf,
17512738 comptime field: std.meta.FieldEnum(std.elf.Elf64.Ehdr),
17522739) @FieldType(std.elf.Elf64.Ehdr, @tagName(field)) {
......@@ -1755,12 +2742,12 @@ pub fn ehdrField(
17552742 };
17562743}
17572744
1758pub const PhdrSlice = union(std.elf.CLASS) {
2745const PhdrSlice = union(std.elf.CLASS) {
17592746 NONE: noreturn,
17602747 @"32": []std.elf.Elf32.Phdr,
17612748 @"64": []std.elf.Elf64.Phdr,
17622749};
1763pub fn phdrSlice(elf: *Elf) PhdrSlice {
2750fn phdrSlice(elf: *Elf) PhdrSlice {
17642751 assert(elf.ehdrField(.type) != .REL);
17652752 const slice = elf.ni.phdr.slice(&elf.mf);
17662753 return switch (elf.identClass()) {
......@@ -1773,104 +2760,47 @@ pub fn phdrSlice(elf: *Elf) PhdrSlice {
17732760 };
17742761}
17752762
1776pub const ShdrSlice = 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) {
2763const ShdrPtr = union(std.elf.CLASS) {
17942764 NONE: noreturn,
17952765 @"32": *std.elf.Elf32.Shdr,
17962766 @"64": *std.elf.Elf64.Shdr,
1797};
1798pub fn shdrPtr(elf: *Elf, shndx: Symbol.Index.Shndx) ShdrPtr {
1799 return switch (elf.shdrSlice()) {
1800 inline else => |shdrs, class| @unionInit(ShdrPtr, @tagName(class), &shdrs[@intFromEnum(shndx)]),
1801 };
1802}
1803
1804pub const SymtabSlice = union(std.elf.CLASS) {
1805 NONE: noreturn,
1806 @"32": []std.elf.Elf32.Sym,
1807 @"64": []std.elf.Elf64.Sym,
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);
2767};
2768fn shdrPtr(elf: *Elf, shndx: Section.Index) ShdrPtr {
2769 const raw_slice = elf.ni.shdr.slice(&elf.mf);
2770 switch (elf.identClass()) {
2771 .NONE, _ => unreachable,
2772 inline else => |class| {
2773 const shdr_slice: []class.ElfN().Shdr = @ptrCast(@alignCast(raw_slice));
2774 const shdr_ptr = &shdr_slice[@intFromEnum(shndx)];
2775 return @unionInit(ShdrPtr, @tagName(class), shdr_ptr);
2776 },
2777 }
18482778}
18492779
1850fn initSymbolAssumeCapacity(elf: *Elf, opts: Symbol.Index.InitOptions) !Symbol.Index {
1851 const si = elf.addSymbolAssumeCapacity();
1852 try si.init(elf, opts);
1853 return si;
2780const SymPtr = union(std.elf.CLASS) {
2781 NONE: noreturn,
2782 @"32": *std.elf.Elf32.Sym,
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 }
18542794}
1855
1856pub fn globalSymbol(elf: *Elf, opts: struct {
1857 name: []const u8,
1858 lib_name: ?[]const u8 = null,
1859 type: std.elf.STT,
1860 bind: std.elf.STB = .GLOBAL,
1861 visibility: std.elf.STV = .DEFAULT,
1862}) !Symbol.Index {
1863 const gpa = elf.base.comp.gpa;
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.*;
2795fn dynsymPtr(elf: *Elf, index: u32) SymPtr {
2796 const raw_slice = elf.shndx.dynsym.get(elf).ni.slice(&elf.mf);
2797 switch (elf.shdrPtr(elf.shndx.dynsym)) {
2798 inline else => |shdr, class| {
2799 const size = elf.targetLoad(&shdr.size);
2800 const slice: []class.ElfN().Sym = @ptrCast(@alignCast(raw_slice[0..@intCast(size)]));
2801 return @unionInit(SymPtr, @tagName(class), &slice[index]);
2802 },
2803 }
18742804}
18752805
18762806fn navType(
......@@ -1885,97 +2815,135 @@ fn navType(
18852815 else
18862816 .OBJECT;
18872817}
1888fn namedSection(elf: *const Elf, name: []const u8) ?Symbol.Index {
2818fn namedSection(elf: *const Elf, name: []const u8) ?Section.Index {
18892819 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;
18912821 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;
18932823 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;
18952825 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;
18972827 return null;
18982828}
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}
19172829fn navMapIndex(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Node.NavMapIndex {
19182830 const gpa = zcu.gpa;
19192831 const ip = &zcu.intern_pool;
19202832 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 {
1953 const gpa = elf.base.comp.gpa;
1954 try elf.symtab.ensureUnusedCapacity(gpa, 1);
1955 const uav_gop = try elf.uavs.getOrPut(gpa, uav_val);
1956 if (!uav_gop.found_existing)
1957 uav_gop.value_ptr.* = try elf.initSymbolAssumeCapacity(.{ .type = .OBJECT });
1958 return @enumFromInt(uav_gop.index);
1959}
1960pub fn uavSymbol(elf: *Elf, uav_val: InternPool.Index) !Symbol.Index {
1961 const umi = try elf.uavMapIndex(uav_val);
1962 return umi.symbol(elf);
2834 try elf.ensureUnusedSymbolCapacity(1, .all_local);
2835 try elf.nodes.ensureUnusedCapacity(gpa, 1);
2836 try elf.navs.ensureUnusedCapacity(gpa, 1);
2837
2838 const nav_gop = elf.navs.getOrPutAssumeCapacity(nav_index);
2839 const nmi: Node.NavMapIndex = @enumFromInt(nav_gop.index);
2840 if (!nav_gop.found_existing) {
2841 const sym_type = navType(ip, nav.resolved.?, elf.base.comp.config.any_non_single_threaded);
2842 const shndx: Section.Index = section: {
2843 if (nav.resolved.?.@"linksection".toSlice(ip)) |@"linksection"| {
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;
19632891}
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 {
19662898 const gpa = elf.base.comp.gpa;
1967 try elf.symtab.ensureUnusedCapacity(gpa, 1);
1968 const lazy_gop = try elf.lazy.getPtr(lazy.kind).map.getOrPut(gpa, lazy.ty);
1969 if (!lazy_gop.found_existing) {
1970 lazy_gop.value_ptr.* = try elf.initSymbolAssumeCapacity(.{
1971 .type = switch (lazy.kind) {
1972 .code => .FUNC,
1973 .const_data => .OBJECT,
1974 },
2899 const zcu = elf.base.comp.zcu.?;
2900
2901 try elf.ensureUnusedSymbolCapacity(1, .all_local);
2902 try elf.nodes.ensureUnusedCapacity(gpa, 1);
2903 try elf.uavs.ensureUnusedCapacity(gpa, 1);
2904 try elf.pending_uavs.ensureUnusedCapacity(gpa, 1);
2905
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(),
19752919 });
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 }
19772945 }
1978 return lazy_gop.value_ptr.*;
2946 return umi;
19792947}
19802948
19812949pub fn loadInput(elf: *Elf, input: link.Input) (Io.File.Reader.SizeError ||
......@@ -2080,19 +3048,23 @@ fn loadObject(
20803048 const diags = &comp.link_diags;
20813049 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);
20843052 log.debug("loadObject({f}{f})", .{ path.fmtEscapeString(), fmtMemberString(member) });
20853053 try elf.checkInputIdent(path, r);
2086 try elf.symtab.ensureUnusedCapacity(gpa, 1);
3054 try elf.ensureUnusedSymbolCapacity(1, .all_local);
20873055 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 });
20883064 elf.inputs.addOneAssumeCapacity().* = .{
20893065 .path = path,
20903066 .member = if (member) |m| try gpa.dupe(u8, m) else null,
2091 .si = try elf.initSymbolAssumeCapacity(.{
2092 .name = std.fs.path.stem(member orelse path.sub_path),
2093 .type = .FILE,
2094 .shndx = .ABS,
2095 }),
3067 .file_symbol = file_symbol,
20963068 };
20973069 const target_endian = elf.targetEndian();
20983070 switch (elf.identClass()) {
......@@ -2108,13 +3080,13 @@ fn loadObject(
21083080 return diags.failParse(path, "bad section header location", .{});
21093081 if (ehdr.shentsize < @sizeOf(ElfN.Shdr))
21103082 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);
21123084 defer gpa.free(sections);
21133085 try fr.seekTo(fl.offset + ehdr.shoff);
21143086 for (sections) |*section| {
21153087 section.* = .{
21163088 .shdr = try r.peekStruct(ElfN.Shdr, target_endian),
2117 .si = .null,
3089 .isi = null,
21183090 };
21193091 try r.discardAll(ehdr.shentsize);
21203092 switch (section.shdr.type) {
......@@ -2136,42 +3108,49 @@ fn loadObject(
21363108 };
21373109 defer gpa.free(shstrtab);
21383110 try elf.nodes.ensureUnusedCapacity(gpa, ehdr.shnum - 1);
2139 try elf.symtab.ensureUnusedCapacity(gpa, ehdr.shnum - 1);
21403111 try elf.input_sections.ensureUnusedCapacity(gpa, ehdr.shnum - 1);
21413112 for (sections[1..]) |*section| switch (section.shdr.type) {
21423113 else => {},
21433114 .PROGBITS, .NOBITS => {
21443115 if (section.shdr.name >= shstrtab.len) continue;
21453116 const name = std.mem.sliceTo(shstrtab[section.shdr.name..], 0);
2146 const parent_si = elf.namedSection(name) orelse continue;
2147 const ni = try elf.mf.addLastChildNode(gpa, parent_si.node(elf), .{
3117 const shndx: Section.Index = elf.namedSection(name) orelse shndx: {
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, .{
21483127 .size = section.shdr.size,
21493128 .alignment = .fromByteUnits(std.math.ceilPowerOfTwoAssert(
21503129 usize,
21513130 @intCast(@max(section.shdr.addralign, 1)),
21523131 )),
2153 .moved = true,
3132 .moved = true, // see assert at end of `flushInputSection`
21543133 });
21553134 elf.nodes.appendAssumeCapacity(.{
21563135 .input_section = @enumFromInt(elf.input_sections.items.len),
21573136 });
2158 section.si = try elf.initSymbolAssumeCapacity(.{
2159 .type = .SECTION,
2160 .shndx = parent_si.shndx(elf),
2161 });
2162 section.si.get(elf).ni = ni;
3137 section.isi = @enumFromInt(elf.input_sections.items.len);
21633138 elf.input_sections.addOneAssumeCapacity().* = .{
2164 .ii = ii,
2165 .si = section.si,
3139 .input = input_index,
21663140 .file_location = .{
21673141 .offset = fl.offset + section.shdr.offset,
2168 .size = section.shdr.size,
3142 .size = if (section.shdr.type == .NOBITS) 0 else section.shdr.size,
21693143 },
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,
21703149 };
21713150 elf.synth_prog_node.increaseEstimatedTotalItems(1);
21723151 },
21733152 };
2174 var symmap: std.ArrayList(Symbol.Index) = .empty;
3153 var symmap: std.ArrayList(Symbol.Id) = .empty;
21753154 defer symmap.deinit(gpa);
21763155 for (sections[1..], 1..) |*symtab, symtab_shndx| switch (symtab.shdr.type) {
21773156 else => {},
......@@ -2202,105 +3181,132 @@ fn loadObject(
22023181 ), 1) catch continue;
22033182 symmap.clearRetainingCapacity();
22043183 try symmap.resize(gpa, symnum);
2205 try elf.symtab.ensureUnusedCapacity(gpa, symnum);
2206 try elf.globals.ensureUnusedCapacity(gpa, symnum);
3184 try elf.ensureUnusedSymbolCapacity(symnum, .maybe_global);
22073185 try fr.seekTo(fl.offset + symtab.shdr.offset + symtab.shdr.entsize);
22083186 for (symmap.items) |*si| {
22093187 si.* = .null;
22103188 const input_sym = try r.peekStruct(ElfN.Sym, target_endian);
22113189 try r.discardAll64(symtab.shdr.entsize);
2212 if (input_sym.name >= strtab.len or input_sym.shndx == std.elf.SHN_UNDEF or
2213 input_sym.shndx >= ehdr.shnum) continue;
2214 switch (input_sym.info.type) {
2215 .NOTYPE, .OBJECT, .FUNC => {},
2216 .SECTION => {
2217 const section = &sections[input_sym.shndx];
2218 if (input_sym.value == section.shdr.addr) si.* = section.si;
3190 if (input_sym.name >= strtab.len or input_sym.shndx >= ehdr.shnum) continue;
3191
3192 const name = std.mem.sliceTo(strtab[input_sym.name..], 0);
3193
3194 const sym_type: std.elf.STT = switch (input_sym.info.type) {
3195 .NOTYPE, .OBJECT, .FUNC, .TLS => |t| t,
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 };
22193220 continue;
22203221 },
2221 else => continue,
2222 }
2223 const name = std.mem.sliceTo(strtab[input_sym.name..], 0);
2224 const parent_si = sections[input_sym.shndx].si;
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;
3222 };
3223
3224 const input_section_node = (sections[input_sym.shndx].isi orelse continue).node(elf);
3225
22353226 switch (input_sym.info.bind) {
2236 else => {},
2237 .GLOBAL => {
2238 const gop = elf.globals.getOrPutAssumeCapacity(elf.targetLoad(
2239 &@field(elf.symPtr(si.*), @tagName(class)).name,
2240 ));
2241 if (gop.found_existing) switch (elf.targetLoad(
2242 switch (elf.symPtr(gop.value_ptr.*)) {
2243 inline else => |sym| &sym.info,
2244 },
2245 ).bind) {
2246 else => unreachable,
2247 .GLOBAL => return diags.failParse(
3227 _ => |bind| return diags.failParse(
3228 path,
3229 "symbol '{s}' has unsupported binding (0x{x})",
3230 .{ name, bind },
3231 ),
3232 .LOCAL => {
3233 const lsi = elf.addLocalSymbolAssumeCapacity(.{
3234 .node = input_section_node,
3235 .name = try elf.string(.strtab, name),
3236 .value = input_sym.value,
3237 .size = input_sym.size,
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(
22483255 path,
22493256 "multiple definitions of '{s}'",
22503257 .{name},
22513258 ),
2252 .WEAK => {},
22533259 };
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.*;
22613260 },
22623261 }
22633262 }
2264 for (sections[1..]) |*rels| switch (rels.shdr.type) {
3263 for (sections[1..]) |*rel_sec| switch (rel_sec.shdr.type) {
22653264 else => {},
22663265 inline .REL, .RELA => |sht| {
2267 if (rels.shdr.link != symtab_shndx or rels.shdr.info == std.elf.SHN_UNDEF or
2268 rels.shdr.info >= ehdr.shnum) continue;
3266 if (rel_sec.shdr.link != symtab_shndx or rel_sec.shdr.info == std.elf.SHN_UNDEF or
3267 rel_sec.shdr.info >= ehdr.shnum) continue;
22693268 const Rel = switch (sht) {
22703269 else => comptime unreachable,
22713270 .REL => ElfN.Rel,
22723271 .RELA => ElfN.Rela,
22733272 };
2274 if (rels.shdr.entsize < @sizeOf(Rel))
3273 if (rel_sec.shdr.entsize < @sizeOf(Rel))
22753274 return diags.failParse(path, "unsupported rel entsize", .{});
22763275
2277 const loc_sec = &sections[rels.shdr.info];
2278 if (loc_sec.si == .null) continue;
2279 const loc_sym = loc_sec.si.get(elf);
2280 assert(loc_sym.loc_relocs == .none);
2281 loc_sym.loc_relocs = @enumFromInt(elf.relocs.items.len);
3276 const loc_sec = &sections[rel_sec.shdr.info];
3277 const loc_node = (loc_sec.isi orelse continue).node(elf);
3278 elf.resetNodeRelocs(loc_node);
22823279
22833280 const relnum = std.math.divExact(
22843281 u32,
2285 @intCast(rels.shdr.size),
2286 @intCast(rels.shdr.entsize),
3282 @intCast(rel_sec.shdr.size),
3283 @intCast(rel_sec.shdr.entsize),
22873284 ) catch return diags.failParse(
22883285 path,
22893286 "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 },
22913288 );
2292 try elf.ensureUnusedRelocCapacity(loc_sec.si, relnum);
2293 try fr.seekTo(fl.offset + rels.shdr.offset);
3289 try elf.ensureUnusedRelocCapacity(loc_node, relnum);
3290 try fr.seekTo(fl.offset + rel_sec.shdr.offset);
22943291 for (0..relnum) |_| {
22953292 const rel = try r.peekStruct(Rel, target_endian);
2296 try r.discardAll64(rels.shdr.entsize);
2297 if (rel.info.sym == 0 or rel.info.sym > symnum) continue;
2298 const target_si = symmap.items[rel.info.sym - 1];
2299 if (target_si == .null) continue;
3293 try r.discardAll64(rel_sec.shdr.entsize);
3294 if (rel.info.sym == 0) continue;
3295 if (rel.info.sym > symnum) return diags.failParse(
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 );
23003306 elf.addRelocAssumeCapacity(
2301 loc_sec.si,
3307 loc_node,
23023308 rel.offset - loc_sec.shdr.addr,
2303 target_si,
3309 target,
23043310 rel.addend,
23053311 .wrap(rel.info.type, elf),
23063312 );
......@@ -2386,7 +3392,7 @@ fn loadDso(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) !void {
23863392}
23873393fn loadDsoExact(elf: *Elf, name: []const u8) !void {
23883394 log.debug("loadDsoExact({f})", .{std.zig.fmtString(name)});
2389 if (elf.si.dynamic != .null) {
3395 if (elf.shndx.dynamic != .UNDEF) {
23903396 try elf.needed.put(elf.base.comp.gpa, try elf.string(.dynstr, name), {});
23913397 }
23923398}
......@@ -2454,20 +3460,27 @@ pub fn prelink(elf: *Elf, prog_node: std.Progress.Node) !void {
24543460fn prelinkInner(elf: *Elf) !void {
24553461 const comp = elf.base.comp;
24563462 const gpa = comp.gpa;
2457 try elf.symtab.ensureUnusedCapacity(gpa, 1);
3463 try elf.ensureUnusedSymbolCapacity(1, .all_local);
24583464 try elf.inputs.ensureUnusedCapacity(gpa, 1);
24593465 const zcu_name = try std.fmt.allocPrint(gpa, "{s}_zcu", .{
24603466 std.fs.path.stem(elf.base.emit.sub_path),
24613467 });
24623468 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 });
24643477 elf.inputs.addOneAssumeCapacity().* = .{
24653478 .path = elf.base.emit,
24663479 .member = null,
2467 .si = si,
3480 .file_symbol = zcu_file_symbol,
24683481 };
24693482
2470 if (elf.si.dynamic != .null) switch (elf.identClass()) {
3483 if (elf.shndx.dynamic != .UNDEF) switch (elf.identClass()) {
24713484 .NONE, _ => unreachable,
24723485 inline else => |ct_class| {
24733486 const ElfN = ct_class.ElfN();
......@@ -2478,9 +3491,9 @@ fn prelinkInner(elf: *Elf) !void {
24783491 @intFromBool(flags != 0) + @intFromBool(flags_1 != 0) +
24793492 @intFromBool(comp.config.output_mode == .Exe) + 12;
24803493 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;
24823495 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)) {
24843497 inline else => |shdr| elf.targetStore(&shdr.size, dynamic_size),
24853498 }
24863499 const sec_dynamic = dynamic_ni.slice(&elf.mf);
......@@ -2489,10 +3502,10 @@ fn prelinkInner(elf: *Elf) !void {
24893502 for (
24903503 dynamic_entries[dynamic_index..][0..needed_len],
24913504 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) };
24933506 dynamic_index += needed_len;
24943507 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)) };
24963509 dynamic_index += 1;
24973510 }
24983511 if (flags != 0) {
......@@ -2507,25 +3520,25 @@ fn prelinkInner(elf: *Elf) !void {
25073520 dynamic_entries[dynamic_index] = .{ std.elf.DT_DEBUG, 0 };
25083521 dynamic_index += 1;
25093522 }
2510 const rela_dyn_si = elf.si.got.shndx(elf).get(elf).rela_si;
2511 const rela_plt_si = elf.si.got_plt.shndx(elf).get(elf).rela_si;
3523 const rela_dyn_shndx = elf.shndx.got.get(elf).rela_shndx;
3524 const rela_plt_shndx = elf.shndx.got_plt.get(elf).rela_shndx;
25123525 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)) },
25143527 .{ 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,
25163529 ) },
25173530 .{ 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)) },
25193532 .{ 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,
25213534 ) },
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)) },
25233536 .{ 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)) },
25253538 .{ 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)) },
25273540 .{ 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,
25293542 ) },
25303543 .{ std.elf.DT_NULL, 0 },
25313544 };
......@@ -2534,42 +3547,40 @@ fn prelinkInner(elf: *Elf) !void {
25343547 if (elf.targetEndian() != native_endian) for (dynamic_entries) |*dynamic_entry|
25353548 std.mem.byteSwapAllFields(@TypeOf(dynamic_entry.*), dynamic_entry);
25363549
2537 const dynamic_sym = elf.si.dynamic.get(elf);
2538 assert(dynamic_sym.loc_relocs == .none);
2539 dynamic_sym.loc_relocs = @enumFromInt(elf.relocs.items.len);
2540 try elf.ensureUnusedRelocCapacity(elf.si.dynamic, 5);
3550 elf.first_dynamic_reloc = @enumFromInt(elf.relocs.items.len);
3551 try elf.ensureUnusedRelocCapacity(dynamic_ni, 5);
25413552 elf.addRelocAssumeCapacity(
2542 elf.si.dynamic,
3553 dynamic_ni,
25433554 @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 12) + 1),
2544 rela_dyn_si,
3555 .local(rela_dyn_shndx.get(elf).lsi),
25453556 0,
25463557 .absAddr(elf),
25473558 );
25483559 elf.addRelocAssumeCapacity(
2549 elf.si.dynamic,
3560 dynamic_ni,
25503561 @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 9) + 1),
2551 rela_plt_si,
3562 .local(rela_plt_shndx.get(elf).lsi),
25523563 0,
25533564 .absAddr(elf),
25543565 );
25553566 elf.addRelocAssumeCapacity(
2556 elf.si.dynamic,
3567 dynamic_ni,
25573568 @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 7) + 1),
2558 elf.si.got_plt,
3569 .local(elf.shndx.got_plt.get(elf).lsi),
25593570 0,
25603571 .absAddr(elf),
25613572 );
25623573 elf.addRelocAssumeCapacity(
2563 elf.si.dynamic,
3574 dynamic_ni,
25643575 @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 5) + 1),
2565 elf.si.dynsym,
3576 .local(elf.shndx.dynsym.get(elf).lsi),
25663577 0,
25673578 .absAddr(elf),
25683579 );
25693580 elf.addRelocAssumeCapacity(
2570 elf.si.dynamic,
3581 dynamic_ni,
25713582 @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 3) + 1),
2572 elf.si.dynstr,
3583 .local(elf.shndx.dynstr.get(elf).lsi),
25733584 0,
25743585 .absAddr(elf),
25753586 );
......@@ -2577,36 +3588,6 @@ fn prelinkInner(elf: *Elf) !void {
25773588 };
25783589}
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
26103591fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
26113592 name: []const u8 = "",
26123593 type: std.elf.SHT = .NULL,
......@@ -2618,19 +3599,22 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
26183599 entsize: std.elf.Word = 0,
26193600 node_align: std.mem.Alignment = .@"1",
26203601 fixed: bool = false,
2621}) !Symbol.Index {
3602}) !Section.Index {
26223603 switch (opts.type) {
26233604 .NULL => assert(opts.size == 0),
26243605 .PROGBITS => assert(opts.size > 0),
26253606 else => {},
26263607 }
3608 if (opts.flags.ALLOC and elf.ehdrField(.type) != .REL) {
3609 assert(elf.getNode(segment_ni) == .segment);
3610 }
26273611 const gpa = elf.base.comp.gpa;
26283612 try elf.nodes.ensureUnusedCapacity(gpa, 1);
26293613 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
26323616 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()) {
26343618 inline else => |ehdr, class| {
26353619 const shndx, const shnum = alloc_shndx: switch (elf.targetLoad(&ehdr.shnum)) {
26363620 1...std.elf.SHN_LORESERVE - 2 => |shndx| {
......@@ -2653,7 +3637,7 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
26533637 break :alloc_shndx .{ shndx, shnum };
26543638 },
26553639 };
2656 assert(shndx < @intFromEnum(Symbol.Index.Shndx.LORESERVE));
3640 assert(shndx < @intFromEnum(Section.Index.LORESERVE));
26573641 break :shndx .{ @enumFromInt(shndx), elf.targetLoad(&ehdr.shentsize) * shnum };
26583642 },
26593643 };
......@@ -2670,17 +3654,22 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
26703654 .fixed = opts.fixed,
26713655 .resized = opts.size > 0,
26723656 });
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;
26773657 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 });
26783668 const offset = ni.fileLocation(&elf.mf, false).offset;
2679 try si.init(elf, .{ .value = addr, .type = .SECTION, .shndx = shndx });
26803669 switch (elf.shdrPtr(shndx)) {
26813670 inline else => |shdr, class| {
26823671 shdr.* = .{
2683 .name = shstrtab_entry,
3672 .name = @intFromEnum(shstrtab_entry),
26843673 .type = opts.type,
26853674 .flags = .{ .shf = opts.flags },
26863675 .addr = @intCast(addr),
......@@ -2694,63 +3683,31 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
26943683 if (elf.targetEndian() != native_endian) std.mem.byteSwapAllFields(class.ElfN().Shdr, shdr);
26953684 },
26963685 }
2697 return si;
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);
3686 return shndx;
27173687}
27183688
2719pub fn addReloc(
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 {
3689fn ensureUnusedRelocCapacity(elf: *Elf, node: MappedFile.Node.Index, len: usize) !void {
27313690 if (len == 0) return;
27323691 const gpa = elf.base.comp.gpa;
27333692 try elf.relocs.ensureUnusedCapacity(gpa, len);
27343693 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)) {
27363695 .NONE, .CORE, _ => unreachable,
27373696 .REL => {
2738 const shndx = loc_si.shndx(elf);
2739 const sh = shndx.get(elf);
2740 if (sh.rela_si == .null) {
3697 const shndx = elf.getNodeShndx(node);
3698 if (shndx.get(elf).rela_shndx == .UNDEF) {
27413699 var bfa_buf: [32]u8 = undefined;
27423700 var bfa: std.heap.BufferFirstAllocator = .init(&bfa_buf, gpa);
27433701 const allocator = bfa.allocator();
27443702
2745 const rela_name =
2746 try std.fmt.allocPrint(allocator, ".rela{s}", .{elf.sectionName(sh.si)});
3703 const rela_name = try std.fmt.allocPrint(allocator, ".rela{s}", .{shndx.name(elf)});
27473704 defer allocator.free(rela_name);
27483705
2749 sh.rela_si = try elf.addSection(.none, .{
3706 const rela_shndx = try elf.addSection(.none, .{
27503707 .name = rela_name,
27513708 .type = .RELA,
2752 .link = @intFromEnum(elf.si.symtab.shndx(elf)),
2753 .info = @intFromEnum(shndx),
3709 .link = @intFromEnum(Section.Index.symtab),
3710 .info = shndx.toSection().?,
27543711 .addralign = switch (class) {
27553712 .NONE, _ => unreachable,
27563713 .@"32" => .@"4",
......@@ -2762,14 +3719,15 @@ pub fn ensureUnusedRelocCapacity(elf: *Elf, loc_si: Symbol.Index, len: usize) !v
27623719 },
27633720 .node_align = elf.mf.flags.block_size,
27643721 });
3722 shndx.get(elf).rela_shndx = rela_shndx;
27653723 }
2766 break :rela .{ sh.rela_si, len };
3724 break :rela .{ shndx.get(elf).rela_shndx, len };
27673725 },
27683726 .EXEC, .DYN => switch (elf.got.tlsld) {
27693727 _ => return,
2770 .none => if (elf.si.dynamic != .null) {
3728 .none => if (elf.shndx.dynamic != .UNDEF) {
27713729 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;
27733731 _, const got_node_size = got_ni.location(&elf.mf).resolve(&elf.mf);
27743732 const got_size = switch (class) {
27753733 .NONE, _ => unreachable,
......@@ -2777,43 +3735,52 @@ pub fn ensureUnusedRelocCapacity(elf: *Elf, loc_si: Symbol.Index, len: usize) !v
27773735 };
27783736 if (got_size > got_node_size)
27793737 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 };
27813739 } else return,
27823740 },
27833741 };
2784 const rela_ni = rela_si.node(elf);
3742 const rela_ni = rela_shndx.get(elf).ni;
27853743 _, 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)) {
27873745 inline else => |shdr| elf.targetLoad(&shdr.size) + elf.targetLoad(&shdr.entsize) * rela_len,
27883746 };
27893747 if (rela_size > rela_node_size)
27903748 try rela_ni.resize(&elf.mf, gpa, rela_size +| rela_size / MappedFile.growth_factor);
27913749}
2792pub fn addRelocAssumeCapacity(
3750fn addRelocAssumeCapacity(
27933751 elf: *Elf,
2794 loc_si: Symbol.Index,
3752 node: MappedFile.Node.Index,
27953753 offset: u64,
2796 target_si: Symbol.Index,
3754 target: Symbol.Id,
27973755 addend: i64,
27983756 @"type": Reloc.Type,
27993757) void {
2800 const target = target_si.get(elf);
3758 assert(node != .none);
28013759 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 }
28023769 elf.relocs.addOneAssumeCapacity().* = .{
28033770 .type = @"type",
28043771 .prev = .none,
2805 .next = target.target_relocs,
2806 .loc = loc_si,
2807 .target = target_si,
3772 .next = next,
3773 .node = node,
3774 .target = target,
28083775 .index = index: switch (elf.ehdrField(.type)) {
28093776 .NONE, .CORE, _ => unreachable,
28103777 .REL => {
2811 const sh = loc_si.shndx(elf).get(elf);
2812 switch (elf.shdrPtr(sh.rela_si.shndx(elf))) {
3778 const sh = elf.getNodeShndx(node).get(elf);
3779 switch (elf.shdrPtr(sh.rela_shndx)) {
28133780 inline else => |shdr, class| {
28143781 const Rela = class.ElfN().Rela;
28153782 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);
28173784 const index: u32 = if (sh.rela_free.unwrap()) |index| alloc_index: {
28183785 const rela: *Rela = @ptrCast(@alignCast(
28193786 rela_slice[@intCast(ent_size * index)..][0..@intCast(ent_size)],
......@@ -2829,11 +3796,15 @@ pub fn addRelocAssumeCapacity(
28293796 const rela: *Rela = @ptrCast(@alignCast(
28303797 rela_slice[@intCast(ent_size * index)..][0..@intCast(ent_size)],
28313798 ));
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.
28323803 rela.* = .{
2833 .offset = @intCast(offset),
3804 .offset = 0,
28343805 .info = .{
28353806 .type = @intCast(@"type".unwrap(elf)),
2836 .sym = @intCast(@intFromEnum(target_si)),
3807 .sym = @intCast(@intFromEnum(target.index(elf))),
28373808 },
28383809 .addend = @intCast(addend),
28393810 };
......@@ -2850,25 +3821,25 @@ pub fn addRelocAssumeCapacity(
28503821 else => {},
28513822 .TLSLD => switch (elf.got.tlsld) {
28523823 _ => {},
2853 .none => if (elf.si.dynamic != .null) {
3824 .none => if (elf.shndx.dynamic != .UNDEF) {
28543825 const tlsld_index = elf.got.len;
28553826 elf.got.tlsld = .wrap(tlsld_index);
28563827 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)) {
28583829 inline else => |shdr, class| {
28593830 const addr_size = @sizeOf(class.ElfN().Addr);
28603831 const old_size = addr_size * tlsld_index;
28613832 const new_size = old_size + addr_size * 2;
28623833 @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],
28643835 0,
28653836 );
28663837 break :got_addr elf.targetLoad(&shdr.addr) + old_size;
28673838 },
28683839 };
2869 const rela_dyn_si = elf.si.got.shndx(elf).get(elf).rela_si;
2870 const rela_dyn_ni = rela_dyn_si.node(elf);
2871 switch (elf.shdrPtr(rela_dyn_si.shndx(elf))) {
3840 const rela_dyn_shndx = elf.shndx.got.get(elf).rela_shndx;
3841 const rela_dyn_ni = rela_dyn_shndx.get(elf).ni;
3842 switch (elf.shdrPtr(rela_dyn_shndx)) {
28723843 inline else => |shdr, class| {
28733844 const Rela = class.ElfN().Rela;
28743845 const old_size = elf.targetLoad(&shdr.size);
......@@ -2899,11 +3870,6 @@ pub fn addRelocAssumeCapacity(
28993870 .offset = offset,
29003871 .addend = addend,
29013872 };
2902 switch (target.target_relocs) {
2903 .none => {},
2904 else => |target_ri| target_ri.get(elf).prev = ri,
2905 }
2906 target.target_relocs = ri;
29073873}
29083874
29093875pub 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)
29253891 if (!Type.fromInterned(nav.resolved.?.type).hasRuntimeBits(zcu)) return;
29263892
29273893 const nmi = try elf.navMapIndex(zcu, nav_index);
2928 const si = nmi.symbol(elf);
2929 const ni = ni: {
2930 const sym = si.get(elf);
2931 switch (sym.ni) {
2932 .none => {
2933 try elf.nodes.ensureUnusedCapacity(gpa, 1);
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 };
3894 const ni = nmi.symbol(elf).index().ptr(elf).node;
3895 elf.resetNodeRelocs(ni);
3896
3897 // Ensure the NAV is marked as moved so that once we're done, `flushMoved` will eventually be
3898 // called to apply the NAV's new relocations.
3899 try ni.moved(gpa, &elf.mf);
29523900
29533901 var nw: MappedFile.Node.Writer = undefined;
29543902 ni.writer(&elf.mf, gpa, &nw);
......@@ -2959,54 +3907,14 @@ fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index)
29593907 zcu.navSrcLoc(nav_index),
29603908 .fromInterned(nav.resolved.?.value),
29613909 &nw.interface,
2962 .{ .atom_index = @intFromEnum(si) },
3910 .{ .atom_index = Node.toAtom(ni) },
29633911 ) catch |err| switch (err) {
29643912 error.WriteFailed => return error.OutOfMemory,
29653913 else => |e| return e,
29663914 };
2967 switch (elf.symPtr(si)) {
3915 switch (elf.symPtr(nmi.symbol(elf).index())) {
29683916 inline else => |sym| elf.targetStore(&sym.size, @intCast(nw.interface.end)),
29693917 }
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) };
30103918}
30113919
30123920pub fn updateFunc(
......@@ -3041,42 +3949,13 @@ fn updateFuncInner(
30413949 const nav = ip.getNav(func.owner_nav);
30423950
30433951 const nmi = try elf.navMapIndex(zcu, func.owner_nav);
3044 const si = nmi.symbol(elf);
3045 log.debug("updateFunc({f}) = {d}", .{ nav.fqn.fmt(ip), si });
3046 const ni = ni: {
3047 const sym = si.get(elf);
3048 switch (sym.ni) {
3049 .none => {
3050 try elf.nodes.ensureUnusedCapacity(gpa, 1);
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 };
3952 log.debug("updateFunc({f}) = {d}", .{ nav.fqn.fmt(ip), nmi.symbol(elf) });
3953 const ni = nmi.symbol(elf).index().ptr(elf).node;
3954 elf.resetNodeRelocs(ni);
3955
3956 // Ensure the NAV is marked as moved so that once we're done, `flushMoved` will eventually be
3957 // called to apply the NAV's new relocations.
3958 try ni.moved(gpa, &elf.mf);
30803959
30813960 var nw: MappedFile.Node.Writer = undefined;
30823961 ni.writer(&elf.mf, gpa, &nw);
......@@ -3086,7 +3965,7 @@ fn updateFuncInner(
30863965 pt,
30873966 zcu.navSrcLoc(func.owner_nav),
30883967 func_index,
3089 @intFromEnum(si),
3968 Node.toAtom(ni),
30903969 mir,
30913970 &nw.interface,
30923971 .none,
......@@ -3094,10 +3973,9 @@ fn updateFuncInner(
30943973 error.WriteFailed => return nw.err.?,
30953974 else => |e| return e,
30963975 };
3097 switch (elf.symPtr(si)) {
3976 switch (elf.symPtr(nmi.symbol(elf).index())) {
30983977 inline else => |sym| elf.targetStore(&sym.size, @intCast(nw.interface.end)),
30993978 }
3100 si.applyLocationRelocs(elf);
31013979}
31023980
31033981pub fn updateErrorData(elf: *Elf, pt: Zcu.PerThread) !void {
......@@ -3120,7 +3998,42 @@ pub fn flush(
31203998 const comp = elf.base.comp;
31213999 _ = arena;
31224000 _ = 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
31234012 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
31244037 elf.mf.flush() catch |err| switch (err) {
31254038 error.Canceled => |e| return e,
31264039 else => |e| return comp.link_diags.fail("flush write failed: {t}", .{e}),
......@@ -3130,15 +4043,10 @@ pub fn flush(
31304043pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool {
31314044 const comp = elf.base.comp;
31324045 task: {
3133 while (elf.pending_uavs.pop()) |pending_uav| {
3134 const sub_prog_node = elf.idleProgNode(tid, elf.const_prog_node, .{ .uav = pending_uav.key });
4046 while (elf.pending_uavs.pop()) |umi| {
4047 const sub_prog_node = elf.idleProgNode(tid, elf.const_prog_node, .{ .uav = umi });
31354048 defer sub_prog_node.end();
3136 elf.flushUav(
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) {
4049 elf.flushUav(.{ .zcu = comp.zcu.?, .tid = tid }, umi) catch |err| switch (err) {
31424050 error.OutOfMemory => |e| return e,
31434051 else => |e| return comp.link_diags.fail(
31444052 "linker failed to lower constant: {t}",
......@@ -3175,9 +4083,9 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool {
31754083 break :task;
31764084 };
31774085 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);
31794087 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)));
31814089 defer sub_prog_node.end();
31824090 elf.flushInputSection(isi) catch |err| switch (err) {
31834091 else => |e| {
......@@ -3185,9 +4093,7 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool {
31854093 return comp.link_diags.fail(
31864094 "linker failed to read input section '{s}' from \"{f}{f}\": {t}",
31874095 .{
3188 elf.sectionName(
3189 elf.getNode(isi.symbol(elf).node(elf).parent(&elf.mf)).section,
3190 ),
4096 elf.getNode(isi.node(elf).parent(&elf.mf)).section.name(elf),
31914097 ii.path(elf).fmtEscapeString(),
31924098 fmtMemberString(ii.member(elf)),
31934099 e,
......@@ -3197,6 +4103,20 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool {
31974103 };
31984104 break :task;
31994105 }
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 }
32004120 while (elf.mf.updates.pop()) |ni| {
32014121 const clean_moved = ni.cleanMoved(&elf.mf);
32024122 const clean_resized = ni.cleanResized(&elf.mf);
......@@ -3209,9 +4129,10 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool {
32094129 } else elf.mf.update_prog_node.completeOne();
32104130 }
32114131 }
3212 if (elf.pending_uavs.count() > 0) return true;
4132 if (elf.pending_uavs.items.len > 0) return true;
32134133 for (&elf.lazy.values) |lazy| if (lazy.map.count() > lazy.pending_index) return true;
32144134 if (elf.input_sections.items.len > elf.input_section_pending_index) return true;
4135 if (elf.changed_symtab_index.count() > 0) return true;
32154136 if (elf.mf.updates.items.len > 0) return true;
32164137 return false;
32174138}
......@@ -3225,13 +4146,13 @@ fn idleProgNode(
32254146 var name: [std.Progress.Node.max_name_len]u8 = undefined;
32264147 return prog_node.start(name: switch (node) {
32274148 else => |tag| @tagName(tag),
3228 .section => |si| elf.sectionName(si),
4149 .section => |shndx| shndx.name(elf),
32294150 .input_section => |isi| {
32304151 const ii = isi.input(elf);
32314152 break :name std.fmt.bufPrint(&name, "{f}{f} {s}", .{
32324153 ii.path(elf).fmtEscapeString(),
32334154 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),
32354156 }) catch &name;
32364157 },
32374158 .nav => |nmi| {
......@@ -3248,59 +4169,43 @@ fn flushUav(
32484169 elf: *Elf,
32494170 pt: Zcu.PerThread,
32504171 umi: Node.UavMapIndex,
3251 uav_align: InternPool.Alignment,
3252 src_loc: Zcu.LazySrcLoc,
32534172) !void {
4173 const comp = elf.base.comp;
4174 const gpa = comp.gpa;
32544175 const zcu = pt.zcu;
3255 const gpa = zcu.gpa;
32564176
32574177 const uav_val = umi.uavValue(elf);
3258 const si = umi.symbol(elf);
3259 const ni = 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 };
4178 const ni = umi.symbol(elf).index().ptr(elf).node;
4179 elf.resetNodeRelocs(ni);
32854180
32864181 var nw: MappedFile.Node.Writer = undefined;
32874182 ni.writer(&elf.mf, gpa, &nw);
32884183 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 };
32894192 codegen.generateSymbol(
32904193 &elf.base,
32914194 pt,
3292 src_loc,
4195 dummy_src_loc,
32934196 .fromInterned(uav_val),
32944197 &nw.interface,
3295 .{ .atom_index = @intFromEnum(si) },
4198 .{ .atom_index = Node.toAtom(ni) },
32964199 ) catch |err| switch (err) {
32974200 error.WriteFailed => return error.OutOfMemory,
32984201 else => |e| return e,
32994202 };
3300 switch (elf.symPtr(si)) {
4203 switch (elf.symPtr(umi.symbol(elf).index())) {
33014204 inline else => |sym| elf.targetStore(&sym.size, @intCast(nw.interface.end)),
33024205 }
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));
33044209}
33054210
33064211fn 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 {
33084213 const gpa = zcu.gpa;
33094214
33104215 const lazy = lmr.lazySymbol(elf);
3311 const si = lmr.symbol(elf);
3312 const ni = ni: {
3313 const sym = si.get(elf);
3314 switch (sym.ni) {
3315 .none => {
3316 try elf.nodes.ensureUnusedCapacity(gpa, 1);
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 };
4216 const ni = lmr.symbol(elf).index().ptr(elf).node;
4217 elf.resetNodeRelocs(ni);
4218
4219 // Ensure the lazy node is marked as moved so that once we're done, `flushMoved` will eventually
4220 // be called to apply the lazy node's new relocations.
4221 try ni.moved(gpa, &elf.mf);
33384222
33394223 var required_alignment: InternPool.Alignment = .none;
33404224 var nw: MappedFile.Node.Writer = undefined;
......@@ -3348,15 +4232,14 @@ fn flushLazy(elf: *Elf, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void {
33484232 &required_alignment,
33494233 &nw.interface,
33504234 .none,
3351 .{ .atom_index = @intFromEnum(si) },
4235 .{ .atom_index = Node.toAtom(ni) },
33524236 );
3353 switch (elf.symPtr(si)) {
4237 switch (elf.symPtr(lmr.symbol(elf).index())) {
33544238 inline else => |sym| elf.targetStore(&sym.size, @intCast(nw.interface.end)),
33554239 }
3356 si.applyLocationRelocs(elf);
33574240}
33584241
3359fn flushInputSection(elf: *Elf, isi: Node.InputSectionIndex) !void {
4242fn flushInputSection(elf: *Elf, isi: InputSection.Index) !void {
33604243 const file_loc = isi.fileLocation(elf);
33614244 if (file_loc.size == 0) return;
33624245 const comp = elf.base.comp;
......@@ -3369,12 +4252,13 @@ fn flushInputSection(elf: *Elf, isi: Node.InputSectionIndex) !void {
33694252 var fr = file.reader(io, &.{});
33704253 try fr.seekTo(file_loc.offset);
33714254 var nw: MappedFile.Node.Writer = undefined;
3372 const si = isi.symbol(elf);
3373 si.node(elf).writer(&elf.mf, gpa, &nw);
4255 isi.node(elf).writer(&elf.mf, gpa, &nw);
33744256 defer nw.deinit();
33754257 if (try nw.interface.sendFileAll(&fr, .limited(@intCast(file_loc.size))) != file_loc.size)
33764258 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));
33784262}
33794263
33804264fn flushFileOffset(elf: *Elf, ni: MappedFile.Node.Index) !void {
......@@ -3397,7 +4281,7 @@ fn flushFileOffset(elf: *Elf, ni: MappedFile.Node.Index) !void {
33974281 var child_it = ni.children(&elf.mf);
33984282 while (child_it.next()) |child_ni| try elf.flushFileOffset(child_ni);
33994283 },
3400 .section => |si| switch (elf.shdrPtr(si.shndx(elf))) {
4284 .section => |shndx| switch (elf.shdrPtr(shndx)) {
34014285 inline else => |shdr| elf.targetStore(&shdr.offset, @intCast(
34024286 ni.fileLocation(&elf.mf, false).offset,
34034287 )),
......@@ -3426,22 +4310,21 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {
34264310 },
34274311 }
34284312 },
3429 .section => |si| {
4313 .section => |shndx| {
34304314 try elf.flushFileOffset(ni);
34314315 const addr = elf.computeNodeVAddr(ni);
3432 const shndx = si.shndx(elf);
34334316 switch (elf.shdrPtr(shndx)) {
34344317 inline else => |shdr, class| {
34354318 const flags = elf.targetLoad(&shdr.flags).shf;
34364319 if (flags.ALLOC) {
3437 if (elf.si.dynamic != .null) {
3438 if (si == elf.si.got) {
4320 if (elf.shndx.dynamic != .UNDEF) {
4321 if (shndx == elf.shndx.got) {
34394322 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;
34414324 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(
34434326 elf.targetLoad(&@field(
3444 elf.shdrPtr(rela_dyn_si.shndx(elf)),
4327 elf.shdrPtr(rela_dyn_shndx),
34454328 @tagName(class),
34464329 ).size),
34474330 )],
......@@ -3461,19 +4344,19 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {
34614344 ),
34624345 },
34634346 }
3464 } else if (si == elf.si.got_plt) {
4347 } else if (shndx == elf.shndx.got_plt) {
34654348 const target_endian = elf.targetEndian();
34664349 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;
34684351 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(
34704353 elf.targetLoad(&@field(
3471 elf.shdrPtr(rela_plt_si.shndx(elf)),
4354 elf.shdrPtr(rela_plt_shndx),
34724355 @tagName(class),
34734356 ).size),
34744357 )],
34754358 ));
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);
34774360 switch (elf.ehdrField(.machine)) {
34784361 else => |machine| @panic(@tagName(machine)),
34794362 .AARCH64, .PPC64, .RISCV => {},
......@@ -3502,7 +4385,7 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {
35024385 }
35034386 },
35044387 }
3505 } else if (si == elf.si.plt_sec) {
4388 } else if (shndx == elf.shndx.plt_sec) {
35064389 const target_endian = elf.targetEndian();
35074390 const old_addr = elf.targetLoad(&shdr.addr);
35084391 const plt_sec_slice = ni.slice(&elf.mf);
......@@ -3525,34 +4408,72 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {
35254408 }
35264409 }
35274410 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);
35294418 }
35304419 },
35314420 }
3532 si.flushMoved(elf, addr);
35334421 },
35344422 .input_section => |isi| {
3535 const old_addr = switch (elf.symPtr(isi.symbol(elf))) {
3536 inline else => |sym| elf.targetLoad(&sym.value),
3537 };
3538 const new_addr = elf.computeNodeVAddr(ni);
4423 const old_section_addr = isi.ptr(elf).vaddr;
4424 const new_section_addr = elf.computeNodeVAddr(ni);
4425 isi.ptr(elf).vaddr = new_section_addr;
4426
4427 // Update local symbols
35394428 const ii = isi.input(elf);
3540 var si = ii.symbol(elf);
3541 const end_si = ii.endSymbol(elf);
3542 while (cond: {
3543 si = si.next();
3544 break :cond si != end_si;
3545 }) {
3546 if (si.get(elf).ni != ni) continue;
3547 si.flushMoved(elf, switch (elf.symPtr(si)) {
3548 inline else => |sym| elf.targetLoad(&sym.value),
3549 } - old_addr + new_addr);
4429 var lsi, const end_lsi = ii.localSymbolRange(elf);
4430 while (lsi != end_lsi) : (lsi = @enumFromInt(@intFromEnum(lsi) + 1)) {
4431 if (lsi.index().ptr(elf).node != ni) continue;
4432 const old_sym_addr: u64 = switch (elf.symPtr(lsi.index())) {
4433 inline else => |sym| switch (elf.targetLoad(&sym.other).visibility) {
4434 .HIDDEN, .INTERNAL => {
4435 // This is actually a global symbol which got demoted to STB_LOCAL due
4436 // to its visibility. It will be handled in the global symbols pass
4437 // below; don't touch it now.
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 }
35504459 }
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));
35514476 },
3552 inline .nav, .uav, .lazy_code, .lazy_const_data => |mi| mi.symbol(elf).flushMoved(
3553 elf,
3554 elf.computeNodeVAddr(ni),
3555 ),
35564477 }
35574478 try ni.childrenMoved(elf.base.comp.gpa, &elf.mf);
35584479}
......@@ -3590,7 +4511,7 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void {
35904511 switch (elf.targetLoad(&next_ph.type)) {
35914512 else => unreachable,
35924513 .NULL, .LOAD => {},
3593 .DYNAMIC, .INTERP, .PHDR, .TLS => break,
4514 .DYNAMIC, .INTERP, .PHDR, .TLS, std.elf.PT.GNU_RELRO => break,
35944515 }
35954516 const next_vaddr = elf.targetLoad(&next_ph.vaddr);
35964517 if (vaddr + memsz <= next_vaddr) break;
......@@ -3612,7 +4533,7 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void {
36124533 }
36134534 },
36144535 },
3615 .section => |si| switch (elf.shdrPtr(si.shndx(elf))) {
4536 .section => |shndx| switch (elf.shdrPtr(shndx)) {
36164537 inline else => |shdr, class| {
36174538 switch (elf.targetLoad(&shdr.type)) {
36184539 else => unreachable,
......@@ -3620,10 +4541,10 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void {
36204541 .PROGBITS => if (size == 0) elf.targetStore(&shdr.type, .NULL),
36214542 .SYMTAB, .DYNAMIC, .REL, .DYNSYM => return,
36224543 .STRTAB => {
3623 if (elf.si.dynamic != .null) {
3624 if (si == elf.si.dynstr) {
4544 if (elf.shndx.dynamic != .UNDEF) {
4545 if (shndx == elf.shndx.dynstr) {
36254546 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),
36274548 ));
36284549 for (dynamic_entries) |*dynamic_entry|
36294550 switch (elf.targetLoad(&dynamic_entry[0])) {
......@@ -3635,19 +4556,19 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void {
36354556 return;
36364557 },
36374558 .RELA => {
3638 if (elf.si.dynamic != .null) {
3639 if (si == elf.si.got.shndx(elf).get(elf).rela_si) {
4559 if (elf.shndx.dynamic != .UNDEF) {
4560 if (shndx == elf.shndx.got.get(elf).rela_shndx) {
36404561 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),
36424563 ));
36434564 for (dynamic_entries) |*dynamic_entry|
36444565 switch (elf.targetLoad(&dynamic_entry[0])) {
36454566 else => {},
36464567 std.elf.DT_RELASZ => dynamic_entry[1] = shdr.size,
36474568 };
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) {
36494570 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),
36514572 ));
36524573 for (dynamic_entries) |*dynamic_entry|
36534574 switch (elf.targetLoad(&dynamic_entry[0])) {
......@@ -3659,7 +4580,9 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void {
36594580 return;
36604581 },
36614582 }
3662 elf.targetStore(&shdr.size, @intCast(size));
4583 if (shndx != elf.shndx.plt) {
4584 elf.targetStore(&shdr.size, @intCast(size));
4585 }
36634586 },
36644587 },
36654588 .input_section, .nav, .uav, .lazy_code, .lazy_const_data => {},
......@@ -3690,7 +4613,6 @@ fn updateExportsInner(
36904613 export_indices: []const Zcu.Export.Index,
36914614) !void {
36924615 const zcu = pt.zcu;
3693 const gpa = zcu.gpa;
36944616 const ip = &zcu.intern_pool;
36954617
36964618 switch (exported) {
......@@ -3700,44 +4622,35 @@ fn updateExportsInner(
37004622 Value.fromInterned(uav).fmtValue(pt),
37014623 }),
37024624 }
3703 try elf.symtab.ensureUnusedCapacity(gpa, export_indices.len);
3704 const exported_si: Symbol.Index, const @"type": std.elf.STT = switch (exported) {
4625 try elf.ensureUnusedSymbolCapacity(@intCast(export_indices.len), .maybe_global);
4626 const exported_lsi: Symbol.LocalIndex, const @"type": std.elf.STT = switch (exported) {
37054627 .nav => |nav| .{
3706 try elf.navSymbol(zcu, nav),
4628 (try elf.navMapIndex(zcu, nav)).symbol(elf),
37074629 navType(ip, ip.getNav(nav).resolved.?, elf.base.comp.config.any_non_single_threaded),
37084630 },
3709 .uav => |uav| .{ @enumFromInt(switch (try elf.lowerUav(
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 },
4631 .uav => |uav| .{ (try elf.uavMapIndex(uav, .none)).symbol(elf), .OBJECT },
37214632 };
37224633 while (try elf.idle(pt.tid)) {}
3723 const exported_ni = exported_si.node(elf);
3724 const value, const size, const shndx = switch (elf.symPtr(exported_si)) {
4634 const value: u64, const size: u64, const shndx: Section.Index = switch (elf.symPtr(exported_lsi.index())) {
37254635 inline else => |exported_sym| .{
37264636 elf.targetLoad(&exported_sym.value),
3727 exported_sym.size,
3728 exported_sym.shndx,
4637 elf.targetLoad(&exported_sym.size),
4638 .fromSection(elf.targetLoad(&exported_sym.shndx)),
37294639 },
37304640 };
37314641 for (export_indices) |export_index| {
37324642 const @"export" = export_index.ptr(zcu);
37334643 const name = @"export".opts.name.toSlice(ip);
3734 const export_si = try elf.globalSymbol(.{
3735 .name = name,
4644 _ = elf.addGlobalSymbolAssumeCapacity(.{
4645 .node = .none,
4646 .name = try .string(elf, name),
4647 .value = value,
4648 .size = @intCast(size),
37364649 .type = @"type",
37374650 .bind = switch (@"export".opts.linkage) {
3738 .internal => .LOCAL,
3739 .strong => .GLOBAL,
3740 .weak => .WEAK,
4651 .internal => @panic("TODO internal linkage"),
4652 .strong => .strong,
4653 .weak => .weak,
37414654 .link_once => return error.LinkOnceUnsupported,
37424655 },
37434656 .visibility = switch (@"export".opts.visibility) {
......@@ -3745,15 +4658,23 @@ fn updateExportsInner(
37454658 .hidden => .HIDDEN,
37464659 .protected => .PROTECTED,
37474660 },
3748 });
3749 export_si.get(elf).ni = exported_ni;
3750 switch (elf.symPtr(export_si)) {
3751 inline else => |export_sym| {
3752 export_sym.size = @intCast(size);
3753 export_sym.shndx = shndx;
4661 .shndx = shndx,
4662 }) catch |err| switch (err) {
4663 error.MultipleDefinitions => {
4664 // HACK: because we currently don't/can't delete these exports, we would typically
4665 // get these errors on every non-initial incremental update. Hack around that by
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 }
37544676 },
3755 }
3756 export_si.flushMoved(elf, value);
4677 };
37574678 }
37584679}
37594680
......@@ -3807,13 +4728,13 @@ pub fn printNode(
38074728 try w.writeByte(')');
38084729 },
38094730 },
3810 .section => |si| try w.print("({s})", .{elf.sectionName(si)}),
4731 .section => |shndx| try w.print("({s})", .{shndx.name(elf)}),
38114732 .input_section => |isi| {
38124733 const ii = isi.input(elf);
38134734 try w.print("({f}{f}, {s})", .{
38144735 ii.path(elf).fmtEscapeString(),
38154736 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),
38174738 });
38184739 },
38194740 .nav => |nmi| {
src/link/MachO/ZigObject.zig+14-14
......@@ -632,7 +632,7 @@ pub fn getNavVAddr(
632632 switch (reloc_info.parent) {
633633 .none => unreachable,
634634 .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).?;
636636 try parent_atom.addReloc(macho_file, .{
637637 .tag = .@"extern",
638638 .offset = @intCast(reloc_info.offset),
......@@ -650,7 +650,7 @@ pub fn getNavVAddr(
650650 .debug_output => |debug_output| switch (debug_output) {
651651 .dwarf => |wip_nav| try wip_nav.infoExternalReloc(.{
652652 .source_off = @intCast(reloc_info.offset),
653 .target_sym = sym_index,
653 .target_sym = @enumFromInt(sym_index),
654654 .target_off = reloc_info.addend,
655655 }),
656656 .none => unreachable,
......@@ -671,7 +671,7 @@ pub fn getUavVAddr(
671671 switch (reloc_info.parent) {
672672 .none => unreachable,
673673 .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).?;
675675 try parent_atom.addReloc(macho_file, .{
676676 .tag = .@"extern",
677677 .offset = @intCast(reloc_info.offset),
......@@ -689,7 +689,7 @@ pub fn getUavVAddr(
689689 .debug_output => |debug_output| switch (debug_output) {
690690 .dwarf => |wip_nav| try wip_nav.infoExternalReloc(.{
691691 .source_off = @intCast(reloc_info.offset),
692 .target_sym = sym_index,
692 .target_sym = @enumFromInt(sym_index),
693693 .target_off = reloc_info.addend,
694694 }),
695695 .none => unreachable,
......@@ -717,7 +717,7 @@ pub fn lowerUav(
717717 const sym = self.symbols.items[metadata.symbol_index];
718718 const existing_alignment = sym.getAtom(macho_file).?.alignment;
719719 if (uav_alignment.order(existing_alignment).compare(.lte))
720 return .{ .sym_index = metadata.symbol_index };
720 return .{ .sym_index = @enumFromInt(metadata.symbol_index) };
721721 }
722722
723723 var name_buf: [32]u8 = undefined;
......@@ -742,7 +742,7 @@ pub fn lowerUav(
742742 ) },
743743 };
744744 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) }),
746746 .fail => {},
747747 }
748748 return res;
......@@ -790,7 +790,7 @@ pub fn updateFunc(
790790 var aw: std.Io.Writer.Allocating = .init(gpa);
791791 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;
794794 defer if (debug_wip_nav) |*wip_nav| wip_nav.deinit();
795795
796796 codegen.emitFunction(
......@@ -798,7 +798,7 @@ pub fn updateFunc(
798798 pt,
799799 zcu.navSrcLoc(func.owner_nav),
800800 func_index,
801 sym_index,
801 @enumFromInt(sym_index),
802802 mir,
803803 &aw.writer,
804804 if (debug_wip_nav) |*wip_nav| .{ .dwarf = wip_nav } else .none,
......@@ -884,7 +884,7 @@ pub fn updateNav(
884884 const sym_index = try self.getGlobalSymbol(macho_file, name, lib_name);
885885 if (nav.resolved.?.@"threadlocal" and macho_file.base.comp.config.any_non_single_threaded) self.symbols.items[sym_index].flags.tlv = true;
886886 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));
888888 defer debug_wip_nav.deinit();
889889 dwarf.finishWipNav(pt, nav_index, &debug_wip_nav) catch |err| switch (err) {
890890 error.OutOfMemory, error.Overflow => |e| return e,
......@@ -902,7 +902,7 @@ pub fn updateNav(
902902 var aw: std.Io.Writer.Allocating = .init(zcu.gpa);
903903 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;
906906 defer if (debug_wip_nav) |*wip_nav| wip_nav.deinit();
907907
908908 codegen.generateSymbol(
......@@ -911,7 +911,7 @@ pub fn updateNav(
911911 zcu.navSrcLoc(nav_index),
912912 .fromInterned(nav.resolved.?.value),
913913 &aw.writer,
914 .{ .atom_index = sym_index },
914 .{ .atom_index = @enumFromInt(sym_index) },
915915 ) catch |err| switch (err) {
916916 error.WriteFailed => return error.OutOfMemory,
917917 else => |e| return e,
......@@ -1214,7 +1214,7 @@ fn lowerConst(
12141214 src_loc,
12151215 val,
12161216 &aw.writer,
1217 .{ .atom_index = sym_index },
1217 .{ .atom_index = @enumFromInt(sym_index) },
12181218 ) catch |err| switch (err) {
12191219 error.WriteFailed => return error.OutOfMemory,
12201220 else => |e| return e,
......@@ -1242,7 +1242,7 @@ fn lowerConst(
12421242 const file_offset = sect.offset + atom.value;
12431243 try macho_file.pwriteAll(code, file_offset);
12441244
1245 return .{ .sym_index = sym_index };
1245 return .{ .sym_index = @enumFromInt(sym_index) };
12461246}
12471247
12481248pub fn updateExports(
......@@ -1377,7 +1377,7 @@ fn updateLazySymbol(
13771377 &required_alignment,
13781378 &aw.writer,
13791379 .none,
1380 .{ .atom_index = symbol_index },
1380 .{ .atom_index = @enumFromInt(symbol_index) },
13811381 );
13821382 const code = aw.written();
13831383
src/link/MappedFile.zig+9
......@@ -305,6 +305,15 @@ pub const Node = extern struct {
305305 }
306306 }
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
308317 pub fn writer(ni: Node.Index, mf: *MappedFile, gpa: std.mem.Allocator, w: *Writer) void {
309318 w.* = .{
310319 .gpa = gpa,