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

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

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

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

lib/std/elf.zig+16-2
......@@ -1043,7 +1043,7 @@ pub const Elf32 = struct {
10431043 pub const Addr = u32;
10441044 pub const Off = u32;
10451045 pub const Ehdr = extern struct {
1046 ident: [EI.NIDENT]u8,
1046 ident: Ident,
10471047 type: ET,
10481048 machine: EM,
10491049 version: Word,
......@@ -1133,7 +1133,7 @@ pub const Elf64 = struct {
11331133 pub const Addr = u64;
11341134 pub const Off = u64;
11351135 pub const Ehdr = extern struct {
1136 ident: [EI.NIDENT]u8,
1136 ident: Ident,
11371137 type: ET,
11381138 machine: EM,
11391139 version: Word,
......@@ -1611,6 +1611,20 @@ pub const Sym = switch (@sizeOf(usize)) {
16111611/// Deprecated, use `std.elf.ElfN.Addr`
16121612pub const Addr = ElfN.Addr;
16131613
1614pub const Ident = extern struct {
1615 magic: [MAGIC.len]u8 = MAGIC.*,
1616 class: CLASS,
1617 data: DATA,
1618 version: u8,
1619 osabi: OSABI,
1620 abiversion: u8,
1621 pad: [7]u8 = @splat(0),
1622
1623 comptime {
1624 assert(@sizeOf(Ident) == EI.NIDENT);
1625 }
1626};
1627
16141628/// Deprecated, use `@intFromEnum(std.elf.CLASS.NONE)`
16151629pub const ELFCLASSNONE = @intFromEnum(CLASS.NONE);
16161630/// Deprecated, use `@intFromEnum(std.elf.CLASS.@"32")`
lib/std/posix.zig+1-1
......@@ -834,7 +834,7 @@ pub fn dl_iterate_phdr(
834834 while (it.next()) |entry| {
835835 const phdrs: []elf.ElfN.Phdr = if (entry.addr != 0) phdrs: {
836836 const ehdr: *elf.ElfN.Ehdr = @ptrFromInt(entry.addr);
837 assert(mem.eql(u8, ehdr.ident[0..4], elf.MAGIC));
837 assert(mem.eql(u8, &ehdr.ident.magic, elf.MAGIC));
838838 const phdrs: [*]elf.ElfN.Phdr = @ptrFromInt(entry.addr + ehdr.phoff);
839839 break :phdrs phdrs[0..ehdr.phnum];
840840 } else getSelfPhdrs();
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+2180-1211
......@@ -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;
137 pub fn fileSymbol(ii: InputIndex, elf: *const Elf) Symbol.LocalIndex {
138 return elf.inputs.items[@intFromEnum(ii)].file_symbol;
108139 }
109140
110 pub fn fileLocation(isi: InputSectionIndex, elf: *const Elf) MappedFile.Node.FileLocation {
111 return elf.input_sections.items[@intFromEnum(isi)].file_location;
112 }
113
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);
415
416 try elf.node_global_symbols.ensureUnusedCapacity(gpa, len);
268417
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)),
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;
339760 },
340761 }
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 )),
346 }
762 },
763 .prev_in_node = .empty,
764 .next_in_node = old_head,
765 };
347766
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,
354 },
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 }
363 }
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;
364822 }
823 }
824 } else {
825 assert(global_ptr.next_in_node == .empty);
826 assert(global_ptr.prev_in_node == .empty);
827 }
365828
366 if (elf.si.dynsym == .null) return;
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))) {
371 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 }
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,
385922 },
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);
386931 }
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);
400 },
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;
401961 }
402962
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 };
963 const src_sym_ptr = @field(elf.symPtr(src_index), @tagName(class));
964 const dest_sym_ptr = @field(elf.symPtr(dest_index), @tagName(class));
438965
439 const got_plt_shndx = elf.si.got_plt.shndx(elf);
440 const got_plt_ni = elf.si.got_plt.node(elf);
441 _, const got_plt_node_size = got_plt_ni.location(&elf.mf).resolve(&elf.mf);
442 const got_plt_addr = got_plt_addr: switch (elf.shdrPtr(got_plt_shndx)) {
443 inline else => |shdr, class| {
444 const Addr = class.ElfN().Addr;
445 const addr_size = @sizeOf(Addr);
446 const old_size = addr_size * (3 + plt_index);
447 const new_size = old_size + addr_size;
448 elf.targetStore(&shdr.size, new_size);
449 if (new_size > got_plt_node_size) try got_plt_ni.resize(
450 &elf.mf,
451 gpa,
452 new_size +| new_size / MappedFile.growth_factor,
453 );
454 std.mem.writeInt(
455 Addr,
456 got_plt_ni.slice(&elf.mf)[old_size..][0..addr_size],
457 @intCast(plt_addr),
458 target_endian,
459 );
460 break :got_plt_addr elf.targetLoad(&shdr.addr) + old_size;
461 },
462 };
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,
1004 },
1005 // SHN_UNDEF is important: we mustn't define this symbol for other DSOs.
1006 .shndx = std.elf.SHN_UNDEF,
1007 .other = .{ .visibility = .DEFAULT },
1008 };
1009 if (elf.targetEndian() != native_endian) {
1010 std.mem.byteSwapAllFields(class.ElfN().Sym, dynsym);
1011 }
1012 }
1013 },
1014 }
1015}
1016fn addPltEntry(elf: *Elf, global_name: String(.strtab), dynsym_index: u32) void {
1017 const target_endian = elf.targetEndian();
1018 const plt_index: u32 = @intCast(elf.got.plt.count());
1019 elf.got.plt.putAssumeCapacityNoClobber(.global(global_name), {});
1020 switch (elf.ehdrField(.machine)) {
1021 else => |machine| @panic(@tagName(machine)),
1022 .X86_64 => {
1023 const plt_ni = elf.shndx.plt.get(elf).ni;
1024 const plt_addr = plt_addr: switch (elf.shdrPtr(elf.shndx.plt)) {
1025 inline else => |shdr| {
1026 const old_size = 16 * (1 + plt_index);
1027 assert(elf.targetLoad(&shdr.size) == old_size);
1028 elf.targetStore(&shdr.size, old_size + 16);
1029 const plt_slice = plt_ni.slice(&elf.mf)[old_size..][0..16];
1030 @memcpy(plt_slice, &[16]u8{
1031 0xf3, 0x0f, 0x1e, 0xfa, // endbr64
1032 0x68, 0x00, 0x00, 0x00, 0x00, // push $0x0
1033 0xe9, 0x00, 0x00, 0x00, 0x00, // jmp 0
1034 0x66, 0x90, // xchg %ax,%ax
1035 });
1036 std.mem.writeInt(u32, plt_slice[5..][0..4], plt_index, target_endian);
1037 std.mem.writeInt(
1038 i32,
1039 plt_slice[10..][0..4],
1040 -@as(i32, @intCast(old_size + 14)),
1041 target_endian,
1042 );
1043 break :plt_addr elf.targetLoad(&shdr.addr) + old_size;
1044 },
1045 };
1046
1047 const got_plt_shndx = elf.shndx.got_plt;
1048 const got_plt_ni = elf.shndx.got_plt.get(elf).ni;
1049 const got_plt_addr = got_plt_addr: switch (elf.shdrPtr(got_plt_shndx)) {
1050 inline else => |shdr, class| {
1051 const ent_size = @sizeOf(class.ElfN().Addr);
1052 const old_size = ent_size * (3 + plt_index);
1053 elf.targetStore(&shdr.size, old_size + ent_size);
1054 std.mem.writeInt(
1055 class.ElfN().Addr,
1056 got_plt_ni.slice(&elf.mf)[old_size..][0..ent_size],
1057 @intCast(plt_addr),
1058 target_endian,
1059 );
1060 break :got_plt_addr elf.targetLoad(&shdr.addr) + old_size;
1061 },
1062 };
4631063
464 const plt_sec_ni = elf.si.plt_sec.node(elf);
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 }
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 );
1083 },
1084 }
4921085
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);
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),
5201103 },
521 }
522 try rela_plt_ni.resized(gpa, &elf.mf);
1104 .addend = 0,
1105 };
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 };
5511179
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 }
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));
5611196 }
1197 };
5621198
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;
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 };
1220 }
1221
1222 fn toTypeErased(s: Symbol.Id) link.File.SymbolId {
1223 return @enumFromInt(@as(u32, @bitCast(s)));
1224 }
1225 fn fromTypeErased(s: link.File.SymbolId) Symbol.Id {
1226 return @bitCast(@intFromEnum(s));
1227 }
1228
1229 fn index(s: Symbol.Id, elf: *const Elf) Symbol.Index {
1230 return switch (s.unwrap()) {
1231 .local => |lsi| lsi.index(),
1232 .global => |name| elf.globalByName(name).?.symtab_index,
1233 };
1234 }
1235
1236 fn value(s: Symbol.Id, elf: *Elf) u64 {
1237 return switch (elf.symPtr(s.index(elf))) {
1238 inline else => |sym| elf.targetLoad(&sym.value),
1239 };
1240 }
1241
1242 /// Returns `true` if the target of `s` has moved, meaning the symbol's value will change at
1243 /// some point due to a call to `flushMoved`.
1244 fn hasMoved(s: Symbol.Id, elf: *Elf) bool {
1245 const node = s.index(elf).ptr(elf).node;
1246 if (node == .none) return false;
1247 return node.hasMoved(&elf.mf);
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
......@@ -1123,19 +2040,18 @@ fn initHeaders(
11232040 const expected_nodes_len = expected_nodes_len: switch (@"type") {
11242041 .NONE, .CORE, _ => unreachable,
11252042 .REL => {
2043 // Each phdr is actually going to be an shdr.
11262044 defer phnum = 0;
11272045 break :expected_nodes_len 5 + phnum;
11282046 },
1129 .EXEC, .DYN => break :expected_nodes_len 8 + phnum * 2 +
1130 @intFromBool(maybe_interp != null) +
1131 @as(usize, 4) * @intFromBool(have_dynamic_section) +
1132 @intFromBool(comp.config.any_non_single_threaded),
2047 .EXEC, .DYN => break :expected_nodes_len 10 +
2048 phnum * 2 - 1 + // each phdr also has a matching shdr, except for the PT_PHDR phdr
2049 @as(usize, 4) * @intFromBool(have_dynamic_section), // .dynstr, .dynsym, .rela.dyn, .rela.plt
11332050 };
11342051 try elf.nodes.ensureTotalCapacity(gpa, expected_nodes_len);
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) {
......@@ -1150,14 +2066,13 @@ fn initHeaders(
11502066 elf.nodes.appendAssumeCapacity(.ehdr);
11512067
11522068 const ehdr: *ElfN.Ehdr = @ptrCast(@alignCast(elf.ni.ehdr.slice(&elf.mf)));
1153 const EI = std.elf.EI;
1154 @memcpy(ehdr.ident[0..std.elf.MAGIC.len], std.elf.MAGIC);
1155 ehdr.ident[EI.CLASS] = @intFromEnum(class);
1156 ehdr.ident[EI.DATA] = @intFromEnum(data);
1157 ehdr.ident[EI.VERSION] = 1;
1158 ehdr.ident[EI.OSABI] = @intFromEnum(osabi);
1159 ehdr.ident[EI.ABIVERSION] = 0;
1160 @memset(ehdr.ident[EI.PAD..], 0);
2069 ehdr.ident = .{
2070 .class = class,
2071 .data = data,
2072 .version = 1,
2073 .osabi = osabi,
2074 .abiversion = 0,
2075 };
11612076 ehdr.type = @"type";
11622077 ehdr.machine = machine;
11632078 ehdr.version = 1;
......@@ -1176,7 +2091,7 @@ fn initHeaders(
11762091 }
11772092
11782093 assert(elf.ni.shdr == try elf.mf.addLastChildNode(gpa, elf.ni.file, .{
1179 .size = elf.ehdrField(.shentsize) * elf.ehdrField(.shnum),
2094 .size = @as(u64, elf.ehdrField(.shentsize)) * @as(u64, elf.ehdrField(.shnum)),
11802095 .alignment = elf.mf.flags.block_size,
11812096 .moved = true,
11822097 .resized = true,
......@@ -1366,7 +2281,7 @@ fn initHeaders(
13662281
13672282 const sh_undef: *ElfN.Shdr = @ptrCast(@alignCast(elf.ni.shdr.slice(&elf.mf)));
13682283 sh_undef.* = .{
1369 .name = try elf.string(.shstrtab, ""),
2284 .name = @intFromEnum(String(.shstrtab).empty),
13702285 .type = .NULL,
13712286 .flags = .{ .shf = .{} },
13722287 .addr = 0,
......@@ -1378,24 +2293,23 @@ fn initHeaders(
13782293 .entsize = 0,
13792294 };
13802295 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Shdr, sh_undef);
1381 elf.shdrs.appendAssumeCapacity(.{ .si = .null, .rela_si = .null, .rela_free = .none });
2296 elf.shdrs.appendAssumeCapacity(.{ .lsi = .null, .ni = .none, .rela_shndx = .UNDEF, .rela_free = .none });
13822297
13832298 elf.symtab.addOneAssumeCapacity().* = .{
1384 .ni = .none,
1385 .loc_relocs = .none,
1386 .target_relocs = .none,
1387 .unused = 0,
2299 .node = .none,
2300 .first_target_reloc = .none,
13882301 };
1389 assert(elf.si.symtab == try elf.addSection(elf.ni.file, .{
2302 assert(.symtab == try elf.addSection(elf.ni.file, .{
13902303 .type = .SYMTAB,
13912304 .size = @sizeOf(ElfN.Sym) * 1,
13922305 .addralign = addr_align,
13932306 .entsize = @sizeOf(ElfN.Sym),
13942307 .node_align = elf.mf.flags.block_size,
2308 .info = 1, // index of first non-local symbol
13952309 }));
13962310 const symtab_null = @field(elf.symPtr(.null), @tagName(ct_class));
13972311 symtab_null.* = .{
1398 .name = try elf.string(.strtab, ""),
2312 .name = @intFromEnum(String(.strtab).empty),
13992313 .value = 0,
14002314 .size = 0,
14012315 .info = .{ .type = .NOTYPE, .bind = .LOCAL },
......@@ -1408,55 +2322,56 @@ fn initHeaders(
14082322 ehdr.shstrndx = ehdr.shnum;
14092323 },
14102324 }
1411 assert(elf.si.shstrtab == try elf.addSection(elf.ni.file, .{
2325 assert(.shstrtab == try elf.addSection(elf.ni.file, .{
14122326 .type = .STRTAB,
14132327 .size = 1,
14142328 .entsize = 1,
14152329 .node_align = elf.mf.flags.block_size,
14162330 }));
1417 try elf.renameSection(.symtab, ".symtab");
1418 try elf.renameSection(.shstrtab, ".shstrtab");
1419 elf.si.shstrtab.node(elf).slice(&elf.mf)[0] = 0;
2331 Section.Index.get(.shstrtab, elf).ni.slice(&elf.mf)[0] = 0;
14202332
1421 assert(elf.si.strtab == try elf.addSection(elf.ni.file, .{
2333 try Section.Index.symtab.rename(elf, ".symtab");
2334 try Section.Index.shstrtab.rename(elf, ".shstrtab");
2335
2336 assert(.strtab == try elf.addSection(elf.ni.file, .{
14222337 .name = ".strtab",
14232338 .type = .STRTAB,
14242339 .size = 1,
14252340 .entsize = 1,
14262341 .node_align = elf.mf.flags.block_size,
14272342 }));
1428 switch (elf.shdrPtr(elf.si.symtab.shndx(elf))) {
1429 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)),
14302346 }
1431 elf.si.strtab.node(elf).slice(&elf.mf)[0] = 0;
14322347
1433 assert(elf.si.rodata == try elf.addSection(elf.ni.rodata, .{
2348 assert(.rodata == try elf.addSection(elf.ni.rodata, .{
14342349 .name = ".rodata",
14352350 .flags = .{ .ALLOC = true },
14362351 .addralign = elf.mf.flags.block_size,
14372352 }));
1438 assert(elf.si.text == try elf.addSection(elf.ni.text, .{
2353 assert(.text == try elf.addSection(elf.ni.text, .{
14392354 .name = ".text",
14402355 .flags = .{ .ALLOC = true, .EXECINSTR = true },
14412356 .addralign = elf.mf.flags.block_size,
14422357 }));
1443 assert(elf.si.data == try elf.addSection(elf.ni.data, .{
2358 assert(.data == try elf.addSection(elf.ni.data, .{
14442359 .name = ".data",
14452360 .flags = .{ .WRITE = true, .ALLOC = true },
14462361 .addralign = elf.mf.flags.block_size,
14472362 }));
1448 assert(elf.si.data_rel_ro == try elf.addSection(elf.ni.data_rel_ro, .{
2363 assert(.data_rel_ro == try elf.addSection(elf.ni.data_rel_ro, .{
14492364 .name = ".data.rel.ro",
14502365 .flags = .{ .WRITE = true, .ALLOC = true },
14512366 .addralign = elf.mf.flags.block_size,
14522367 }));
14532368 if (@"type" != .REL) {
1454 assert(elf.si.got == try elf.addSection(elf.ni.data_rel_ro, .{
2369 elf.shndx.got = try elf.addSection(elf.ni.data_rel_ro, .{
14552370 .name = ".got",
14562371 .flags = .{ .WRITE = true, .ALLOC = true },
14572372 .addralign = addr_align,
1458 }));
1459 assert(elf.si.got_plt == try elf.addSection(
2373 });
2374 elf.shndx.got_plt = try elf.addSection(
14602375 if (elf.options.z_now) elf.ni.data_rel_ro else elf.ni.data,
14612376 .{
14622377 .name = ".got.plt",
......@@ -1469,26 +2384,26 @@ fn initHeaders(
14692384 },
14702385 .addralign = addr_align,
14712386 },
1472 ));
2387 );
14732388 const plt_size: std.elf.Xword, const plt_align: std.mem.Alignment, const plt_sec =
14742389 switch (machine) {
14752390 else => @panic(@tagName(machine)),
14762391 .X86_64 => .{ 16, .@"16", true },
14772392 };
1478 assert(elf.si.plt == try elf.addSection(elf.ni.text, .{
2393 elf.shndx.plt = try elf.addSection(elf.ni.text, .{
14792394 .name = ".plt",
14802395 .type = .PROGBITS,
14812396 .flags = .{ .ALLOC = true, .EXECINSTR = true },
14822397 .size = plt_size,
14832398 .addralign = plt_align,
14842399 .node_align = elf.mf.flags.block_size,
1485 }));
1486 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, .{
14872402 .name = ".plt.sec",
14882403 .flags = .{ .ALLOC = true, .EXECINSTR = true },
14892404 .addralign = plt_align,
14902405 .node_align = elf.mf.flags.block_size,
1491 }));
2406 });
14922407 if (maybe_interp) |interp| {
14932408 const interp_ni = try elf.mf.addLastChildNode(gpa, elf.ni.rodata, .{
14942409 .size = interp.len + 1,
......@@ -1499,13 +2414,13 @@ fn initHeaders(
14992414 elf.nodes.appendAssumeCapacity(.{ .segment = interp_phndx });
15002415 elf.phdrs.items[interp_phndx] = interp_ni;
15012416
1502 const sec_interp_si = try elf.addSection(interp_ni, .{
2417 const sec_interp_shndx = try elf.addSection(interp_ni, .{
15032418 .name = ".interp",
15042419 .type = .PROGBITS,
15052420 .flags = .{ .ALLOC = true },
15062421 .size = @intCast(interp.len + 1),
15072422 });
1508 const sec_interp = sec_interp_si.node(elf).slice(&elf.mf);
2423 const sec_interp = sec_interp_shndx.get(elf).ni.slice(&elf.mf);
15092424 @memcpy(sec_interp[0..interp.len], interp);
15102425 sec_interp[interp.len] = 0;
15112426 }
......@@ -1518,7 +2433,7 @@ fn initHeaders(
15182433 elf.nodes.appendAssumeCapacity(.{ .segment = dynamic_phndx });
15192434 elf.phdrs.items[dynamic_phndx] = dynamic_ni;
15202435
1521 elf.si.dynstr = try elf.addSection(elf.ni.rodata, .{
2436 const dynstr_shndx = try elf.addSection(elf.ni.rodata, .{
15222437 .name = ".dynstr",
15232438 .type = .STRTAB,
15242439 .flags = .{ .ALLOC = true },
......@@ -1526,26 +2441,27 @@ fn initHeaders(
15262441 .entsize = 1,
15272442 .node_align = elf.mf.flags.block_size,
15282443 });
1529 const dynstr_shndx = elf.si.dynstr.shndx(elf);
1530 elf.dynsym.putAssumeCapacityNoClobber(.null, {});
2444 dynstr_shndx.get(elf).ni.slice(&elf.mf)[0] = 0;
2445 elf.shndx.dynstr = dynstr_shndx;
2446
15312447 switch (class) {
15322448 .NONE, _ => unreachable,
15332449 inline else => |ct_class| {
15342450 const Sym = ct_class.ElfN().Sym;
1535 elf.si.dynsym = try elf.addSection(elf.ni.rodata, .{
2451 elf.shndx.dynsym = try elf.addSection(elf.ni.rodata, .{
15362452 .name = ".dynsym",
15372453 .type = .DYNSYM,
15382454 .flags = .{ .ALLOC = true },
15392455 .size = @sizeOf(Sym) * 1,
1540 .link = @intFromEnum(dynstr_shndx),
2456 .link = dynstr_shndx.toSection().?,
15412457 .info = 1,
15422458 .addralign = addr_align,
15432459 .entsize = @sizeOf(Sym),
15442460 .node_align = elf.mf.flags.block_size,
15452461 });
1546 const dynsym_null = &@field(elf.dynsymSlice(), @tagName(ct_class))[0];
2462 const dynsym_null = @field(elf.dynsymPtr(0), @tagName(ct_class));
15472463 dynsym_null.* = .{
1548 .name = try elf.string(.dynstr, ""),
2464 .name = @intFromEnum(String(.dynstr).empty),
15492465 .value = 0,
15502466 .size = 0,
15512467 .info = .{ .type = .NOTYPE, .bind = .LOCAL },
......@@ -1562,57 +2478,57 @@ fn initHeaders(
15622478 .NONE, _ => unreachable,
15632479 inline else => |ct_class| @sizeOf(ct_class.ElfN().Rela),
15642480 };
1565 elf.si.got.shndx(elf).get(elf).rela_si = try elf.addSection(elf.ni.rodata, .{
2481 elf.shndx.got.get(elf).rela_shndx = try elf.addSection(elf.ni.rodata, .{
15662482 .name = ".rela.dyn",
15672483 .type = .RELA,
15682484 .flags = .{ .ALLOC = true },
1569 .link = @intFromEnum(elf.si.dynsym.shndx(elf)),
2485 .link = elf.shndx.dynsym.toSection().?,
15702486 .addralign = addr_align,
15712487 .entsize = rela_size,
15722488 .node_align = elf.mf.flags.block_size,
15732489 });
1574 const got_plt_shndx = elf.si.got_plt.shndx(elf);
1575 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, .{
15762492 .name = ".rela.plt",
15772493 .type = .RELA,
15782494 .flags = .{ .ALLOC = true, .INFO_LINK = true },
1579 .link = @intFromEnum(elf.si.dynsym.shndx(elf)),
1580 .info = @intFromEnum(got_plt_shndx),
2495 .link = elf.shndx.dynsym.toSection().?,
2496 .info = got_plt_shndx.toSection().?,
15812497 .addralign = addr_align,
15822498 .entsize = rela_size,
15832499 .node_align = elf.mf.flags.block_size,
15842500 });
1585 elf.si.dynamic = try elf.addSection(dynamic_ni, .{
2501 elf.shndx.dynamic = try elf.addSection(dynamic_ni, .{
15862502 .name = ".dynamic",
15872503 .type = .DYNAMIC,
15882504 .flags = .{ .ALLOC = true, .WRITE = true },
1589 .link = @intFromEnum(dynstr_shndx),
2505 .link = dynstr_shndx.toSection().?,
15902506 .entsize = @intCast(addr_align.toByteUnits() * 2),
15912507 .node_align = addr_align,
15922508 });
15932509 switch (machine) {
15942510 else => @panic(@tagName(machine)),
15952511 .X86_64 => {
1596 @memcpy(elf.si.plt.node(elf).slice(&elf.mf)[0..16], &[16]u8{
2512 const plt_ni = elf.shndx.plt.get(elf).ni;
2513 const got_plt_sym: Symbol.Id = .local(elf.shndx.got_plt.get(elf).lsi);
2514 @memcpy(plt_ni.slice(&elf.mf)[0..16], &[16]u8{
15972515 0xff, 0x35, 0x00, 0x00, 0x00, 0x00, // push 0x0(%rip)
15982516 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *0x0(%rip)
15992517 0x0f, 0x1f, 0x40, 0x00, // nopl 0x0(%rax)
16002518 });
1601 const plt_sym = elf.si.plt.get(elf);
1602 assert(plt_sym.loc_relocs == .none);
1603 plt_sym.loc_relocs = @enumFromInt(elf.relocs.items.len);
1604 try elf.ensureUnusedRelocCapacity(elf.si.plt, 2);
2519 elf.first_plt_reloc = @enumFromInt(elf.relocs.items.len);
2520 try elf.ensureUnusedRelocCapacity(plt_ni, 2);
16052521 elf.addRelocAssumeCapacity(
1606 elf.si.plt,
2522 plt_ni,
16072523 2,
1608 elf.si.got_plt,
2524 got_plt_sym,
16092525 8 * 1 - 4,
16102526 .{ .X86_64 = .PC32 },
16112527 );
16122528 elf.addRelocAssumeCapacity(
1613 elf.si.plt,
2529 plt_ni,
16142530 8,
1615 elf.si.got_plt,
2531 got_plt_sym,
16162532 8 * 2 - 4,
16172533 .{ .X86_64 = .PC32 },
16182534 );
......@@ -1632,7 +2548,7 @@ fn initHeaders(
16322548 assert(maybe_interp == null);
16332549 assert(!have_dynamic_section);
16342550 }
1635 if (comp.config.any_non_single_threaded) elf.si.tdata = try elf.addSection(elf.ni.tls, .{
2551 if (comp.config.any_non_single_threaded) elf.shndx.tdata = try elf.addSection(elf.ni.tls, .{
16362552 .name = ".tdata",
16372553 .flags = .{ .WRITE = true, .ALLOC = true, .TLS = true },
16382554 .addralign = elf.mf.flags.block_size,
......@@ -1642,7 +2558,7 @@ fn initHeaders(
16422558
16432559pub fn startProgress(elf: *Elf, prog_node: std.Progress.Node) void {
16442560 prog_node.increaseEstimatedTotalItems(4);
1645 elf.const_prog_node = prog_node.start("Constants", elf.pending_uavs.count());
2561 elf.const_prog_node = prog_node.start("Constants", elf.pending_uavs.items.len);
16462562 elf.synth_prog_node = prog_node.start("Synthetics", count: {
16472563 var count: usize = 0;
16482564 for (&elf.lazy.values) |*lazy| count += lazy.map.count() - lazy.pending_index;
......@@ -1669,35 +2585,105 @@ pub fn endProgress(elf: *Elf) void {
16692585fn getNode(elf: *const Elf, ni: MappedFile.Node.Index) Node {
16702586 return elf.nodes.get(@intFromEnum(ni));
16712587}
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}
16722606fn computeNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 {
1673 const parent_vaddr = parent_vaddr: {
1674 const parent_ni = ni.parent(&elf.mf);
1675 const parent_si = switch (elf.getNode(parent_ni)) {
1676 .file => return 0,
1677 .ehdr, .shdr => unreachable,
1678 .segment => |phndx| break :parent_vaddr switch (elf.phdrSlice()) {
1679 inline else => |phdr| elf.targetLoad(&phdr[phndx].vaddr),
1680 },
1681 .section => |si| si,
1682 .input_section => unreachable,
1683 inline .nav, .uav, .lazy_code, .lazy_const_data => |mi| mi.symbol(elf),
1684 };
1685 break :parent_vaddr if (parent_si == elf.si.tdata) 0 else switch (elf.symPtr(parent_si)) {
1686 inline else => |sym| elf.targetLoad(&sym.value),
1687 };
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),
16882616 };
16892617 const offset, _ = ni.location(&elf.mf).resolve(&elf.mf);
16902618 return parent_vaddr + offset;
16912619}
16922620
1693pub fn identClass(elf: *const Elf) std.elf.CLASS {
2621/// Deletes any existing relocations in the given node, and marks the start of the node's contiguous
2622/// sequence of relocations, so that the caller may append the node's updated relocations.
2623///
2624/// Asserts that `ni` must be a node which supports relocations (see `Elf.Node`). Does not support
2625/// the special-case sections '.plt' and '.dynamic'.
2626fn resetNodeRelocs(elf: *Elf, ni: MappedFile.Node.Index) void {
2627 const first_reloc_ptr: *Reloc.Index = switch (elf.getNode(ni)) {
2628 .file => unreachable, // cannot contain relocs
2629 .ehdr => unreachable, // cannot contain relocs
2630 .shdr => unreachable, // cannot contain relocs
2631 .segment => unreachable, // cannot contain relocs
2632 .section => unreachable, // cannot contain relocs (.plt and .dynamic unsupported)
2633 .input_section => |isi| &elf.input_sections.items[@intFromEnum(isi)].first_reloc,
2634 .nav => |nmi| &elf.navs.values()[@intFromEnum(nmi)].first_reloc,
2635 .uav => |umi| &elf.uavs.values()[@intFromEnum(umi)].first_reloc,
2636 inline .lazy_code, .lazy_const_data => |lmi| &elf.lazy.getPtr(lmi.ref().kind).map.values()[lmi.ref().index].first_reloc,
2637 };
2638 if (first_reloc_ptr.* != .none) {
2639 for (elf.relocs.items[@intFromEnum(first_reloc_ptr.*)..]) |*reloc| {
2640 if (reloc.node != ni) break;
2641 reloc.delete(elf);
2642 }
2643 }
2644 first_reloc_ptr.* = @enumFromInt(elf.relocs.items.len);
2645}
2646
2647/// Given that `node` has moved, updates all relocations in `node` (starting from `first_reloc`) as
2648/// needed. In relocatables, this means updating the offsets of those relocations. In ELF modules,
2649/// this means applying the relocations.
2650fn flushMovedNodeRelocs(
2651 elf: *Elf,
2652 node: MappedFile.Node.Index,
2653 node_vaddr: u64,
2654 first_reloc: Reloc.Index,
2655) void {
2656 if (first_reloc == .none) return;
2657 switch (elf.ehdrField(.type)) {
2658 .NONE, .CORE, _ => unreachable,
2659 .REL => {
2660 // In a relocatable, we're not actually applying any relocations ourselves, but we need
2661 // to update the offsets of the relocation entries since the node they're in has moved.
2662 for (elf.relocs.items[@intFromEnum(first_reloc)..]) |*reloc| {
2663 if (reloc.node != node) break;
2664 reloc.updateNodeOffset(elf, node_vaddr);
2665 }
2666 },
2667 .EXEC, .DYN => {
2668 // For an ELF module, we just need to apply relocations.
2669 for (elf.relocs.items[@intFromEnum(first_reloc)..]) |*reloc| {
2670 if (reloc.node != node) break;
2671 reloc.apply(elf);
2672 }
2673 // TODO: once we're emitting runtime relocation entries, we need to update their offsets
2674 // too, like the logic for relocatables above.
2675 },
2676 }
2677}
2678
2679fn identClass(elf: *const Elf) std.elf.CLASS {
16942680 return @enumFromInt(elf.mf.memory_map.memory[std.elf.EI.CLASS]);
16952681}
1696pub fn identData(elf: *const Elf) std.elf.DATA {
2682fn identData(elf: *const Elf) std.elf.DATA {
16972683 return @enumFromInt(elf.mf.memory_map.memory[std.elf.EI.DATA]);
16982684}
16992685
1700pub fn targetEndian(elf: *const Elf) std.lang.Endian {
2686fn targetEndian(elf: *const Elf) std.lang.Endian {
17012687 return switch (elf.identData()) {
17022688 .NONE, _ => unreachable,
17032689 .@"2LSB" => .little,
......@@ -1731,12 +2717,12 @@ fn targetStore(elf: *const Elf, ptr: anytype, val: @typeInfo(@TypeOf(ptr)).point
17312717 };
17322718}
17332719
1734pub const EhdrPtr = union(std.elf.CLASS) {
2720const EhdrPtr = union(std.elf.CLASS) {
17352721 NONE: noreturn,
17362722 @"32": *std.elf.Elf32.Ehdr,
17372723 @"64": *std.elf.Elf64.Ehdr,
17382724};
1739pub fn ehdrPtr(elf: *Elf) EhdrPtr {
2725fn ehdrPtr(elf: *Elf) EhdrPtr {
17402726 const slice = elf.ni.ehdr.slice(&elf.mf);
17412727 return switch (elf.identClass()) {
17422728 .NONE, _ => unreachable,
......@@ -1747,7 +2733,7 @@ pub fn ehdrPtr(elf: *Elf) EhdrPtr {
17472733 ),
17482734 };
17492735}
1750pub fn ehdrField(
2736fn ehdrField(
17512737 elf: *Elf,
17522738 comptime field: std.meta.FieldEnum(std.elf.Elf64.Ehdr),
17532739) @FieldType(std.elf.Elf64.Ehdr, @tagName(field)) {
......@@ -1756,12 +2742,12 @@ pub fn ehdrField(
17562742 };
17572743}
17582744
1759pub const PhdrSlice = union(std.elf.CLASS) {
2745const PhdrSlice = union(std.elf.CLASS) {
17602746 NONE: noreturn,
17612747 @"32": []std.elf.Elf32.Phdr,
17622748 @"64": []std.elf.Elf64.Phdr,
17632749};
1764pub fn phdrSlice(elf: *Elf) PhdrSlice {
2750fn phdrSlice(elf: *Elf) PhdrSlice {
17652751 assert(elf.ehdrField(.type) != .REL);
17662752 const slice = elf.ni.phdr.slice(&elf.mf);
17672753 return switch (elf.identClass()) {
......@@ -1774,104 +2760,47 @@ pub fn phdrSlice(elf: *Elf) PhdrSlice {
17742760 };
17752761}
17762762
1777pub const ShdrSlice = union(std.elf.CLASS) {
1778 NONE: noreturn,
1779 @"32": []std.elf.Elf32.Shdr,
1780 @"64": []std.elf.Elf64.Shdr,
1781};
1782pub fn shdrSlice(elf: *Elf) ShdrSlice {
1783 const slice = elf.ni.shdr.slice(&elf.mf);
1784 return switch (elf.identClass()) {
1785 .NONE, _ => unreachable,
1786 inline else => |class| @unionInit(
1787 ShdrSlice,
1788 @tagName(class),
1789 @ptrCast(@alignCast(slice)),
1790 ),
1791 };
1792}
1793
1794pub const ShdrPtr = union(std.elf.CLASS) {
2763const ShdrPtr = union(std.elf.CLASS) {
17952764 NONE: noreturn,
17962765 @"32": *std.elf.Elf32.Shdr,
17972766 @"64": *std.elf.Elf64.Shdr,
17982767};
1799pub fn shdrPtr(elf: *Elf, shndx: Symbol.Index.Shndx) ShdrPtr {
1800 return switch (elf.shdrSlice()) {
1801 inline else => |shdrs, class| @unionInit(ShdrPtr, @tagName(class), &shdrs[@intFromEnum(shndx)]),
1802 };
1803}
1804
1805pub const SymtabSlice = union(std.elf.CLASS) {
1806 NONE: noreturn,
1807 @"32": []std.elf.Elf32.Sym,
1808 @"64": []std.elf.Elf64.Sym,
1809};
1810pub fn symtabSlice(elf: *Elf) SymtabSlice {
1811 const slice = elf.si.symtab.node(elf).slice(&elf.mf);
1812 return switch (elf.identClass()) {
2768fn shdrPtr(elf: *Elf, shndx: Section.Index) ShdrPtr {
2769 const raw_slice = elf.ni.shdr.slice(&elf.mf);
2770 switch (elf.identClass()) {
18132771 .NONE, _ => unreachable,
1814 inline else => |class| @unionInit(SymtabSlice, @tagName(class), @ptrCast(@alignCast(
1815 slice[0..std.mem.alignBackwardAnyAlign(usize, slice.len, @sizeOf(class.ElfN().Sym))],
1816 ))),
1817 };
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 }
18182778}
18192779
1820pub const SymPtr = union(std.elf.CLASS) {
2780const SymPtr = union(std.elf.CLASS) {
18212781 NONE: noreturn,
18222782 @"32": *std.elf.Elf32.Sym,
18232783 @"64": *std.elf.Elf64.Sym,
1824};
1825pub fn symPtr(elf: *Elf, si: Symbol.Index) SymPtr {
1826 return switch (elf.symtabSlice()) {
1827 inline else => |syms, class| @unionInit(SymPtr, @tagName(class), &syms[@intFromEnum(si)]),
1828 };
1829}
1830
1831pub fn dynsymSlice(elf: *Elf) SymtabSlice {
1832 const slice = elf.si.dynsym.node(elf).slice(&elf.mf);
1833 return switch (elf.identClass()) {
1834 .NONE, _ => unreachable,
1835 inline else => |class| @unionInit(SymtabSlice, @tagName(class), @ptrCast(@alignCast(
1836 slice[0..std.mem.alignBackwardAnyAlign(usize, slice.len, @sizeOf(class.ElfN().Sym))],
1837 ))),
1838 };
1839}
1840
1841fn addSymbolAssumeCapacity(elf: *Elf) Symbol.Index {
1842 defer elf.symtab.addOneAssumeCapacity().* = .{
1843 .ni = .none,
1844 .loc_relocs = .none,
1845 .target_relocs = .none,
1846 .unused = 0,
1847 };
1848 return @enumFromInt(elf.symtab.items.len);
1849}
1850
1851fn initSymbolAssumeCapacity(elf: *Elf, opts: Symbol.Index.InitOptions) !Symbol.Index {
1852 const si = elf.addSymbolAssumeCapacity();
1853 try si.init(elf, opts);
1854 return si;
1855}
1856
1857pub fn globalSymbol(elf: *Elf, opts: struct {
1858 name: []const u8,
1859 lib_name: ?[]const u8 = null,
1860 type: std.elf.STT,
1861 bind: std.elf.STB = .GLOBAL,
1862 visibility: std.elf.STV = .DEFAULT,
1863}) !Symbol.Index {
1864 const gpa = elf.base.comp.gpa;
1865 try elf.symtab.ensureUnusedCapacity(gpa, 1);
1866 const global_gop = try elf.globals.getOrPut(gpa, try elf.string(.strtab, opts.name));
1867 if (!global_gop.found_existing) global_gop.value_ptr.* = try elf.initSymbolAssumeCapacity(.{
1868 .name = opts.name,
1869 .lib_name = opts.lib_name,
1870 .type = opts.type,
1871 .bind = opts.bind,
1872 .visibility = opts.visibility,
1873 });
1874 return global_gop.value_ptr.*;
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 }
2794}
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 }
18752804}
18762805
18772806fn navType(
......@@ -1886,97 +2815,135 @@ fn navType(
18862815 else
18872816 .OBJECT;
18882817}
1889fn namedSection(elf: *const Elf, name: []const u8) ?Symbol.Index {
2818fn namedSection(elf: *const Elf, name: []const u8) ?Section.Index {
18902819 if (std.mem.eql(u8, name, ".rodata") or
1891 std.mem.startsWith(u8, name, ".rodata.")) return elf.si.rodata;
2820 std.mem.startsWith(u8, name, ".rodata.")) return .rodata;
18922821 if (std.mem.eql(u8, name, ".text") or
1893 std.mem.startsWith(u8, name, ".text.")) return elf.si.text;
2822 std.mem.startsWith(u8, name, ".text.")) return .text;
18942823 if (std.mem.eql(u8, name, ".data") or
1895 std.mem.startsWith(u8, name, ".data.")) return elf.si.data;
2824 std.mem.startsWith(u8, name, ".data.")) return .data;
18962825 if (std.mem.eql(u8, name, ".tdata") or
1897 std.mem.startsWith(u8, name, ".tdata.")) return elf.si.tdata;
2826 std.mem.startsWith(u8, name, ".tdata.")) return elf.shndx.tdata;
18982827 return null;
18992828}
1900fn navSection(
1901 elf: *Elf,
1902 ip: *const InternPool,
1903 nav_resolved: @typeInfo(@FieldType(InternPool.Nav, "resolved")).optional.child,
1904) Symbol.Index {
1905 if (nav_resolved.@"linksection".toSlice(ip)) |@"linksection"|
1906 if (elf.namedSection(@"linksection")) |si| return si;
1907 return switch (navType(
1908 ip,
1909 nav_resolved,
1910 elf.base.comp.config.any_non_single_threaded,
1911 )) {
1912 else => unreachable,
1913 .FUNC => elf.si.text,
1914 .OBJECT => elf.si.data,
1915 .TLS => elf.si.tdata,
1916 };
1917}
19182829fn navMapIndex(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Node.NavMapIndex {
19192830 const gpa = zcu.gpa;
19202831 const ip = &zcu.intern_pool;
19212832 const nav = ip.getNav(nav_index);
1922 try elf.symtab.ensureUnusedCapacity(gpa, 1);
1923 const nav_gop = try elf.navs.getOrPut(gpa, nav_index);
1924 if (!nav_gop.found_existing) nav_gop.value_ptr.* = try elf.initSymbolAssumeCapacity(.{
1925 .name = nav.fqn.toSlice(ip),
1926 .type = navType(ip, nav.resolved.?, elf.base.comp.config.any_non_single_threaded),
1927 });
1928 return @enumFromInt(nav_gop.index);
1929}
1930pub fn navSymbol(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Symbol.Index {
1931 const ip = &zcu.intern_pool;
1932 const nav = ip.getNav(nav_index);
1933 if (nav.getExtern(ip)) |@"extern"| return elf.globalSymbol(.{
1934 .name = @"extern".name.toSlice(ip),
1935 .lib_name = @"extern".lib_name.toSlice(ip),
1936 .type = navType(ip, nav.resolved.?, elf.base.comp.config.any_non_single_threaded),
1937 .bind = switch (@"extern".linkage) {
1938 .internal => .LOCAL,
1939 .strong => .GLOBAL,
1940 .weak => .WEAK,
1941 .link_once => return error.LinkOnceUnsupported,
1942 },
1943 .visibility = switch (@"extern".visibility) {
1944 .default => .DEFAULT,
1945 .hidden => .HIDDEN,
1946 .protected => .PROTECTED,
1947 },
1948 });
1949 const nmi = try elf.navMapIndex(zcu, nav_index);
1950 return nmi.symbol(elf);
1951}
19522833
1953fn uavMapIndex(elf: *Elf, uav_val: InternPool.Index) !Node.UavMapIndex {
1954 const gpa = elf.base.comp.gpa;
1955 try elf.symtab.ensureUnusedCapacity(gpa, 1);
1956 const uav_gop = try elf.uavs.getOrPut(gpa, uav_val);
1957 if (!uav_gop.found_existing)
1958 uav_gop.value_ptr.* = try elf.initSymbolAssumeCapacity(.{ .type = .OBJECT });
1959 return @enumFromInt(uav_gop.index);
1960}
1961pub fn uavSymbol(elf: *Elf, uav_val: InternPool.Index) !Symbol.Index {
1962 const umi = try elf.uavMapIndex(uav_val);
1963 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;
19642891}
19652892
1966pub fn lazySymbol(elf: *Elf, lazy: link.File.LazySymbol) !Symbol.Index {
2893fn uavMapIndex(
2894 elf: *Elf,
2895 uav_val: InternPool.Index,
2896 uav_align: InternPool.Alignment,
2897) !Node.UavMapIndex {
19672898 const gpa = elf.base.comp.gpa;
1968 try elf.symtab.ensureUnusedCapacity(gpa, 1);
1969 const lazy_gop = try elf.lazy.getPtr(lazy.kind).map.getOrPut(gpa, lazy.ty);
1970 if (!lazy_gop.found_existing) {
1971 lazy_gop.value_ptr.* = try elf.initSymbolAssumeCapacity(.{
1972 .type = switch (lazy.kind) {
1973 .code => .FUNC,
1974 .const_data => .OBJECT,
1975 },
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(),
19762919 });
1977 elf.synth_prog_node.increaseEstimatedTotalItems(1);
2920 var name_buf: [32]u8 = undefined;
2921 const name = std.fmt.bufPrint(
2922 &name_buf,
2923 "__anon_{d}",
2924 .{@intFromEnum(uav_val)},
2925 ) catch unreachable;
2926 uav_gop.value_ptr.* = .{
2927 .lsi = elf.addLocalSymbolAssumeCapacity(.{
2928 .node = node,
2929 .name = try elf.string(.strtab, name),
2930 .value = 0,
2931 .size = 0,
2932 .type = .OBJECT,
2933 .shndx = shndx,
2934 }),
2935 .first_reloc = .none,
2936 };
2937 elf.nodes.appendAssumeCapacity(.{ .uav = umi });
2938 elf.const_prog_node.increaseEstimatedTotalItems(1);
2939 elf.pending_uavs.appendAssumeCapacity(umi);
2940 } else {
2941 const node = uav_gop.value_ptr.lsi.index().ptr(elf).node;
2942 if (resolved_align.toStdMem().order(node.alignment(&elf.mf)).compare(.gt)) {
2943 node.realign(&elf.mf, resolved_align.toStdMem());
2944 }
19782945 }
1979 return lazy_gop.value_ptr.*;
2946 return umi;
19802947}
19812948
19822949pub fn loadInput(elf: *Elf, input: link.Input) (Io.File.Reader.SizeError ||
......@@ -2081,22 +3048,23 @@ fn loadObject(
20813048 const diags = &comp.link_diags;
20823049 const r = &fr.interface;
20833050
2084 const ii: Node.InputIndex = @enumFromInt(elf.inputs.items.len);
3051 const input_index: Node.InputIndex = @enumFromInt(elf.inputs.items.len);
20853052 log.debug("loadObject({f}{f})", .{ path.fmtEscapeString(), fmtMemberString(member) });
2086 const ident = try r.peek(std.elf.EI.OSABI);
2087 if (!std.mem.eql(u8, ident[0..std.elf.MAGIC.len], std.elf.MAGIC)) return error.BadMagic;
2088 if (!std.mem.eql(u8, ident[std.elf.MAGIC.len..], elf.mf.memory_map.memory[std.elf.MAGIC.len..ident.len]))
2089 return diags.failParse(path, "bad ident", .{});
2090 try elf.symtab.ensureUnusedCapacity(gpa, 1);
3053 try elf.checkInputIdent(path, r);
3054 try elf.ensureUnusedSymbolCapacity(1, .all_local);
20913055 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 });
20923064 elf.inputs.addOneAssumeCapacity().* = .{
20933065 .path = path,
20943066 .member = if (member) |m| try gpa.dupe(u8, m) else null,
2095 .si = try elf.initSymbolAssumeCapacity(.{
2096 .name = std.fs.path.stem(member orelse path.sub_path),
2097 .type = .FILE,
2098 .shndx = .ABS,
2099 }),
3067 .file_symbol = file_symbol,
21003068 };
21013069 const target_endian = elf.targetEndian();
21023070 switch (elf.identClass()) {
......@@ -2108,17 +3076,17 @@ fn loadObject(
21083076 if (ehdr.machine != elf.ehdrField(.machine))
21093077 return diags.failParse(path, "bad machine", .{});
21103078 if (ehdr.shoff == 0 or ehdr.shnum <= 1) return;
2111 if (ehdr.shoff + ehdr.shentsize * ehdr.shnum > fl.size)
3079 if (ehdr.shoff + @as(u64, ehdr.shentsize) * @as(u64, ehdr.shnum) > fl.size)
21123080 return diags.failParse(path, "bad section header location", .{});
21133081 if (ehdr.shentsize < @sizeOf(ElfN.Shdr))
21143082 return diags.failParse(path, "unsupported shentsize", .{});
2115 const sections = try gpa.alloc(struct { shdr: ElfN.Shdr, si: Symbol.Index }, ehdr.shnum);
3083 const sections = try gpa.alloc(struct { shdr: ElfN.Shdr, isi: ?InputSection.Index }, ehdr.shnum);
21163084 defer gpa.free(sections);
21173085 try fr.seekTo(fl.offset + ehdr.shoff);
21183086 for (sections) |*section| {
21193087 section.* = .{
21203088 .shdr = try r.peekStruct(ElfN.Shdr, target_endian),
2121 .si = .null,
3089 .isi = null,
21223090 };
21233091 try r.discardAll(ehdr.shentsize);
21243092 switch (section.shdr.type) {
......@@ -2140,42 +3108,49 @@ fn loadObject(
21403108 };
21413109 defer gpa.free(shstrtab);
21423110 try elf.nodes.ensureUnusedCapacity(gpa, ehdr.shnum - 1);
2143 try elf.symtab.ensureUnusedCapacity(gpa, ehdr.shnum - 1);
21443111 try elf.input_sections.ensureUnusedCapacity(gpa, ehdr.shnum - 1);
21453112 for (sections[1..]) |*section| switch (section.shdr.type) {
21463113 else => {},
21473114 .PROGBITS, .NOBITS => {
21483115 if (section.shdr.name >= shstrtab.len) continue;
21493116 const name = std.mem.sliceTo(shstrtab[section.shdr.name..], 0);
2150 const parent_si = elf.namedSection(name) orelse continue;
2151 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, .{
21523127 .size = section.shdr.size,
21533128 .alignment = .fromByteUnits(std.math.ceilPowerOfTwoAssert(
21543129 usize,
21553130 @intCast(@max(section.shdr.addralign, 1)),
21563131 )),
2157 .moved = true,
3132 .moved = true, // see assert at end of `flushInputSection`
21583133 });
21593134 elf.nodes.appendAssumeCapacity(.{
21603135 .input_section = @enumFromInt(elf.input_sections.items.len),
21613136 });
2162 section.si = try elf.initSymbolAssumeCapacity(.{
2163 .type = .SECTION,
2164 .shndx = parent_si.shndx(elf),
2165 });
2166 section.si.get(elf).ni = ni;
3137 section.isi = @enumFromInt(elf.input_sections.items.len);
21673138 elf.input_sections.addOneAssumeCapacity().* = .{
2168 .ii = ii,
2169 .si = section.si,
3139 .input = input_index,
21703140 .file_location = .{
21713141 .offset = fl.offset + section.shdr.offset,
2172 .size = section.shdr.size,
3142 .size = if (section.shdr.type == .NOBITS) 0 else section.shdr.size,
21733143 },
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,
21743149 };
21753150 elf.synth_prog_node.increaseEstimatedTotalItems(1);
21763151 },
21773152 };
2178 var symmap: std.ArrayList(Symbol.Index) = .empty;
3153 var symmap: std.ArrayList(Symbol.Id) = .empty;
21793154 defer symmap.deinit(gpa);
21803155 for (sections[1..], 1..) |*symtab, symtab_shndx| switch (symtab.shdr.type) {
21813156 else => {},
......@@ -2206,105 +3181,132 @@ fn loadObject(
22063181 ), 1) catch continue;
22073182 symmap.clearRetainingCapacity();
22083183 try symmap.resize(gpa, symnum);
2209 try elf.symtab.ensureUnusedCapacity(gpa, symnum);
2210 try elf.globals.ensureUnusedCapacity(gpa, symnum);
3184 try elf.ensureUnusedSymbolCapacity(symnum, .maybe_global);
22113185 try fr.seekTo(fl.offset + symtab.shdr.offset + symtab.shdr.entsize);
22123186 for (symmap.items) |*si| {
22133187 si.* = .null;
22143188 const input_sym = try r.peekStruct(ElfN.Sym, target_endian);
22153189 try r.discardAll64(symtab.shdr.entsize);
2216 if (input_sym.name >= strtab.len or input_sym.shndx == std.elf.SHN_UNDEF or
2217 input_sym.shndx >= ehdr.shnum) continue;
2218 switch (input_sym.info.type) {
2219 .NOTYPE, .OBJECT, .FUNC => {},
2220 .SECTION => {
2221 const section = &sections[input_sym.shndx];
2222 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 };
22233220 continue;
22243221 },
2225 else => continue,
2226 }
2227 const name = std.mem.sliceTo(strtab[input_sym.name..], 0);
2228 const parent_si = sections[input_sym.shndx].si;
2229 si.* = try elf.initSymbolAssumeCapacity(.{
2230 .name = name,
2231 .value = input_sym.value,
2232 .size = input_sym.size,
2233 .type = input_sym.info.type,
2234 .bind = input_sym.info.bind,
2235 .visibility = input_sym.other.visibility,
2236 .shndx = parent_si.shndx(elf),
2237 });
2238 si.get(elf).ni = parent_si.get(elf).ni;
3222 };
3223
3224 const input_section_node = (sections[input_sym.shndx].isi orelse continue).node(elf);
3225
22393226 switch (input_sym.info.bind) {
2240 else => {},
2241 .GLOBAL => {
2242 const gop = elf.globals.getOrPutAssumeCapacity(elf.targetLoad(
2243 &@field(elf.symPtr(si.*), @tagName(class)).name,
2244 ));
2245 if (gop.found_existing) switch (elf.targetLoad(
2246 switch (elf.symPtr(gop.value_ptr.*)) {
2247 inline else => |sym| &sym.info,
2248 },
2249 ).bind) {
2250 else => unreachable,
2251 .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(
22523255 path,
22533256 "multiple definitions of '{s}'",
22543257 .{name},
22553258 ),
2256 .WEAK => {},
22573259 };
2258 gop.value_ptr.* = si.*;
2259 },
2260 .WEAK => {
2261 const gop = elf.globals.getOrPutAssumeCapacity(elf.targetLoad(
2262 &@field(elf.symPtr(si.*), @tagName(class)).name,
2263 ));
2264 if (!gop.found_existing) gop.value_ptr.* = si.*;
22653260 },
22663261 }
22673262 }
2268 for (sections[1..]) |*rels| switch (rels.shdr.type) {
3263 for (sections[1..]) |*rel_sec| switch (rel_sec.shdr.type) {
22693264 else => {},
22703265 inline .REL, .RELA => |sht| {
2271 if (rels.shdr.link != symtab_shndx or rels.shdr.info == std.elf.SHN_UNDEF or
2272 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;
22733268 const Rel = switch (sht) {
22743269 else => comptime unreachable,
22753270 .REL => ElfN.Rel,
22763271 .RELA => ElfN.Rela,
22773272 };
2278 if (rels.shdr.entsize < @sizeOf(Rel))
3273 if (rel_sec.shdr.entsize < @sizeOf(Rel))
22793274 return diags.failParse(path, "unsupported rel entsize", .{});
22803275
2281 const loc_sec = &sections[rels.shdr.info];
2282 if (loc_sec.si == .null) continue;
2283 const loc_sym = loc_sec.si.get(elf);
2284 assert(loc_sym.loc_relocs == .none);
2285 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);
22863279
22873280 const relnum = std.math.divExact(
22883281 u32,
2289 @intCast(rels.shdr.size),
2290 @intCast(rels.shdr.entsize),
3282 @intCast(rel_sec.shdr.size),
3283 @intCast(rel_sec.shdr.entsize),
22913284 ) catch return diags.failParse(
22923285 path,
22933286 "relocation section size (0x{x}) is not a multiple of entsize (0x{x})",
2294 .{ rels.shdr.size, rels.shdr.entsize },
3287 .{ rel_sec.shdr.size, rel_sec.shdr.entsize },
22953288 );
2296 try elf.ensureUnusedRelocCapacity(loc_sec.si, relnum);
2297 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);
22983291 for (0..relnum) |_| {
22993292 const rel = try r.peekStruct(Rel, target_endian);
2300 try r.discardAll64(rels.shdr.entsize);
2301 if (rel.info.sym == 0 or rel.info.sym > symnum) continue;
2302 const target_si = symmap.items[rel.info.sym - 1];
2303 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 );
23043306 elf.addRelocAssumeCapacity(
2305 loc_sec.si,
3307 loc_node,
23063308 rel.offset - loc_sec.shdr.addr,
2307 target_si,
3309 target,
23083310 rel.addend,
23093311 .wrap(rel.info.type, elf),
23103312 );
......@@ -2322,10 +3324,7 @@ fn loadDso(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) !void {
23223324 const r = &fr.interface;
23233325
23243326 log.debug("loadDso({f})", .{path.fmtEscapeString()});
2325 const ident = try r.peek(std.elf.EI.NIDENT);
2326 if (!std.mem.eql(u8, ident[0..std.elf.MAGIC.len], std.elf.MAGIC)) return error.BadMagic;
2327 if (!std.mem.eql(u8, ident[std.elf.MAGIC.len..], elf.mf.memory_map.memory[std.elf.MAGIC.len..ident.len]))
2328 return diags.failParse(path, "bad ident", .{});
3327 try elf.checkInputIdent(path, r);
23293328 const target_endian = elf.targetEndian();
23303329 switch (elf.identClass()) {
23313330 .NONE, _ => unreachable,
......@@ -2393,7 +3392,62 @@ fn loadDso(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) !void {
23933392}
23943393fn loadDsoExact(elf: *Elf, name: []const u8) !void {
23953394 log.debug("loadDsoExact({f})", .{std.zig.fmtString(name)});
2396 try elf.needed.put(elf.base.comp.gpa, try elf.string(.dynstr, name), {});
3395 if (elf.shndx.dynamic != .UNDEF) {
3396 try elf.needed.put(elf.base.comp.gpa, try elf.string(.dynstr, name), {});
3397 }
3398}
3399
3400/// Validates that the `std.elf.Ident` present at the start of `r` is a compatible link input.
3401///
3402/// Returns an error if it is incompatible, or if the ident is broken or missing.
3403///
3404/// Does not advance the position of `r`. Requires `r` to have a 16-byte buffer.
3405fn checkInputIdent(
3406 elf: *const Elf,
3407 path: std.Build.Cache.Path,
3408 r: *Io.Reader,
3409) !void {
3410 const diags = &elf.base.comp.link_diags;
3411
3412 const ident = try r.peekStructPointer(std.elf.Ident);
3413 const target: *const std.elf.Ident = @ptrCast(elf.mf.memory_map.memory[0..@sizeOf(std.elf.Ident)]);
3414
3415 if (!std.mem.eql(u8, &ident.magic, std.elf.MAGIC)) {
3416 return error.BadMagic;
3417 }
3418
3419 if (ident.class != target.class) return diags.failParse(
3420 path,
3421 "bad ELF class ({?s})",
3422 .{std.enums.tagName(std.elf.CLASS, ident.class)},
3423 );
3424 if (ident.data != target.data) return diags.failParse(
3425 path,
3426 "bad ELF data encoding ({?s})",
3427 .{std.enums.tagName(std.elf.DATA, ident.data)},
3428 );
3429 if (ident.version != target.version) return diags.failParse(
3430 path,
3431 "bad ELF version ({d})",
3432 .{ident.version},
3433 );
3434
3435 // OSABI is a bit more complex. On Linux, `.NONE` and `.GNU` are both valid and both common.
3436 // It sounds reasonable to allow the value we chose *and* allow `.NONE`.
3437 const expect_abiversion: u8 = abiver: {
3438 if (ident.osabi == .NONE) break :abiver 0;
3439 if (ident.osabi == target.osabi) break :abiver target.abiversion;
3440 return diags.failParse(
3441 path,
3442 "bad ELF OS/ABI ({?s})",
3443 .{std.enums.tagName(std.elf.OSABI, ident.osabi)},
3444 );
3445 };
3446 if (ident.abiversion != expect_abiversion) return diags.failParse(
3447 path,
3448 "bad ELF ABI version ({d})",
3449 .{ident.abiversion},
3450 );
23973451}
23983452
23993453pub fn prelink(elf: *Elf, prog_node: std.Progress.Node) !void {
......@@ -2406,20 +3460,27 @@ pub fn prelink(elf: *Elf, prog_node: std.Progress.Node) !void {
24063460fn prelinkInner(elf: *Elf) !void {
24073461 const comp = elf.base.comp;
24083462 const gpa = comp.gpa;
2409 try elf.symtab.ensureUnusedCapacity(gpa, 1);
3463 try elf.ensureUnusedSymbolCapacity(1, .all_local);
24103464 try elf.inputs.ensureUnusedCapacity(gpa, 1);
24113465 const zcu_name = try std.fmt.allocPrint(gpa, "{s}_zcu", .{
24123466 std.fs.path.stem(elf.base.emit.sub_path),
24133467 });
24143468 defer gpa.free(zcu_name);
2415 const si = try elf.initSymbolAssumeCapacity(.{ .name = zcu_name, .type = .FILE, .shndx = .ABS });
3469 const zcu_file_symbol = elf.addLocalSymbolAssumeCapacity(.{
3470 .node = .none,
3471 .name = try elf.string(.strtab, zcu_name),
3472 .value = 0,
3473 .size = 0,
3474 .type = .FILE,
3475 .shndx = .ABS,
3476 });
24163477 elf.inputs.addOneAssumeCapacity().* = .{
24173478 .path = elf.base.emit,
24183479 .member = null,
2419 .si = si,
3480 .file_symbol = zcu_file_symbol,
24203481 };
24213482
2422 if (elf.si.dynamic != .null) switch (elf.identClass()) {
3483 if (elf.shndx.dynamic != .UNDEF) switch (elf.identClass()) {
24233484 .NONE, _ => unreachable,
24243485 inline else => |ct_class| {
24253486 const ElfN = ct_class.ElfN();
......@@ -2430,9 +3491,9 @@ fn prelinkInner(elf: *Elf) !void {
24303491 @intFromBool(flags != 0) + @intFromBool(flags_1 != 0) +
24313492 @intFromBool(comp.config.output_mode == .Exe) + 12;
24323493 const dynamic_size: u32 = @intCast(@sizeOf(ElfN.Addr) * 2 * dynamic_len);
2433 const dynamic_ni = elf.si.dynamic.node(elf);
3494 const dynamic_ni = elf.shndx.dynamic.get(elf).ni;
24343495 try dynamic_ni.resize(&elf.mf, gpa, dynamic_size);
2435 switch (elf.shdrPtr(elf.si.dynamic.shndx(elf))) {
3496 switch (elf.shdrPtr(elf.shndx.dynamic)) {
24363497 inline else => |shdr| elf.targetStore(&shdr.size, dynamic_size),
24373498 }
24383499 const sec_dynamic = dynamic_ni.slice(&elf.mf);
......@@ -2441,10 +3502,10 @@ fn prelinkInner(elf: *Elf) !void {
24413502 for (
24423503 dynamic_entries[dynamic_index..][0..needed_len],
24433504 elf.needed.keys(),
2444 ) |*dynamic_entry, needed| dynamic_entry.* = .{ std.elf.DT_NEEDED, needed };
3505 ) |*dynamic_entry, needed| dynamic_entry.* = .{ std.elf.DT_NEEDED, @intFromEnum(needed) };
24453506 dynamic_index += needed_len;
24463507 if (elf.options.soname) |soname| {
2447 dynamic_entries[dynamic_index] = .{ std.elf.DT_SONAME, try elf.string(.dynstr, soname) };
3508 dynamic_entries[dynamic_index] = .{ std.elf.DT_SONAME, @intFromEnum(try elf.string(.dynstr, soname)) };
24483509 dynamic_index += 1;
24493510 }
24503511 if (flags != 0) {
......@@ -2459,25 +3520,25 @@ fn prelinkInner(elf: *Elf) !void {
24593520 dynamic_entries[dynamic_index] = .{ std.elf.DT_DEBUG, 0 };
24603521 dynamic_index += 1;
24613522 }
2462 const rela_dyn_si = elf.si.got.shndx(elf).get(elf).rela_si;
2463 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;
24643525 dynamic_entries[dynamic_index..][0..12].* = .{
2465 .{ std.elf.DT_RELA, @intCast(elf.computeNodeVAddr(rela_dyn_si.node(elf))) },
3526 .{ std.elf.DT_RELA, @intCast(elf.computeNodeVAddr(rela_dyn_shndx.get(elf).ni)) },
24663527 .{ std.elf.DT_RELASZ, elf.targetLoad(
2467 &@field(elf.shdrPtr(rela_dyn_si.shndx(elf)), @tagName(ct_class)).size,
3528 &@field(elf.shdrPtr(rela_dyn_shndx), @tagName(ct_class)).size,
24683529 ) },
24693530 .{ std.elf.DT_RELAENT, @sizeOf(ElfN.Rela) },
2470 .{ std.elf.DT_JMPREL, @intCast(elf.computeNodeVAddr(rela_plt_si.node(elf))) },
3531 .{ std.elf.DT_JMPREL, @intCast(elf.computeNodeVAddr(rela_plt_shndx.get(elf).ni)) },
24713532 .{ std.elf.DT_PLTRELSZ, elf.targetLoad(
2472 &@field(elf.shdrPtr(rela_plt_si.shndx(elf)), @tagName(ct_class)).size,
3533 &@field(elf.shdrPtr(rela_plt_shndx), @tagName(ct_class)).size,
24733534 ) },
2474 .{ std.elf.DT_PLTGOT, @intCast(elf.computeNodeVAddr(elf.si.got_plt.node(elf))) },
3535 .{ std.elf.DT_PLTGOT, @intCast(elf.computeNodeVAddr(elf.shndx.got_plt.get(elf).ni)) },
24753536 .{ std.elf.DT_PLTREL, std.elf.DT_RELA },
2476 .{ std.elf.DT_SYMTAB, @intCast(elf.computeNodeVAddr(elf.si.dynsym.node(elf))) },
3537 .{ std.elf.DT_SYMTAB, @intCast(elf.computeNodeVAddr(elf.shndx.dynsym.get(elf).ni)) },
24773538 .{ std.elf.DT_SYMENT, @sizeOf(ElfN.Sym) },
2478 .{ std.elf.DT_STRTAB, @intCast(elf.computeNodeVAddr(elf.si.dynstr.node(elf))) },
3539 .{ std.elf.DT_STRTAB, @intCast(elf.computeNodeVAddr(elf.shndx.dynstr.get(elf).ni)) },
24793540 .{ std.elf.DT_STRSZ, elf.targetLoad(
2480 &@field(elf.shdrPtr(elf.si.dynstr.shndx(elf)), @tagName(ct_class)).size,
3541 &@field(elf.shdrPtr(elf.shndx.dynstr), @tagName(ct_class)).size,
24813542 ) },
24823543 .{ std.elf.DT_NULL, 0 },
24833544 };
......@@ -2486,42 +3547,40 @@ fn prelinkInner(elf: *Elf) !void {
24863547 if (elf.targetEndian() != native_endian) for (dynamic_entries) |*dynamic_entry|
24873548 std.mem.byteSwapAllFields(@TypeOf(dynamic_entry.*), dynamic_entry);
24883549
2489 const dynamic_sym = elf.si.dynamic.get(elf);
2490 assert(dynamic_sym.loc_relocs == .none);
2491 dynamic_sym.loc_relocs = @enumFromInt(elf.relocs.items.len);
2492 try elf.ensureUnusedRelocCapacity(elf.si.dynamic, 5);
3550 elf.first_dynamic_reloc = @enumFromInt(elf.relocs.items.len);
3551 try elf.ensureUnusedRelocCapacity(dynamic_ni, 5);
24933552 elf.addRelocAssumeCapacity(
2494 elf.si.dynamic,
3553 dynamic_ni,
24953554 @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 12) + 1),
2496 rela_dyn_si,
3555 .local(rela_dyn_shndx.get(elf).lsi),
24973556 0,
24983557 .absAddr(elf),
24993558 );
25003559 elf.addRelocAssumeCapacity(
2501 elf.si.dynamic,
3560 dynamic_ni,
25023561 @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 9) + 1),
2503 rela_plt_si,
3562 .local(rela_plt_shndx.get(elf).lsi),
25043563 0,
25053564 .absAddr(elf),
25063565 );
25073566 elf.addRelocAssumeCapacity(
2508 elf.si.dynamic,
3567 dynamic_ni,
25093568 @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 7) + 1),
2510 elf.si.got_plt,
3569 .local(elf.shndx.got_plt.get(elf).lsi),
25113570 0,
25123571 .absAddr(elf),
25133572 );
25143573 elf.addRelocAssumeCapacity(
2515 elf.si.dynamic,
3574 dynamic_ni,
25163575 @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 5) + 1),
2517 elf.si.dynsym,
3576 .local(elf.shndx.dynsym.get(elf).lsi),
25183577 0,
25193578 .absAddr(elf),
25203579 );
25213580 elf.addRelocAssumeCapacity(
2522 elf.si.dynamic,
3581 dynamic_ni,
25233582 @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 3) + 1),
2524 elf.si.dynstr,
3583 .local(elf.shndx.dynstr.get(elf).lsi),
25253584 0,
25263585 .absAddr(elf),
25273586 );
......@@ -2529,36 +3588,6 @@ fn prelinkInner(elf: *Elf) !void {
25293588 };
25303589}
25313590
2532pub fn getNavVAddr(
2533 elf: *Elf,
2534 pt: Zcu.PerThread,
2535 nav: InternPool.Nav.Index,
2536 reloc_info: link.File.RelocInfo,
2537) !u64 {
2538 return elf.getVAddr(reloc_info, try elf.navSymbol(pt.zcu, nav));
2539}
2540
2541pub fn getUavVAddr(
2542 elf: *Elf,
2543 uav: InternPool.Index,
2544 reloc_info: link.File.RelocInfo,
2545) !u64 {
2546 return elf.getVAddr(reloc_info, try elf.uavSymbol(uav));
2547}
2548
2549pub fn getVAddr(elf: *Elf, reloc_info: link.File.RelocInfo, target_si: Symbol.Index) !u64 {
2550 try elf.addReloc(
2551 @enumFromInt(reloc_info.parent.atom_index),
2552 reloc_info.offset,
2553 target_si,
2554 reloc_info.addend,
2555 .absAddr(elf),
2556 );
2557 return switch (elf.symPtr(target_si)) {
2558 inline else => |sym| elf.targetLoad(&sym.value),
2559 };
2560}
2561
25623591fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
25633592 name: []const u8 = "",
25643593 type: std.elf.SHT = .NULL,
......@@ -2570,19 +3599,22 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
25703599 entsize: std.elf.Word = 0,
25713600 node_align: std.mem.Alignment = .@"1",
25723601 fixed: bool = false,
2573}) !Symbol.Index {
3602}) !Section.Index {
25743603 switch (opts.type) {
25753604 .NULL => assert(opts.size == 0),
25763605 .PROGBITS => assert(opts.size > 0),
25773606 else => {},
25783607 }
3608 if (opts.flags.ALLOC and elf.ehdrField(.type) != .REL) {
3609 assert(elf.getNode(segment_ni) == .segment);
3610 }
25793611 const gpa = elf.base.comp.gpa;
25803612 try elf.nodes.ensureUnusedCapacity(gpa, 1);
25813613 try elf.shdrs.ensureUnusedCapacity(gpa, 1);
2582 try elf.symtab.ensureUnusedCapacity(gpa, 1);
3614 if (opts.flags.ALLOC) try elf.ensureUnusedSymbolCapacity(1, .all_local);
25833615
25843616 const shstrtab_entry = try elf.string(.shstrtab, opts.name);
2585 const shndx: Symbol.Index.Shndx, const new_shdr_size = shndx: switch (elf.ehdrPtr()) {
3617 const shndx: Section.Index, const new_shdr_size = shndx: switch (elf.ehdrPtr()) {
25863618 inline else => |ehdr, class| {
25873619 const shndx, const shnum = alloc_shndx: switch (elf.targetLoad(&ehdr.shnum)) {
25883620 1...std.elf.SHN_LORESERVE - 2 => |shndx| {
......@@ -2605,8 +3637,8 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
26053637 break :alloc_shndx .{ shndx, shnum };
26063638 },
26073639 };
2608 assert(shndx < @intFromEnum(Symbol.Index.Shndx.LORESERVE));
2609 break :shndx .{ @enumFromInt(shndx), elf.targetLoad(&ehdr.shentsize) * shnum };
3640 assert(shndx < @intFromEnum(Section.Index.LORESERVE));
3641 break :shndx .{ @enumFromInt(shndx), @as(u64, elf.targetLoad(&ehdr.shentsize)) * @as(u64, shnum) };
26103642 },
26113643 };
26123644 _, const shdr_node_size = elf.ni.shdr.location(&elf.mf).resolve(&elf.mf);
......@@ -2622,17 +3654,22 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
26223654 .fixed = opts.fixed,
26233655 .resized = opts.size > 0,
26243656 });
2625 const si = elf.addSymbolAssumeCapacity();
2626 elf.nodes.appendAssumeCapacity(.{ .section = si });
2627 elf.shdrs.appendAssumeCapacity(.{ .si = si, .rela_si = .null, .rela_free = .none });
2628 si.get(elf).ni = ni;
26293657 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 });
26303668 const offset = ni.fileLocation(&elf.mf, false).offset;
2631 try si.init(elf, .{ .value = addr, .type = .SECTION, .shndx = shndx });
26323669 switch (elf.shdrPtr(shndx)) {
26333670 inline else => |shdr, class| {
26343671 shdr.* = .{
2635 .name = shstrtab_entry,
3672 .name = @intFromEnum(shstrtab_entry),
26363673 .type = opts.type,
26373674 .flags = .{ .shf = opts.flags },
26383675 .addr = @intCast(addr),
......@@ -2646,63 +3683,31 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
26463683 if (elf.targetEndian() != native_endian) std.mem.byteSwapAllFields(class.ElfN().Shdr, shdr);
26473684 },
26483685 }
2649 return si;
2650}
2651
2652fn renameSection(elf: *Elf, si: Symbol.Index, name: []const u8) !void {
2653 const shstrtab_entry = try elf.string(.shstrtab, name);
2654 switch (elf.shdrPtr(si.shndx(elf))) {
2655 inline else => |shdr| elf.targetStore(&shdr.name, shstrtab_entry),
2656 }
2657}
2658
2659fn sectionName(elf: *Elf, si: Symbol.Index) [:0]const u8 {
2660 const name = elf.si.shstrtab.node(elf).slice(&elf.mf)[switch (elf.shdrPtr(si.shndx(elf))) {
2661 inline else => |shdr| elf.targetLoad(&shdr.name),
2662 }..];
2663 return name[0..std.mem.indexOfScalar(u8, name, 0).? :0];
2664}
2665
2666fn string(elf: *Elf, comptime section: enum { shstrtab, strtab, dynstr }, key: []const u8) !u32 {
2667 if (key.len == 0) return 0;
2668 return @field(elf, @tagName(section)).get(elf, @field(elf.si, @tagName(section)), key);
3686 return shndx;
26693687}
26703688
2671pub fn addReloc(
2672 elf: *Elf,
2673 loc_si: Symbol.Index,
2674 offset: u64,
2675 target_si: Symbol.Index,
2676 addend: i64,
2677 @"type": Reloc.Type,
2678) !void {
2679 try elf.ensureUnusedRelocCapacity(loc_si, 1);
2680 elf.addRelocAssumeCapacity(loc_si, offset, target_si, addend, @"type");
2681}
2682pub fn ensureUnusedRelocCapacity(elf: *Elf, loc_si: Symbol.Index, len: usize) !void {
3689fn ensureUnusedRelocCapacity(elf: *Elf, node: MappedFile.Node.Index, len: usize) !void {
26833690 if (len == 0) return;
26843691 const gpa = elf.base.comp.gpa;
26853692 try elf.relocs.ensureUnusedCapacity(gpa, len);
26863693 const class = elf.identClass();
2687 const rela_si, const rela_len = rela: switch (elf.ehdrField(.type)) {
3694 const rela_shndx, const rela_len = rela: switch (elf.ehdrField(.type)) {
26883695 .NONE, .CORE, _ => unreachable,
26893696 .REL => {
2690 const shndx = loc_si.shndx(elf);
2691 const sh = shndx.get(elf);
2692 if (sh.rela_si == .null) {
3697 const shndx = elf.getNodeShndx(node);
3698 if (shndx.get(elf).rela_shndx == .UNDEF) {
26933699 var bfa_buf: [32]u8 = undefined;
26943700 var bfa: std.heap.BufferFirstAllocator = .init(&bfa_buf, gpa);
26953701 const allocator = bfa.allocator();
26963702
2697 const rela_name =
2698 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)});
26993704 defer allocator.free(rela_name);
27003705
2701 sh.rela_si = try elf.addSection(.none, .{
3706 const rela_shndx = try elf.addSection(.none, .{
27023707 .name = rela_name,
27033708 .type = .RELA,
2704 .link = @intFromEnum(elf.si.symtab.shndx(elf)),
2705 .info = @intFromEnum(shndx),
3709 .link = @intFromEnum(Section.Index.symtab),
3710 .info = shndx.toSection().?,
27063711 .addralign = switch (class) {
27073712 .NONE, _ => unreachable,
27083713 .@"32" => .@"4",
......@@ -2714,14 +3719,15 @@ pub fn ensureUnusedRelocCapacity(elf: *Elf, loc_si: Symbol.Index, len: usize) !v
27143719 },
27153720 .node_align = elf.mf.flags.block_size,
27163721 });
3722 shndx.get(elf).rela_shndx = rela_shndx;
27173723 }
2718 break :rela .{ sh.rela_si, len };
3724 break :rela .{ shndx.get(elf).rela_shndx, len };
27193725 },
27203726 .EXEC, .DYN => switch (elf.got.tlsld) {
27213727 _ => return,
2722 .none => if (elf.si.dynamic != .null) {
3728 .none => if (elf.shndx.dynamic != .UNDEF) {
27233729 try elf.mf.updates.ensureUnusedCapacity(gpa, 1);
2724 const got_ni = elf.si.got.node(elf);
3730 const got_ni = elf.shndx.got.get(elf).ni;
27253731 _, const got_node_size = got_ni.location(&elf.mf).resolve(&elf.mf);
27263732 const got_size = switch (class) {
27273733 .NONE, _ => unreachable,
......@@ -2729,43 +3735,52 @@ pub fn ensureUnusedRelocCapacity(elf: *Elf, loc_si: Symbol.Index, len: usize) !v
27293735 };
27303736 if (got_size > got_node_size)
27313737 try got_ni.resize(&elf.mf, gpa, got_size +| got_size / MappedFile.growth_factor);
2732 break :rela .{ elf.si.got.shndx(elf).get(elf).rela_si, 1 };
3738 break :rela .{ elf.shndx.got.get(elf).rela_shndx, 1 };
27333739 } else return,
27343740 },
27353741 };
2736 const rela_ni = rela_si.node(elf);
3742 const rela_ni = rela_shndx.get(elf).ni;
27373743 _, const rela_node_size = rela_ni.location(&elf.mf).resolve(&elf.mf);
2738 const rela_size = switch (elf.shdrPtr(rela_si.shndx(elf))) {
3744 const rela_size = switch (elf.shdrPtr(rela_shndx)) {
27393745 inline else => |shdr| elf.targetLoad(&shdr.size) + elf.targetLoad(&shdr.entsize) * rela_len,
27403746 };
27413747 if (rela_size > rela_node_size)
27423748 try rela_ni.resize(&elf.mf, gpa, rela_size +| rela_size / MappedFile.growth_factor);
27433749}
2744pub fn addRelocAssumeCapacity(
3750fn addRelocAssumeCapacity(
27453751 elf: *Elf,
2746 loc_si: Symbol.Index,
3752 node: MappedFile.Node.Index,
27473753 offset: u64,
2748 target_si: Symbol.Index,
3754 target: Symbol.Id,
27493755 addend: i64,
27503756 @"type": Reloc.Type,
27513757) void {
2752 const target = target_si.get(elf);
3758 assert(node != .none);
27533759 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 }
27543769 elf.relocs.addOneAssumeCapacity().* = .{
27553770 .type = @"type",
27563771 .prev = .none,
2757 .next = target.target_relocs,
2758 .loc = loc_si,
2759 .target = target_si,
3772 .next = next,
3773 .node = node,
3774 .target = target,
27603775 .index = index: switch (elf.ehdrField(.type)) {
27613776 .NONE, .CORE, _ => unreachable,
27623777 .REL => {
2763 const sh = loc_si.shndx(elf).get(elf);
2764 switch (elf.shdrPtr(sh.rela_si.shndx(elf))) {
3778 const sh = elf.getNodeShndx(node).get(elf);
3779 switch (elf.shdrPtr(sh.rela_shndx)) {
27653780 inline else => |shdr, class| {
27663781 const Rela = class.ElfN().Rela;
27673782 const ent_size = elf.targetLoad(&shdr.entsize);
2768 const rela_slice = sh.rela_si.node(elf).slice(&elf.mf);
3783 const rela_slice = sh.rela_shndx.get(elf).ni.slice(&elf.mf);
27693784 const index: u32 = if (sh.rela_free.unwrap()) |index| alloc_index: {
27703785 const rela: *Rela = @ptrCast(@alignCast(
27713786 rela_slice[@intCast(ent_size * index)..][0..@intCast(ent_size)],
......@@ -2781,11 +3796,15 @@ pub fn addRelocAssumeCapacity(
27813796 const rela: *Rela = @ptrCast(@alignCast(
27823797 rela_slice[@intCast(ent_size * index)..][0..@intCast(ent_size)],
27833798 ));
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.
27843803 rela.* = .{
2785 .offset = @intCast(offset),
3804 .offset = 0,
27863805 .info = .{
27873806 .type = @intCast(@"type".unwrap(elf)),
2788 .sym = @intCast(@intFromEnum(target_si)),
3807 .sym = @intCast(@intFromEnum(target.index(elf))),
27893808 },
27903809 .addend = @intCast(addend),
27913810 };
......@@ -2802,25 +3821,25 @@ pub fn addRelocAssumeCapacity(
28023821 else => {},
28033822 .TLSLD => switch (elf.got.tlsld) {
28043823 _ => {},
2805 .none => if (elf.si.dynamic != .null) {
3824 .none => if (elf.shndx.dynamic != .UNDEF) {
28063825 const tlsld_index = elf.got.len;
28073826 elf.got.tlsld = .wrap(tlsld_index);
28083827 elf.got.len = tlsld_index + 2;
2809 const got_addr = got_addr: switch (elf.shdrPtr(elf.si.got.shndx(elf))) {
3828 const got_addr = got_addr: switch (elf.shdrPtr(elf.shndx.got)) {
28103829 inline else => |shdr, class| {
28113830 const addr_size = @sizeOf(class.ElfN().Addr);
28123831 const old_size = addr_size * tlsld_index;
28133832 const new_size = old_size + addr_size * 2;
28143833 @memset(
2815 elf.si.got.node(elf).slice(&elf.mf)[old_size..new_size],
3834 elf.shndx.got.get(elf).ni.slice(&elf.mf)[old_size..new_size],
28163835 0,
28173836 );
28183837 break :got_addr elf.targetLoad(&shdr.addr) + old_size;
28193838 },
28203839 };
2821 const rela_dyn_si = elf.si.got.shndx(elf).get(elf).rela_si;
2822 const rela_dyn_ni = rela_dyn_si.node(elf);
2823 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)) {
28243843 inline else => |shdr, class| {
28253844 const Rela = class.ElfN().Rela;
28263845 const old_size = elf.targetLoad(&shdr.size);
......@@ -2851,11 +3870,6 @@ pub fn addRelocAssumeCapacity(
28513870 .offset = offset,
28523871 .addend = addend,
28533872 };
2854 switch (target.target_relocs) {
2855 .none => {},
2856 else => |target_ri| target_ri.get(elf).prev = ri,
2857 }
2858 target.target_relocs = ri;
28593873}
28603874
28613875pub fn updateNav(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !void {
......@@ -2877,30 +3891,12 @@ fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index)
28773891 if (!Type.fromInterned(nav.resolved.?.type).hasRuntimeBits(zcu)) return;
28783892
28793893 const nmi = try elf.navMapIndex(zcu, nav_index);
2880 const si = nmi.symbol(elf);
2881 const ni = ni: {
2882 const sym = si.get(elf);
2883 switch (sym.ni) {
2884 .none => {
2885 try elf.nodes.ensureUnusedCapacity(gpa, 1);
2886 const sec_si = elf.navSection(ip, nav.resolved.?);
2887 const ni = try elf.mf.addLastChildNode(gpa, sec_si.node(elf), .{
2888 .alignment = zcu.navAlignment(nav_index).toStdMem(),
2889 .moved = true,
2890 });
2891 elf.nodes.appendAssumeCapacity(.{ .nav = nmi });
2892 sym.ni = ni;
2893 switch (elf.symPtr(si)) {
2894 inline else => |sym_ptr, class| sym_ptr.shndx =
2895 @field(elf.symPtr(sec_si), @tagName(class)).shndx,
2896 }
2897 },
2898 else => si.deleteLocationRelocs(elf),
2899 }
2900 assert(sym.loc_relocs == .none);
2901 sym.loc_relocs = @enumFromInt(elf.relocs.items.len);
2902 break :ni sym.ni;
2903 };
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);
29043900
29053901 var nw: MappedFile.Node.Writer = undefined;
29063902 ni.writer(&elf.mf, gpa, &nw);
......@@ -2911,54 +3907,14 @@ fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index)
29113907 zcu.navSrcLoc(nav_index),
29123908 .fromInterned(nav.resolved.?.value),
29133909 &nw.interface,
2914 .{ .atom_index = @intFromEnum(si) },
3910 .{ .atom_index = Node.toAtom(ni) },
29153911 ) catch |err| switch (err) {
29163912 error.WriteFailed => return error.OutOfMemory,
29173913 else => |e| return e,
29183914 };
2919 switch (elf.symPtr(si)) {
3915 switch (elf.symPtr(nmi.symbol(elf).index())) {
29203916 inline else => |sym| elf.targetStore(&sym.size, @intCast(nw.interface.end)),
29213917 }
2922 si.applyLocationRelocs(elf);
2923}
2924
2925pub fn lowerUav(
2926 elf: *Elf,
2927 pt: Zcu.PerThread,
2928 uav_val: InternPool.Index,
2929 uav_align: InternPool.Alignment,
2930 src_loc: Zcu.LazySrcLoc,
2931) !codegen.SymbolResult {
2932 const zcu = pt.zcu;
2933 const gpa = zcu.gpa;
2934
2935 try elf.pending_uavs.ensureUnusedCapacity(gpa, 1);
2936 const umi = elf.uavMapIndex(uav_val) catch |err| switch (err) {
2937 error.OutOfMemory => |e| return e,
2938 else => |e| return .{ .fail = try Zcu.ErrorMsg.create(
2939 gpa,
2940 src_loc,
2941 "linker failed to update constant: {s}",
2942 .{@errorName(e)},
2943 ) },
2944 };
2945 const si = umi.symbol(elf);
2946 if (switch (si.get(elf).ni) {
2947 .none => true,
2948 else => |ni| uav_align.toStdMem().order(ni.alignment(&elf.mf)).compare(.gt),
2949 }) {
2950 const gop = elf.pending_uavs.getOrPutAssumeCapacity(umi);
2951 if (gop.found_existing) {
2952 gop.value_ptr.alignment = gop.value_ptr.alignment.max(uav_align);
2953 } else {
2954 gop.value_ptr.* = .{
2955 .alignment = uav_align,
2956 .src_loc = src_loc,
2957 };
2958 elf.const_prog_node.increaseEstimatedTotalItems(1);
2959 }
2960 }
2961 return .{ .sym_index = @intFromEnum(si) };
29623918}
29633919
29643920pub fn updateFunc(
......@@ -2993,42 +3949,13 @@ fn updateFuncInner(
29933949 const nav = ip.getNav(func.owner_nav);
29943950
29953951 const nmi = try elf.navMapIndex(zcu, func.owner_nav);
2996 const si = nmi.symbol(elf);
2997 log.debug("updateFunc({f}) = {d}", .{ nav.fqn.fmt(ip), si });
2998 const ni = ni: {
2999 const sym = si.get(elf);
3000 switch (sym.ni) {
3001 .none => {
3002 try elf.nodes.ensureUnusedCapacity(gpa, 1);
3003 const sec_si = elf.navSection(ip, nav.resolved.?);
3004 const mod = zcu.navFileScope(func.owner_nav).mod.?;
3005 const target = &mod.resolved_target.result;
3006 const ni = try elf.mf.addLastChildNode(gpa, sec_si.node(elf), .{
3007 .alignment = switch (nav.resolved.?.@"align") {
3008 .none => switch (mod.optimize_mode) {
3009 .Debug,
3010 .ReleaseSafe,
3011 .ReleaseFast,
3012 => target_util.defaultFunctionAlignment(target),
3013 .ReleaseSmall => target_util.minFunctionAlignment(target),
3014 },
3015 else => |a| a.maxStrict(target_util.minFunctionAlignment(target)),
3016 }.toStdMem(),
3017 .moved = true,
3018 });
3019 elf.nodes.appendAssumeCapacity(.{ .nav = nmi });
3020 sym.ni = ni;
3021 switch (elf.symPtr(si)) {
3022 inline else => |sym_ptr, class| sym_ptr.shndx =
3023 @field(elf.symPtr(sec_si), @tagName(class)).shndx,
3024 }
3025 },
3026 else => si.deleteLocationRelocs(elf),
3027 }
3028 assert(sym.loc_relocs == .none);
3029 sym.loc_relocs = @enumFromInt(elf.relocs.items.len);
3030 break :ni sym.ni;
3031 };
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);
30323959
30333960 var nw: MappedFile.Node.Writer = undefined;
30343961 ni.writer(&elf.mf, gpa, &nw);
......@@ -3038,7 +3965,7 @@ fn updateFuncInner(
30383965 pt,
30393966 zcu.navSrcLoc(func.owner_nav),
30403967 func_index,
3041 @intFromEnum(si),
3968 Node.toAtom(ni),
30423969 mir,
30433970 &nw.interface,
30443971 .none,
......@@ -3046,10 +3973,9 @@ fn updateFuncInner(
30463973 error.WriteFailed => return nw.err.?,
30473974 else => |e| return e,
30483975 };
3049 switch (elf.symPtr(si)) {
3976 switch (elf.symPtr(nmi.symbol(elf).index())) {
30503977 inline else => |sym| elf.targetStore(&sym.size, @intCast(nw.interface.end)),
30513978 }
3052 si.applyLocationRelocs(elf);
30533979}
30543980
30553981pub fn updateErrorData(elf: *Elf, pt: Zcu.PerThread) !void {
......@@ -3072,7 +3998,42 @@ pub fn flush(
30723998 const comp = elf.base.comp;
30733999 _ = arena;
30744000 _ = 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
30754012 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
30764037 elf.mf.flush() catch |err| switch (err) {
30774038 error.Canceled => |e| return e,
30784039 else => |e| return comp.link_diags.fail("flush write failed: {t}", .{e}),
......@@ -3082,15 +4043,10 @@ pub fn flush(
30824043pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool {
30834044 const comp = elf.base.comp;
30844045 task: {
3085 while (elf.pending_uavs.pop()) |pending_uav| {
3086 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 });
30874048 defer sub_prog_node.end();
3088 elf.flushUav(
3089 .{ .zcu = comp.zcu.?, .tid = tid },
3090 pending_uav.key,
3091 pending_uav.value.alignment,
3092 pending_uav.value.src_loc,
3093 ) catch |err| switch (err) {
4049 elf.flushUav(.{ .zcu = comp.zcu.?, .tid = tid }, umi) catch |err| switch (err) {
30944050 error.OutOfMemory => |e| return e,
30954051 else => |e| return comp.link_diags.fail(
30964052 "linker failed to lower constant: {t}",
......@@ -3127,9 +4083,9 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool {
31274083 break :task;
31284084 };
31294085 if (elf.input_section_pending_index < elf.input_sections.items.len) {
3130 const isi: Node.InputSectionIndex = @enumFromInt(elf.input_section_pending_index);
4086 const isi: InputSection.Index = @enumFromInt(elf.input_section_pending_index);
31314087 elf.input_section_pending_index += 1;
3132 const sub_prog_node = elf.idleProgNode(tid, elf.input_prog_node, elf.getNode(isi.symbol(elf).node(elf)));
4088 const sub_prog_node = elf.idleProgNode(tid, elf.input_prog_node, elf.getNode(isi.node(elf)));
31334089 defer sub_prog_node.end();
31344090 elf.flushInputSection(isi) catch |err| switch (err) {
31354091 else => |e| {
......@@ -3137,9 +4093,7 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool {
31374093 return comp.link_diags.fail(
31384094 "linker failed to read input section '{s}' from \"{f}{f}\": {t}",
31394095 .{
3140 elf.sectionName(
3141 elf.getNode(isi.symbol(elf).node(elf).parent(&elf.mf)).section,
3142 ),
4096 elf.getNode(isi.node(elf).parent(&elf.mf)).section.name(elf),
31434097 ii.path(elf).fmtEscapeString(),
31444098 fmtMemberString(ii.member(elf)),
31454099 e,
......@@ -3149,6 +4103,20 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool {
31494103 };
31504104 break :task;
31514105 }
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 }
31524120 while (elf.mf.updates.pop()) |ni| {
31534121 const clean_moved = ni.cleanMoved(&elf.mf);
31544122 const clean_resized = ni.cleanResized(&elf.mf);
......@@ -3161,9 +4129,10 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool {
31614129 } else elf.mf.update_prog_node.completeOne();
31624130 }
31634131 }
3164 if (elf.pending_uavs.count() > 0) return true;
4132 if (elf.pending_uavs.items.len > 0) return true;
31654133 for (&elf.lazy.values) |lazy| if (lazy.map.count() > lazy.pending_index) return true;
31664134 if (elf.input_sections.items.len > elf.input_section_pending_index) return true;
4135 if (elf.changed_symtab_index.count() > 0) return true;
31674136 if (elf.mf.updates.items.len > 0) return true;
31684137 return false;
31694138}
......@@ -3177,13 +4146,13 @@ fn idleProgNode(
31774146 var name: [std.Progress.Node.max_name_len]u8 = undefined;
31784147 return prog_node.start(name: switch (node) {
31794148 else => |tag| @tagName(tag),
3180 .section => |si| elf.sectionName(si),
4149 .section => |shndx| shndx.name(elf),
31814150 .input_section => |isi| {
31824151 const ii = isi.input(elf);
31834152 break :name std.fmt.bufPrint(&name, "{f}{f} {s}", .{
31844153 ii.path(elf).fmtEscapeString(),
31854154 fmtMemberString(ii.member(elf)),
3186 elf.sectionName(elf.getNode(isi.symbol(elf).node(elf).parent(&elf.mf)).section),
4155 elf.getNode(isi.node(elf).parent(&elf.mf)).section.name(elf),
31874156 }) catch &name;
31884157 },
31894158 .nav => |nmi| {
......@@ -3200,59 +4169,43 @@ fn flushUav(
32004169 elf: *Elf,
32014170 pt: Zcu.PerThread,
32024171 umi: Node.UavMapIndex,
3203 uav_align: InternPool.Alignment,
3204 src_loc: Zcu.LazySrcLoc,
32054172) !void {
4173 const comp = elf.base.comp;
4174 const gpa = comp.gpa;
32064175 const zcu = pt.zcu;
3207 const gpa = zcu.gpa;
32084176
32094177 const uav_val = umi.uavValue(elf);
3210 const si = umi.symbol(elf);
3211 const ni = ni: {
3212 const sym = si.get(elf);
3213 switch (sym.ni) {
3214 .none => {
3215 try elf.nodes.ensureUnusedCapacity(gpa, 1);
3216 const sec_si = elf.si.data;
3217 const ni = try elf.mf.addLastChildNode(gpa, sec_si.node(elf), .{
3218 .alignment = uav_align.toStdMem(),
3219 .moved = true,
3220 });
3221 elf.nodes.appendAssumeCapacity(.{ .uav = umi });
3222 sym.ni = ni;
3223 switch (elf.symPtr(si)) {
3224 inline else => |sym_ptr, class| sym_ptr.shndx =
3225 @field(elf.symPtr(sec_si), @tagName(class)).shndx,
3226 }
3227 },
3228 else => {
3229 if (sym.ni.alignment(&elf.mf).order(uav_align.toStdMem()).compare(.gte)) return;
3230 si.deleteLocationRelocs(elf);
3231 },
3232 }
3233 assert(sym.loc_relocs == .none);
3234 sym.loc_relocs = @enumFromInt(elf.relocs.items.len);
3235 break :ni sym.ni;
3236 };
4178 const ni = umi.symbol(elf).index().ptr(elf).node;
4179 elf.resetNodeRelocs(ni);
32374180
32384181 var nw: MappedFile.Node.Writer = undefined;
32394182 ni.writer(&elf.mf, gpa, &nw);
32404183 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 };
32414192 codegen.generateSymbol(
32424193 &elf.base,
32434194 pt,
3244 src_loc,
4195 dummy_src_loc,
32454196 .fromInterned(uav_val),
32464197 &nw.interface,
3247 .{ .atom_index = @intFromEnum(si) },
4198 .{ .atom_index = Node.toAtom(ni) },
32484199 ) catch |err| switch (err) {
32494200 error.WriteFailed => return error.OutOfMemory,
32504201 else => |e| return e,
32514202 };
3252 switch (elf.symPtr(si)) {
4203 switch (elf.symPtr(umi.symbol(elf).index())) {
32534204 inline else => |sym| elf.targetStore(&sym.size, @intCast(nw.interface.end)),
32544205 }
3255 si.applyLocationRelocs(elf);
4206 // The UAV should already be considered to have moved, because it is created as moved and
4207 // pending calls to `flushUav` always happen before pending calls to `flushMoved`.
4208 assert(ni.hasMoved(&elf.mf));
32564209}
32574210
32584211fn flushLazy(elf: *Elf, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void {
......@@ -3260,33 +4213,12 @@ fn flushLazy(elf: *Elf, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void {
32604213 const gpa = zcu.gpa;
32614214
32624215 const lazy = lmr.lazySymbol(elf);
3263 const si = lmr.symbol(elf);
3264 const ni = ni: {
3265 const sym = si.get(elf);
3266 switch (sym.ni) {
3267 .none => {
3268 try elf.nodes.ensureUnusedCapacity(gpa, 1);
3269 const sec_si: Symbol.Index = switch (lazy.kind) {
3270 .code => .text,
3271 .const_data => .rodata,
3272 };
3273 const ni = try elf.mf.addLastChildNode(gpa, sec_si.node(elf), .{ .moved = true });
3274 elf.nodes.appendAssumeCapacity(switch (lazy.kind) {
3275 .code => .{ .lazy_code = @enumFromInt(lmr.index) },
3276 .const_data => .{ .lazy_const_data = @enumFromInt(lmr.index) },
3277 });
3278 sym.ni = ni;
3279 switch (elf.symPtr(si)) {
3280 inline else => |sym_ptr, class| sym_ptr.shndx =
3281 @field(elf.symPtr(sec_si), @tagName(class)).shndx,
3282 }
3283 },
3284 else => si.deleteLocationRelocs(elf),
3285 }
3286 assert(sym.loc_relocs == .none);
3287 sym.loc_relocs = @enumFromInt(elf.relocs.items.len);
3288 break :ni sym.ni;
3289 };
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);
32904222
32914223 var required_alignment: InternPool.Alignment = .none;
32924224 var nw: MappedFile.Node.Writer = undefined;
......@@ -3300,15 +4232,14 @@ fn flushLazy(elf: *Elf, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void {
33004232 &required_alignment,
33014233 &nw.interface,
33024234 .none,
3303 .{ .atom_index = @intFromEnum(si) },
4235 .{ .atom_index = Node.toAtom(ni) },
33044236 );
3305 switch (elf.symPtr(si)) {
4237 switch (elf.symPtr(lmr.symbol(elf).index())) {
33064238 inline else => |sym| elf.targetStore(&sym.size, @intCast(nw.interface.end)),
33074239 }
3308 si.applyLocationRelocs(elf);
33094240}
33104241
3311fn flushInputSection(elf: *Elf, isi: Node.InputSectionIndex) !void {
4242fn flushInputSection(elf: *Elf, isi: InputSection.Index) !void {
33124243 const file_loc = isi.fileLocation(elf);
33134244 if (file_loc.size == 0) return;
33144245 const comp = elf.base.comp;
......@@ -3321,12 +4252,13 @@ fn flushInputSection(elf: *Elf, isi: Node.InputSectionIndex) !void {
33214252 var fr = file.reader(io, &.{});
33224253 try fr.seekTo(file_loc.offset);
33234254 var nw: MappedFile.Node.Writer = undefined;
3324 const si = isi.symbol(elf);
3325 si.node(elf).writer(&elf.mf, gpa, &nw);
4255 isi.node(elf).writer(&elf.mf, gpa, &nw);
33264256 defer nw.deinit();
33274257 if (try nw.interface.sendFileAll(&fr, .limited(@intCast(file_loc.size))) != file_loc.size)
33284258 return error.EndOfStream;
3329 si.applyLocationRelocs(elf);
4259 // The input section should already be considered to have moved, because it is created as moved
4260 // and pending calls to `flushInputSection` always happen before pending calls to `flushMoved`.
4261 assert(isi.node(elf).hasMoved(&elf.mf));
33304262}
33314263
33324264fn flushFileOffset(elf: *Elf, ni: MappedFile.Node.Index) !void {
......@@ -3349,7 +4281,7 @@ fn flushFileOffset(elf: *Elf, ni: MappedFile.Node.Index) !void {
33494281 var child_it = ni.children(&elf.mf);
33504282 while (child_it.next()) |child_ni| try elf.flushFileOffset(child_ni);
33514283 },
3352 .section => |si| switch (elf.shdrPtr(si.shndx(elf))) {
4284 .section => |shndx| switch (elf.shdrPtr(shndx)) {
33534285 inline else => |shdr| elf.targetStore(&shdr.offset, @intCast(
33544286 ni.fileLocation(&elf.mf, false).offset,
33554287 )),
......@@ -3378,22 +4310,21 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {
33784310 },
33794311 }
33804312 },
3381 .section => |si| {
4313 .section => |shndx| {
33824314 try elf.flushFileOffset(ni);
33834315 const addr = elf.computeNodeVAddr(ni);
3384 const shndx = si.shndx(elf);
33854316 switch (elf.shdrPtr(shndx)) {
33864317 inline else => |shdr, class| {
33874318 const flags = elf.targetLoad(&shdr.flags).shf;
33884319 if (flags.ALLOC) {
3389 if (elf.si.dynamic != .null) {
3390 if (si == elf.si.got) {
4320 if (elf.shndx.dynamic != .UNDEF) {
4321 if (shndx == elf.shndx.got) {
33914322 const old_addr = elf.targetLoad(&shdr.addr);
3392 const rela_dyn_si = shndx.get(elf).rela_si;
4323 const rela_dyn_shndx = shndx.get(elf).rela_shndx;
33934324 const relas: []class.ElfN().Rela = @ptrCast(@alignCast(
3394 rela_dyn_si.node(elf).slice(&elf.mf)[0..@intCast(
4325 rela_dyn_shndx.get(elf).ni.slice(&elf.mf)[0..@intCast(
33954326 elf.targetLoad(&@field(
3396 elf.shdrPtr(rela_dyn_si.shndx(elf)),
4327 elf.shdrPtr(rela_dyn_shndx),
33974328 @tagName(class),
33984329 ).size),
33994330 )],
......@@ -3413,19 +4344,19 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {
34134344 ),
34144345 },
34154346 }
3416 } else if (si == elf.si.got_plt) {
4347 } else if (shndx == elf.shndx.got_plt) {
34174348 const target_endian = elf.targetEndian();
34184349 const old_addr = elf.targetLoad(&shdr.addr);
3419 const rela_plt_si = shndx.get(elf).rela_si;
4350 const rela_plt_shndx = shndx.get(elf).rela_shndx;
34204351 const relas: []class.ElfN().Rela = @ptrCast(@alignCast(
3421 rela_plt_si.node(elf).slice(&elf.mf)[0..@intCast(
4352 rela_plt_shndx.get(elf).ni.slice(&elf.mf)[0..@intCast(
34224353 elf.targetLoad(&@field(
3423 elf.shdrPtr(rela_plt_si.shndx(elf)),
4354 elf.shdrPtr(rela_plt_shndx),
34244355 @tagName(class),
34254356 ).size),
34264357 )],
34274358 ));
3428 const plt_sec_slice = elf.si.plt_sec.node(elf).slice(&elf.mf);
4359 const plt_sec_slice = elf.shndx.plt_sec.get(elf).ni.slice(&elf.mf);
34294360 switch (elf.ehdrField(.machine)) {
34304361 else => |machine| @panic(@tagName(machine)),
34314362 .AARCH64, .PPC64, .RISCV => {},
......@@ -3454,7 +4385,7 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {
34544385 }
34554386 },
34564387 }
3457 } else if (si == elf.si.plt_sec) {
4388 } else if (shndx == elf.shndx.plt_sec) {
34584389 const target_endian = elf.targetEndian();
34594390 const old_addr = elf.targetLoad(&shdr.addr);
34604391 const plt_sec_slice = ni.slice(&elf.mf);
......@@ -3477,34 +4408,72 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {
34774408 }
34784409 }
34794410 elf.targetStore(&shdr.addr, @intCast(addr));
3480 @field(elf.symPtr(si), @tagName(class)).value = shdr.addr;
4411 shndx.get(elf).lsi.index().flushMoved(elf, addr);
4412 }
4413
4414 if (shndx == elf.shndx.plt) {
4415 elf.flushMovedNodeRelocs(ni, elf.targetLoad(&shdr.addr), elf.first_plt_reloc);
4416 } else if (shndx == elf.shndx.dynamic) {
4417 elf.flushMovedNodeRelocs(ni, elf.targetLoad(&shdr.addr), elf.first_dynamic_reloc);
34814418 }
34824419 },
34834420 }
3484 si.flushMoved(elf, addr);
34854421 },
34864422 .input_section => |isi| {
3487 const old_addr = switch (elf.symPtr(isi.symbol(elf))) {
3488 inline else => |sym| elf.targetLoad(&sym.value),
3489 };
3490 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
34914428 const ii = isi.input(elf);
3492 var si = ii.symbol(elf);
3493 const end_si = ii.endSymbol(elf);
3494 while (cond: {
3495 si = si.next();
3496 break :cond si != end_si;
3497 }) {
3498 if (si.get(elf).ni != ni) continue;
3499 si.flushMoved(elf, switch (elf.symPtr(si)) {
3500 inline else => |sym| elf.targetLoad(&sym.value),
3501 } - 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 }
35024459 }
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));
35034476 },
3504 inline .nav, .uav, .lazy_code, .lazy_const_data => |mi| mi.symbol(elf).flushMoved(
3505 elf,
3506 elf.computeNodeVAddr(ni),
3507 ),
35084477 }
35094478 try ni.childrenMoved(elf.base.comp.gpa, &elf.mf);
35104479}
......@@ -3542,7 +4511,7 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void {
35424511 switch (elf.targetLoad(&next_ph.type)) {
35434512 else => unreachable,
35444513 .NULL, .LOAD => {},
3545 .DYNAMIC, .INTERP, .PHDR, .TLS => break,
4514 .DYNAMIC, .INTERP, .PHDR, .TLS, std.elf.PT.GNU_RELRO => break,
35464515 }
35474516 const next_vaddr = elf.targetLoad(&next_ph.vaddr);
35484517 if (vaddr + memsz <= next_vaddr) break;
......@@ -3564,7 +4533,7 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void {
35644533 }
35654534 },
35664535 },
3567 .section => |si| switch (elf.shdrPtr(si.shndx(elf))) {
4536 .section => |shndx| switch (elf.shdrPtr(shndx)) {
35684537 inline else => |shdr, class| {
35694538 switch (elf.targetLoad(&shdr.type)) {
35704539 else => unreachable,
......@@ -3572,10 +4541,10 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void {
35724541 .PROGBITS => if (size == 0) elf.targetStore(&shdr.type, .NULL),
35734542 .SYMTAB, .DYNAMIC, .REL, .DYNSYM => return,
35744543 .STRTAB => {
3575 if (elf.si.dynamic != .null) {
3576 if (si == elf.si.dynstr) {
4544 if (elf.shndx.dynamic != .UNDEF) {
4545 if (shndx == elf.shndx.dynstr) {
35774546 const dynamic_entries: [][2]class.ElfN().Addr = @ptrCast(@alignCast(
3578 elf.si.dynamic.node(elf).slice(&elf.mf),
4547 elf.shndx.dynamic.get(elf).ni.slice(&elf.mf),
35794548 ));
35804549 for (dynamic_entries) |*dynamic_entry|
35814550 switch (elf.targetLoad(&dynamic_entry[0])) {
......@@ -3587,19 +4556,19 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void {
35874556 return;
35884557 },
35894558 .RELA => {
3590 if (elf.si.dynamic != .null) {
3591 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) {
35924561 const dynamic_entries: [][2]class.ElfN().Addr = @ptrCast(@alignCast(
3593 elf.si.dynamic.node(elf).slice(&elf.mf),
4562 elf.shndx.dynamic.get(elf).ni.slice(&elf.mf),
35944563 ));
35954564 for (dynamic_entries) |*dynamic_entry|
35964565 switch (elf.targetLoad(&dynamic_entry[0])) {
35974566 else => {},
35984567 std.elf.DT_RELASZ => dynamic_entry[1] = shdr.size,
35994568 };
3600 } else if (si == elf.si.got_plt.shndx(elf).get(elf).rela_si) {
4569 } else if (shndx == elf.shndx.got_plt.get(elf).rela_shndx) {
36014570 const dynamic_entries: [][2]class.ElfN().Addr = @ptrCast(@alignCast(
3602 elf.si.dynamic.node(elf).slice(&elf.mf),
4571 elf.shndx.dynamic.get(elf).ni.slice(&elf.mf),
36034572 ));
36044573 for (dynamic_entries) |*dynamic_entry|
36054574 switch (elf.targetLoad(&dynamic_entry[0])) {
......@@ -3611,7 +4580,9 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void {
36114580 return;
36124581 },
36134582 }
3614 elf.targetStore(&shdr.size, @intCast(size));
4583 if (shndx != elf.shndx.plt) {
4584 elf.targetStore(&shdr.size, @intCast(size));
4585 }
36154586 },
36164587 },
36174588 .input_section, .nav, .uav, .lazy_code, .lazy_const_data => {},
......@@ -3642,7 +4613,6 @@ fn updateExportsInner(
36424613 export_indices: []const Zcu.Export.Index,
36434614) !void {
36444615 const zcu = pt.zcu;
3645 const gpa = zcu.gpa;
36464616 const ip = &zcu.intern_pool;
36474617
36484618 switch (exported) {
......@@ -3652,44 +4622,35 @@ fn updateExportsInner(
36524622 Value.fromInterned(uav).fmtValue(pt),
36534623 }),
36544624 }
3655 try elf.symtab.ensureUnusedCapacity(gpa, export_indices.len);
3656 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) {
36574627 .nav => |nav| .{
3658 try elf.navSymbol(zcu, nav),
4628 (try elf.navMapIndex(zcu, nav)).symbol(elf),
36594629 navType(ip, ip.getNav(nav).resolved.?, elf.base.comp.config.any_non_single_threaded),
36604630 },
3661 .uav => |uav| .{ @enumFromInt(switch (try elf.lowerUav(
3662 pt,
3663 uav,
3664 Type.fromInterned(ip.typeOf(uav)).abiAlignment(zcu),
3665 export_indices[0].ptr(zcu).src,
3666 )) {
3667 .sym_index => |si| si,
3668 .fail => |em| {
3669 defer em.destroy(gpa);
3670 return elf.base.comp.link_diags.fail("{s}", .{em.msg});
3671 },
3672 }), .OBJECT },
4631 .uav => |uav| .{ (try elf.uavMapIndex(uav, .none)).symbol(elf), .OBJECT },
36734632 };
36744633 while (try elf.idle(pt.tid)) {}
3675 const exported_ni = exported_si.node(elf);
3676 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())) {
36774635 inline else => |exported_sym| .{
36784636 elf.targetLoad(&exported_sym.value),
3679 exported_sym.size,
3680 exported_sym.shndx,
4637 elf.targetLoad(&exported_sym.size),
4638 .fromSection(elf.targetLoad(&exported_sym.shndx)),
36814639 },
36824640 };
36834641 for (export_indices) |export_index| {
36844642 const @"export" = export_index.ptr(zcu);
36854643 const name = @"export".opts.name.toSlice(ip);
3686 const export_si = try elf.globalSymbol(.{
3687 .name = name,
4644 _ = elf.addGlobalSymbolAssumeCapacity(.{
4645 .node = .none,
4646 .name = try .string(elf, name),
4647 .value = value,
4648 .size = @intCast(size),
36884649 .type = @"type",
36894650 .bind = switch (@"export".opts.linkage) {
3690 .internal => .LOCAL,
3691 .strong => .GLOBAL,
3692 .weak => .WEAK,
4651 .internal => @panic("TODO internal linkage"),
4652 .strong => .strong,
4653 .weak => .weak,
36934654 .link_once => return error.LinkOnceUnsupported,
36944655 },
36954656 .visibility = switch (@"export".opts.visibility) {
......@@ -3697,15 +4658,23 @@ fn updateExportsInner(
36974658 .hidden => .HIDDEN,
36984659 .protected => .PROTECTED,
36994660 },
3700 });
3701 export_si.get(elf).ni = exported_ni;
3702 switch (elf.symPtr(export_si)) {
3703 inline else => |export_sym| {
3704 export_sym.size = @intCast(size);
3705 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 }
37064676 },
3707 }
3708 export_si.flushMoved(elf, value);
4677 };
37094678 }
37104679}
37114680
......@@ -3759,13 +4728,13 @@ pub fn printNode(
37594728 try w.writeByte(')');
37604729 },
37614730 },
3762 .section => |si| try w.print("({s})", .{elf.sectionName(si)}),
4731 .section => |shndx| try w.print("({s})", .{shndx.name(elf)}),
37634732 .input_section => |isi| {
37644733 const ii = isi.input(elf);
37654734 try w.print("({f}{f}, {s})", .{
37664735 ii.path(elf).fmtEscapeString(),
37674736 fmtMemberString(ii.member(elf)),
3768 elf.sectionName(elf.getNode(isi.symbol(elf).node(elf).parent(&elf.mf)).section),
4737 elf.getNode(isi.node(elf).parent(&elf.mf)).section.name(elf),
37694738 });
37704739 },
37714740 .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,