authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-11-20 04:33:04-08:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2025-11-20 04:33:04-08:00
loga9568ed2963298864e5c9a92a3eafe81771128ff
treea4b60d5afdbf0174f399375246412e58e0023995
parent7b325e08c9b401b723345c33d12a37a832dedfab
parent61a1cefeb30fab3aa82e0d47385ca4f2c4b36c1b
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #25898 from jacobly0/elfv2-progress

Elf2: more progress

8 files changed, 838 insertions(+), 247 deletions(-)

lib/std/Io/Writer.zig-4
......@@ -2282,10 +2282,6 @@ pub const Discarding = struct {
22822282
22832283 pub fn sendFile(w: *Writer, file_reader: *File.Reader, limit: Limit) FileError!usize {
22842284 if (File.Handle == void) return error.Unimplemented;
2285 switch (builtin.zig_backend) {
2286 else => {},
2287 .stage2_aarch64 => return error.Unimplemented,
2288 }
22892285 const d: *Discarding = @alignCast(@fieldParentPtr("writer", w));
22902286 d.count += w.end;
22912287 w.end = 0;
lib/std/Progress.zig-1
......@@ -427,7 +427,6 @@ const noop_impl = builtin.single_threaded or switch (builtin.os.tag) {
427427 .wasi, .freestanding => true,
428428 else => false,
429429} or switch (builtin.zig_backend) {
430 .stage2_aarch64 => true,
431430 else => false,
432431};
433432
lib/std/fs/File.zig+1-4
......@@ -739,10 +739,7 @@ pub const Writer = struct {
739739 return .{
740740 .vtable = &.{
741741 .drain = drain,
742 .sendFile = switch (builtin.zig_backend) {
743 else => sendFile,
744 .stage2_aarch64 => Io.Writer.unimplementedSendFile,
745 },
742 .sendFile = sendFile,
746743 },
747744 .buffer = buffer,
748745 };
src/codegen/aarch64/Select.zig+9-14
......@@ -9569,11 +9569,15 @@ pub const Value = struct {
95699569 .zr
95709570 else
95719571 return false;
9572 if (part_ra != .zr) {
9573 const live_vi = isel.live_registers.getPtr(part_ra);
9574 assert(live_vi.* == .free);
9575 live_vi.* = .allocating;
9576 }
9572 const part_lock: RegLock = switch (part_ra) {
9573 else => isel.lockReg(part_ra),
9574 .zr => .empty,
9575 };
9576 defer switch (opts.expected_live_registers.get(part_ra)) {
9577 _ => {},
9578 .allocating => unreachable,
9579 .free => part_lock.unlock(isel),
9580 };
95779581 if (opts.wrap) |int_info| switch (int_info.bits) {
95789582 else => unreachable,
95799583 1...7, 9...15, 17...31 => |bits| try isel.emit(switch (int_info.signedness) {
......@@ -9604,15 +9608,6 @@ pub const Value = struct {
96049608 64 => {},
96059609 };
96069610 try isel.loadReg(part_ra, part_size, part_vi.signedness(isel), base_ra, opts.offset);
9607 if (part_ra != .zr) {
9608 const live_vi = isel.live_registers.getPtr(part_ra);
9609 assert(live_vi.* == .allocating);
9610 switch (opts.expected_live_registers.get(part_ra)) {
9611 _ => {},
9612 .allocating => unreachable,
9613 .free => live_vi.* = .free,
9614 }
9615 }
96169611 return true;
96179612 }
96189613 var used = false;
src/codegen/x86_64/Emit.zig+9-3
......@@ -881,7 +881,7 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI
881881 end_offset - 4,
882882 @enumFromInt(reloc.target.index),
883883 reloc.off - 4,
884 .{ .X86_64 = .PC32 },
884 .{ .X86_64 = .PLT32 },
885885 ) else if (emit.bin_file.cast(.macho)) |macho_file| {
886886 const zo = macho_file.getZigObject().?;
887887 const atom = zo.symbols.items[emit.atom_index].getAtom(macho_file).?;
......@@ -916,7 +916,13 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI
916916 .r_info = @as(u64, reloc.target.index) << 32 | @intFromEnum(r_type),
917917 .r_addend = reloc.off - 4,
918918 }, zo);
919 } else return emit.fail("TODO implement {s} reloc for {s}", .{
919 } else if (emit.bin_file.cast(.elf2)) |elf| try elf.addReloc(
920 @enumFromInt(emit.atom_index),
921 end_offset - 4,
922 @enumFromInt(reloc.target.index),
923 reloc.off - 4,
924 .{ .X86_64 = if (emit.pic) .TLSLD else unreachable },
925 ) else return emit.fail("TODO implement {s} reloc for {s}", .{
920926 @tagName(reloc.target.type), @tagName(emit.bin_file.tag),
921927 }),
922928 .tlv => if (emit.bin_file.cast(.elf)) |elf_file| {
......@@ -933,7 +939,7 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI
933939 end_offset - 4,
934940 @enumFromInt(reloc.target.index),
935941 reloc.off,
936 .{ .X86_64 = .TPOFF32 },
942 .{ .X86_64 = if (emit.pic) .DTPOFF32 else .TPOFF32 },
937943 ) else if (emit.bin_file.cast(.macho)) |macho_file| {
938944 const zo = macho_file.getZigObject().?;
939945 const atom = zo.symbols.items[emit.atom_index].getAtom(macho_file).?;
src/link.zig+10-5
......@@ -1069,7 +1069,7 @@ pub const File = struct {
10691069 errdefer archive.file.close();
10701070 loadInput(base, .{ .archive = archive }) catch |err| switch (err) {
10711071 error.BadMagic, error.UnexpectedEndOfFile => {
1072 if (base.tag != .elf) return err;
1072 if (base.tag != .elf and base.tag != .elf2) return err;
10731073 try loadGnuLdScript(base, path, query, archive.file);
10741074 archive.file.close();
10751075 return;
......@@ -1091,7 +1091,7 @@ pub const File = struct {
10911091 errdefer dso.file.close();
10921092 loadInput(base, .{ .dso = dso }) catch |err| switch (err) {
10931093 error.BadMagic, error.UnexpectedEndOfFile => {
1094 if (base.tag != .elf) return err;
1094 if (base.tag != .elf and base.tag != .elf2) return err;
10951095 try loadGnuLdScript(base, path, query, dso.file);
10961096 dso.file.close();
10971097 return;
......@@ -1101,8 +1101,9 @@ pub const File = struct {
11011101 }
11021102
11031103 fn loadGnuLdScript(base: *File, path: Path, parent_query: UnresolvedInput.Query, file: fs.File) anyerror!void {
1104 const diags = &base.comp.link_diags;
1105 const gpa = base.comp.gpa;
1104 const comp = base.comp;
1105 const diags = &comp.link_diags;
1106 const gpa = comp.gpa;
11061107 const stat = try file.stat();
11071108 const size = std.math.cast(u32, stat.size) orelse return error.FileTooBig;
11081109 const buf = try gpa.alloc(u8, size);
......@@ -1124,7 +1125,11 @@ pub const File = struct {
11241125 @panic("TODO");
11251126 } else {
11261127 if (fs.path.isAbsolute(arg.path)) {
1127 const new_path = Path.initCwd(try gpa.dupe(u8, arg.path));
1128 const new_path = Path.initCwd(path: {
1129 comp.mutex.lock();
1130 defer comp.mutex.unlock();
1131 break :path try comp.arena.dupe(u8, arg.path);
1132 });
11281133 switch (Compilation.classifyFileExt(arg.path)) {
11291134 .shared_library => try openLoadDso(base, new_path, query),
11301135 .object => try openLoadObject(base, new_path),
src/link/Elf2.zig+807-214
......@@ -9,8 +9,13 @@ si: Symbol.Known,
99symtab: std.ArrayList(Symbol),
1010shstrtab: StringTable,
1111strtab: StringTable,
12dynsym: std.ArrayList(Symbol.Index),
12dynsym: std.AutoArrayHashMapUnmanaged(Symbol.Index, void),
1313dynstr: StringTable,
14got: struct {
15 len: u32,
16 tlsld: GotIndex,
17 plt: std.AutoArrayHashMapUnmanaged(Symbol.Index, void),
18},
1419needed: std.AutoArrayHashMapUnmanaged(u32, void),
1520inputs: std.ArrayList(struct {
1621 path: std.Build.Cache.Path,
......@@ -35,8 +40,6 @@ pending_uavs: std.AutoArrayHashMapUnmanaged(Node.UavMapIndex, struct {
3540 src_loc: Zcu.LazySrcLoc,
3641}),
3742relocs: std.ArrayList(Reloc),
38/// This is hiding actual bugs with global symbols! Reconsider once they are implemented correctly.
39entry_hack: Symbol.Index,
4043const_prog_node: std.Progress.Node,
4144synth_prog_node: std.Progress.Node,
4245input_prog_node: std.Progress.Node,
......@@ -156,6 +159,7 @@ pub const Node = union(enum) {
156159 comptime phdr: MappedFile.Node.Index = @enumFromInt(4),
157160 comptime text: MappedFile.Node.Index = @enumFromInt(5),
158161 comptime data: MappedFile.Node.Index = @enumFromInt(6),
162 comptime data_rel_ro: MappedFile.Node.Index = @enumFromInt(7),
159163 tls: MappedFile.Node.Index,
160164 };
161165
......@@ -179,71 +183,12 @@ pub const Section = struct {
179183 pub fn unwrap(ri: RelIndex) ?u32 {
180184 return switch (ri) {
181185 .none => null,
182 else => @intFromEnum(ri) - 1,
186 _ => @intFromEnum(ri) - 1,
183187 };
184188 }
185189 };
186190};
187191
188pub const StringTable = struct {
189 map: std.HashMapUnmanaged(u32, void, StringTable.Context, std.hash_map.default_max_load_percentage),
190
191 const Context = struct {
192 slice: []const u8,
193
194 pub fn eql(_: Context, lhs_key: u32, rhs_key: u32) bool {
195 return lhs_key == rhs_key;
196 }
197
198 pub fn hash(ctx: Context, key: u32) u64 {
199 return std.hash_map.hashString(std.mem.sliceTo(ctx.slice[key..], 0));
200 }
201 };
202
203 const Adapter = struct {
204 slice: []const u8,
205
206 pub fn eql(adapter: Adapter, lhs_key: []const u8, rhs_key: u32) bool {
207 return std.mem.startsWith(u8, adapter.slice[rhs_key..], lhs_key) and
208 adapter.slice[rhs_key + lhs_key.len] == 0;
209 }
210
211 pub fn hash(_: Adapter, key: []const u8) u64 {
212 assert(std.mem.indexOfScalar(u8, key, 0) == null);
213 return std.hash_map.hashString(key);
214 }
215 };
216
217 pub fn get(st: *StringTable, elf: *Elf, si: Symbol.Index, key: []const u8) !u32 {
218 const gpa = elf.base.comp.gpa;
219 const ni = si.node(elf);
220 const slice_const = ni.sliceConst(&elf.mf);
221 const gop = try st.map.getOrPutContextAdapted(
222 gpa,
223 key,
224 StringTable.Adapter{ .slice = slice_const },
225 .{ .slice = slice_const },
226 );
227 if (gop.found_existing) return gop.key_ptr.*;
228 const old_size, const new_size = size: switch (elf.shdrPtr(si.shndx(elf))) {
229 inline else => |shdr| {
230 const old_size: u32 = @intCast(elf.targetLoad(&shdr.size));
231 const new_size: u32 = @intCast(old_size + key.len + 1);
232 elf.targetStore(&shdr.size, new_size);
233 break :size .{ old_size, new_size };
234 },
235 };
236 _, const node_size = ni.location(&elf.mf).resolve(&elf.mf);
237 if (new_size > node_size)
238 try ni.resize(&elf.mf, gpa, new_size +| new_size / MappedFile.growth_factor);
239 const slice = ni.slice(&elf.mf)[old_size..];
240 @memcpy(slice[0..key.len], key);
241 slice[key.len] = 0;
242 gop.key_ptr.* = old_size;
243 return old_size;
244 }
245};
246
247192pub const Symbol = struct {
248193 ni: MappedFile.Node.Index,
249194 /// Relocations contained within this symbol
......@@ -260,6 +205,11 @@ pub const Symbol = struct {
260205 rodata,
261206 text,
262207 data,
208 data_rel_ro,
209 got,
210 got_plt,
211 plt,
212 plt_sec,
263213 _,
264214
265215 pub fn get(si: Symbol.Index, elf: *Elf) *Symbol {
......@@ -333,7 +283,8 @@ pub const Symbol = struct {
333283 shndx: Shndx = .UNDEF,
334284 };
335285 pub fn init(si: Symbol.Index, elf: *Elf, opts: InitOptions) !void {
336 const gpa = elf.base.comp.gpa;
286 const comp = elf.base.comp;
287 const gpa = comp.gpa;
337288 const target_endian = elf.targetEndian();
338289 const name_strtab_entry = try elf.string(.strtab, opts.name);
339290 switch (elf.shdrPtr(elf.si.symtab.shndx(elf))) {
......@@ -373,15 +324,34 @@ pub const Symbol = struct {
373324 @intFromEnum(si) + 1,
374325 )),
375326 }
376 if (opts.bind == .LOCAL or elf.si.dynsym == .null) return;
377 const dsi = elf.dynsym.items.len;
378 try elf.dynsym.append(gpa, si);
327
328 if (opts.bind == .LOCAL) return;
329 no_entry: {
330 if (std.mem.eql(u8, opts.name, entry: switch (elf.options.entry) {
331 .default => switch (comp.config.output_mode) {
332 .Exe => continue :entry .enabled,
333 .Lib, .Obj => continue :entry .disabled,
334 },
335 .disabled => break :no_entry,
336 .enabled => "_start",
337 .named => |named| named,
338 })) {
339 elf.si.entry = si;
340 switch (elf.ehdrPtr()) {
341 inline else => |ehdr| elf.targetStore(&ehdr.entry, @intCast(opts.value)),
342 }
343 }
344 }
345
346 if (elf.si.dynsym == .null) return;
347 const dsi = elf.dynsym.count();
348 try elf.dynsym.putNoClobber(gpa, si, {});
379349 const name_dynstr_entry = try elf.string(.dynstr, opts.name);
380350 switch (elf.shdrPtr(elf.si.dynsym.shndx(elf))) {
381351 inline else => |shdr| {
382352 const old_size = elf.targetLoad(&shdr.size);
383353 const ent_size = elf.targetLoad(&shdr.entsize);
384 const new_size = ent_size * elf.dynsym.items.len;
354 const new_size = ent_size * elf.dynsym.count();
385355 if (new_size > old_size) {
386356 elf.targetStore(&shdr.size, @intCast(new_size));
387357 const dynsym_ni = elf.si.dynsym.node(elf);
......@@ -409,13 +379,136 @@ pub const Symbol = struct {
409379 if (target_endian != native_endian) std.mem.byteSwapAllFields(Sym, dynsym);
410380 },
411381 }
382
383 if (opts.type != .FUNC or opts.shndx != .UNDEF) return;
384 const plt_index: u32 = @intCast(elf.got.plt.count());
385 try elf.got.plt.putNoClobber(gpa, si, {});
386 switch (elf.ehdrField(.machine)) {
387 else => |machine| @panic(@tagName(machine)),
388 .X86_64 => {
389 const plt_ni = elf.si.plt.node(elf);
390 _, const plt_node_size = plt_ni.location(&elf.mf).resolve(&elf.mf);
391 const plt_addr = plt_addr: switch (elf.shdrPtr(elf.si.plt.shndx(elf))) {
392 inline else => |shdr| {
393 const old_size = 16 * (1 + plt_index);
394 const new_size = old_size + 16;
395 elf.targetStore(&shdr.size, new_size);
396 if (new_size > plt_node_size) try plt_ni.resize(
397 &elf.mf,
398 gpa,
399 new_size +| new_size / MappedFile.growth_factor,
400 );
401 const plt_slice = plt_ni.slice(&elf.mf)[old_size..new_size];
402 @memcpy(plt_slice, &[16]u8{
403 0xf3, 0x0f, 0x1e, 0xfa, // endbr64
404 0x68, 0x00, 0x00, 0x00, 0x00, // push $0x0
405 0xe9, 0x00, 0x00, 0x00, 0x00, // jmp 0
406 0x66, 0x90, // xchg %ax,%ax
407 });
408 std.mem.writeInt(u32, plt_slice[5..][0..4], plt_index, target_endian);
409 std.mem.writeInt(
410 i32,
411 plt_slice[10..][0..4],
412 2 - @as(i32, @intCast(new_size)),
413 target_endian,
414 );
415 break :plt_addr elf.targetLoad(&shdr.addr) + old_size;
416 },
417 };
418
419 const got_plt_shndx = elf.si.got_plt.shndx(elf);
420 const got_plt_ni = elf.si.got_plt.node(elf);
421 _, const got_plt_node_size = got_plt_ni.location(&elf.mf).resolve(&elf.mf);
422 const got_plt_addr = got_plt_addr: switch (elf.shdrPtr(got_plt_shndx)) {
423 inline else => |shdr, class| {
424 const Addr = class.ElfN().Addr;
425 const addr_size = @sizeOf(Addr);
426 const old_size = addr_size * (3 + plt_index);
427 const new_size = old_size + addr_size;
428 elf.targetStore(&shdr.size, new_size);
429 if (new_size > got_plt_node_size) try got_plt_ni.resize(
430 &elf.mf,
431 gpa,
432 new_size +| new_size / MappedFile.growth_factor,
433 );
434 std.mem.writeInt(
435 Addr,
436 got_plt_ni.slice(&elf.mf)[old_size..][0..addr_size],
437 @intCast(plt_addr),
438 target_endian,
439 );
440 break :got_plt_addr elf.targetLoad(&shdr.addr) + old_size;
441 },
442 };
443
444 const plt_sec_ni = elf.si.plt_sec.node(elf);
445 _, const plt_sec_node_size = plt_sec_ni.location(&elf.mf).resolve(&elf.mf);
446 switch (elf.shdrPtr(elf.si.plt_sec.shndx(elf))) {
447 inline else => |shdr| {
448 const old_size = 16 * plt_index;
449 const new_size = old_size + 16;
450 elf.targetStore(&shdr.size, new_size);
451 if (new_size > plt_sec_node_size) try plt_sec_ni.resize(
452 &elf.mf,
453 gpa,
454 new_size +| new_size / MappedFile.growth_factor,
455 );
456 const plt_sec_slice = plt_sec_ni.slice(&elf.mf)[old_size..new_size];
457 @memcpy(plt_sec_slice, &[16]u8{
458 0xf3, 0x0f, 0x1e, 0xfa, // endbr64
459 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *0x0(%rip)
460 0x66, 0x0f, 0x1f, 0x44, 0x00, 0x00, // nopw 0x0(%rax,%rax,1)
461 });
462 std.mem.writeInt(
463 i32,
464 plt_sec_slice[6..][0..4],
465 @intCast(@as(i64, @bitCast(
466 got_plt_addr -% (elf.targetLoad(&shdr.addr) + old_size + 10),
467 ))),
468 target_endian,
469 );
470 },
471 }
472
473 const rela_plt_si = got_plt_shndx.get(elf).rela_si;
474 const rela_plt_ni = rela_plt_si.node(elf);
475 _, const rela_plt_node_size = rela_plt_ni.location(&elf.mf).resolve(&elf.mf);
476 switch (elf.shdrPtr(rela_plt_si.shndx(elf))) {
477 inline else => |shdr, class| {
478 const Rela = class.ElfN().Rela;
479 const rela_size = elf.targetLoad(&shdr.entsize);
480 const old_size = rela_size * plt_index;
481 const new_size = old_size + rela_size;
482 elf.targetStore(&shdr.size, new_size);
483 if (new_size > rela_plt_node_size) try rela_plt_ni.resize(
484 &elf.mf,
485 gpa,
486 new_size +| new_size / MappedFile.growth_factor,
487 );
488 const rela: *Rela = @ptrCast(@alignCast(
489 rela_plt_ni.slice(&elf.mf)[@intCast(old_size)..@intCast(new_size)],
490 ));
491 rela.* = .{
492 .offset = @intCast(got_plt_addr),
493 .info = .{
494 .type = @intFromEnum(std.elf.R_X86_64.JUMP_SLOT),
495 .sym = @intCast(dsi),
496 },
497 .addend = 0,
498 };
499 if (target_endian != native_endian) std.mem.byteSwapAllFields(Rela, rela);
500 },
501 }
502 try rela_plt_ni.resized(gpa, &elf.mf);
503 },
504 }
412505 }
413506
414507 pub fn flushMoved(si: Symbol.Index, elf: *Elf, value: u64) void {
415508 switch (elf.symPtr(si)) {
416509 inline else => |sym, class| {
417510 elf.targetStore(&sym.value, @intCast(value));
418 if (si == elf.entry_hack) {
511 if (si == elf.si.entry) {
419512 @branchHint(.unlikely);
420513 @field(elf.ehdrPtr(), @tagName(class)).entry = sym.value;
421514 }
......@@ -464,10 +557,16 @@ pub const Symbol = struct {
464557 comptime rodata: Symbol.Index = .rodata,
465558 comptime text: Symbol.Index = .text,
466559 comptime data: Symbol.Index = .data,
560 comptime data_rel_ro: Symbol.Index = .data_rel_ro,
561 comptime got: Symbol.Index = .got,
562 comptime got_plt: Symbol.Index = .got_plt,
563 comptime plt: Symbol.Index = .plt,
564 comptime plt_sec: Symbol.Index = .plt_sec,
467565 dynsym: Symbol.Index,
468566 dynstr: Symbol.Index,
469567 dynamic: Symbol.Index,
470568 tdata: Symbol.Index,
569 entry: Symbol.Index,
471570 };
472571
473572 comptime {
......@@ -475,6 +574,83 @@ pub const Symbol = struct {
475574 }
476575};
477576
577pub const StringTable = struct {
578 map: std.HashMapUnmanaged(u32, void, StringTable.Context, std.hash_map.default_max_load_percentage),
579
580 const Context = struct {
581 slice: []const u8,
582
583 pub fn eql(_: Context, lhs_key: u32, rhs_key: u32) bool {
584 return lhs_key == rhs_key;
585 }
586
587 pub fn hash(ctx: Context, key: u32) u64 {
588 return std.hash_map.hashString(std.mem.sliceTo(ctx.slice[key..], 0));
589 }
590 };
591
592 const Adapter = struct {
593 slice: []const u8,
594
595 pub fn eql(adapter: Adapter, lhs_key: []const u8, rhs_key: u32) bool {
596 return std.mem.startsWith(u8, adapter.slice[rhs_key..], lhs_key) and
597 adapter.slice[rhs_key + lhs_key.len] == 0;
598 }
599
600 pub fn hash(_: Adapter, key: []const u8) u64 {
601 assert(std.mem.indexOfScalar(u8, key, 0) == null);
602 return std.hash_map.hashString(key);
603 }
604 };
605
606 pub fn get(st: *StringTable, elf: *Elf, si: Symbol.Index, key: []const u8) !u32 {
607 const gpa = elf.base.comp.gpa;
608 const ni = si.node(elf);
609 const slice_const = ni.sliceConst(&elf.mf);
610 const gop = try st.map.getOrPutContextAdapted(
611 gpa,
612 key,
613 StringTable.Adapter{ .slice = slice_const },
614 .{ .slice = slice_const },
615 );
616 if (gop.found_existing) return gop.key_ptr.*;
617 try ni.resized(gpa, &elf.mf);
618 const old_size, const new_size = size: switch (elf.shdrPtr(si.shndx(elf))) {
619 inline else => |shdr| {
620 const old_size: u32 = @intCast(elf.targetLoad(&shdr.size));
621 const new_size: u32 = @intCast(old_size + key.len + 1);
622 elf.targetStore(&shdr.size, new_size);
623 break :size .{ old_size, new_size };
624 },
625 };
626 _, const node_size = ni.location(&elf.mf).resolve(&elf.mf);
627 if (new_size > node_size)
628 try ni.resize(&elf.mf, gpa, new_size +| new_size / MappedFile.growth_factor);
629 const slice = ni.slice(&elf.mf)[old_size..];
630 @memcpy(slice[0..key.len], key);
631 slice[key.len] = 0;
632 gop.key_ptr.* = old_size;
633 return old_size;
634 }
635};
636
637pub const GotIndex = enum(u32) {
638 none = std.math.maxInt(u32),
639 _,
640
641 pub fn wrap(i: ?u32) GotIndex {
642 const gi: GotIndex = @enumFromInt(i orelse return .none);
643 assert(gi != .none);
644 return gi;
645 }
646 pub fn unwrap(gi: GotIndex) ?u32 {
647 return switch (gi) {
648 _ => @intFromEnum(gi),
649 .none => null,
650 };
651 }
652};
653
478654pub const Reloc = extern struct {
479655 type: Reloc.Type,
480656 prev: Reloc.Index,
......@@ -500,7 +676,6 @@ pub const Reloc = extern struct {
500676 .X86_64 => .{ .X86_64 = .NONE },
501677 };
502678 }
503
504679 pub fn absAddr(elf: *Elf) Reloc.Type {
505680 return switch (elf.ehdrField(.machine)) {
506681 else => unreachable,
......@@ -510,7 +685,6 @@ pub const Reloc = extern struct {
510685 .X86_64 => .{ .X86_64 = .@"64" },
511686 };
512687 }
513
514688 pub fn sizeAddr(elf: *Elf) Reloc.Type {
515689 return switch (elf.ehdrField(.machine)) {
516690 else => unreachable,
......@@ -528,7 +702,6 @@ pub const Reloc = extern struct {
528702 => |machine| @unionInit(Reloc.Type, @tagName(machine), @enumFromInt(int)),
529703 };
530704 }
531
532705 pub fn unwrap(rt: Reloc.Type, elf: *Elf) u32 {
533706 return switch (elf.ehdrField(.machine)) {
534707 else => unreachable,
......@@ -558,7 +731,7 @@ pub const Reloc = extern struct {
558731 else => |ni| if (ni.hasMoved(&elf.mf)) return,
559732 }
560733 switch (reloc.target.get(elf).ni) {
561 .none => return,
734 .none => {},
562735 else => |ni| if (ni.hasMoved(&elf.mf)) return,
563736 }
564737 const loc_slice = loc_ni.slice(&elf.mf)[@intCast(reloc.offset)..];
......@@ -568,7 +741,6 @@ pub const Reloc = extern struct {
568741 const loc_sym = &symtab[@intFromEnum(reloc.loc)];
569742 const loc_shndx = elf.targetLoad(&loc_sym.shndx);
570743 assert(loc_shndx != std.elf.SHN_UNDEF);
571 const loc_value = elf.targetLoad(&loc_sym.value) + reloc.offset;
572744 const target_sym = &symtab[@intFromEnum(reloc.target)];
573745 const target_value =
574746 elf.targetLoad(&target_sym.value) +% @as(u64, @bitCast(reloc.addend));
......@@ -582,10 +754,28 @@ pub const Reloc = extern struct {
582754 target_value,
583755 target_endian,
584756 ),
585 .PC32, .PLT32 => std.mem.writeInt(
757 .PC32 => std.mem.writeInt(
758 i32,
759 loc_slice[0..4],
760 @intCast(@as(i64, @bitCast(target_value -%
761 (elf.targetLoad(&loc_sym.value) + reloc.offset)))),
762 target_endian,
763 ),
764 .PLT32 => std.mem.writeInt(
586765 i32,
587766 loc_slice[0..4],
588 @intCast(@as(i64, @bitCast(target_value -% loc_value))),
767 @intCast(@as(i64, @bitCast(
768 if (elf.got.plt.getIndex(reloc.target)) |plt_index|
769 elf.targetLoad(&@field(
770 elf.shdrPtr(elf.si.plt_sec.shndx(elf)),
771 @tagName(class),
772 ).addr) +% 16 * plt_index +%
773 @as(u64, @bitCast(reloc.addend)) -%
774 (elf.targetLoad(&loc_sym.value) + reloc.offset)
775 else
776 target_value -%
777 (elf.targetLoad(&loc_sym.value) + reloc.offset),
778 ))),
589779 target_endian,
590780 ),
591781 .@"32" => std.mem.writeInt(
......@@ -600,6 +790,23 @@ pub const Reloc = extern struct {
600790 @intCast(@as(i64, @bitCast(target_value))),
601791 target_endian,
602792 ),
793 .TLSLD => std.mem.writeInt(
794 i32,
795 loc_slice[0..4],
796 @intCast(@as(i64, @bitCast(
797 elf.targetLoad(&symtab[@intFromEnum(elf.si.got)].value) +%
798 @as(u64, @bitCast(reloc.addend)) +%
799 @as(u64, 8) * elf.got.tlsld.unwrap().? -%
800 (elf.targetLoad(&loc_sym.value) + reloc.offset),
801 ))),
802 target_endian,
803 ),
804 .DTPOFF32 => std.mem.writeInt(
805 i32,
806 loc_slice[0..4],
807 @intCast(@as(i64, @bitCast(target_value))),
808 target_endian,
809 ),
603810 .TPOFF32 => {
604811 const phdr = @field(elf.phdrSlice(), @tagName(class));
605812 const ph = &phdr[elf.getNode(elf.ni.tls).segment];
......@@ -614,13 +821,15 @@ pub const Reloc = extern struct {
614821 .SIZE32 => std.mem.writeInt(
615822 u32,
616823 loc_slice[0..4],
617 @intCast(elf.targetLoad(&target_sym.size)),
824 @intCast(
825 elf.targetLoad(&target_sym.size) +% @as(u64, @bitCast(reloc.addend)),
826 ),
618827 target_endian,
619828 ),
620829 .SIZE64 => std.mem.writeInt(
621830 u64,
622831 loc_slice[0..8],
623 @intCast(elf.targetLoad(&target_sym.size)),
832 elf.targetLoad(&target_sym.size) +% @as(u64, @bitCast(reloc.addend)),
624833 target_endian,
625834 ),
626835 },
......@@ -711,7 +920,7 @@ fn create(
711920 .big => .@"2MSB",
712921 };
713922 const osabi: std.elf.OSABI = switch (target.os.tag) {
714 else => .NONE,
923 else => if (target.abi.isGnu()) .GNU else .NONE,
715924 .freestanding, .other => .STANDALONE,
716925 .netbsd => .NETBSD,
717926 .illumos => .SOLARIS,
......@@ -776,6 +985,7 @@ fn create(
776985 .dynstr = .null,
777986 .dynamic = .null,
778987 .tdata = .null,
988 .entry = .null,
779989 },
780990 .symtab = .empty,
781991 .shstrtab = .{
......@@ -788,6 +998,11 @@ fn create(
788998 .dynstr = .{
789999 .map = .empty,
7901000 },
1001 .got = .{
1002 .len = 0,
1003 .tlsld = .none,
1004 .plt = .empty,
1005 },
7911006 .needed = .empty,
7921007 .inputs = .empty,
7931008 .input_sections = .empty,
......@@ -801,7 +1016,6 @@ fn create(
8011016 }),
8021017 .pending_uavs = .empty,
8031018 .relocs = .empty,
804 .entry_hack = .null,
8051019 .const_prog_node = .none,
8061020 .synth_prog_node = .none,
8071021 .input_prog_node = .none,
......@@ -823,6 +1037,7 @@ pub fn deinit(elf: *Elf) void {
8231037 elf.strtab.map.deinit(gpa);
8241038 elf.dynsym.deinit(gpa);
8251039 elf.dynstr.map.deinit(gpa);
1040 elf.got.plt.deinit(gpa);
8261041 elf.needed.deinit(gpa);
8271042 for (elf.inputs.items) |input| if (input.member) |m| gpa.free(m);
8281043 elf.inputs.deinit(gpa);
......@@ -873,14 +1088,16 @@ fn initHeaders(
8731088 phnum += 1;
8741089 const data_phndx = phnum;
8751090 phnum += 1;
876 const dynamic_phndx = if (have_dynamic_section) phndx: {
1091 const tls_phndx = if (comp.config.any_non_single_threaded) phndx: {
8771092 defer phnum += 1;
8781093 break :phndx phnum;
8791094 } else undefined;
880 const tls_phndx = if (comp.config.any_non_single_threaded) phndx: {
1095 const dynamic_phndx = if (have_dynamic_section) phndx: {
8811096 defer phnum += 1;
8821097 break :phndx phnum;
8831098 } else undefined;
1099 const relro_phndx = phnum;
1100 phnum += 1;
8841101
8851102 const expected_nodes_len = expected_nodes_len: switch (@"type") {
8861103 .NONE, .CORE, _ => unreachable,
......@@ -888,12 +1105,14 @@ fn initHeaders(
8881105 defer phnum = 0;
8891106 break :expected_nodes_len 5 + phnum;
8901107 },
891 .EXEC, .DYN => break :expected_nodes_len 5 + phnum * 2 +
892 @as(usize, 2) * @intFromBool(have_dynamic_section),
1108 .EXEC, .DYN => break :expected_nodes_len 9 + phnum * 2 +
1109 @as(usize, 4) * @intFromBool(have_dynamic_section),
8931110 };
8941111 try elf.nodes.ensureTotalCapacity(gpa, expected_nodes_len);
8951112 try elf.shdrs.ensureTotalCapacity(gpa, shnum);
8961113 try elf.phdrs.resize(gpa, phnum);
1114 try elf.symtab.ensureTotalCapacity(gpa, 1);
1115 if (have_dynamic_section) try elf.dynsym.ensureTotalCapacity(gpa, 1);
8971116 elf.nodes.appendAssumeCapacity(.file);
8981117
8991118 switch (class) {
......@@ -976,10 +1195,18 @@ fn initHeaders(
9761195 elf.nodes.appendAssumeCapacity(.{ .segment = data_phndx });
9771196 elf.phdrs.items[data_phndx] = elf.ni.data;
9781197
1198 assert(elf.ni.data_rel_ro == try elf.mf.addOnlyChildNode(gpa, elf.ni.data, .{
1199 .alignment = elf.mf.flags.block_size,
1200 .moved = true,
1201 .bubbles_moved = false,
1202 }));
1203 elf.nodes.appendAssumeCapacity(.{ .segment = relro_phndx });
1204 elf.phdrs.items[relro_phndx] = elf.ni.data_rel_ro;
1205
9791206 break :ph_vaddr switch (elf.ehdrField(.type)) {
9801207 .NONE, .CORE, _ => unreachable,
9811208 .REL, .DYN => 0,
982 .EXEC => switch (elf.ehdrField(.machine)) {
1209 .EXEC => switch (machine) {
9831210 .@"386" => 0x400000,
9841211 .AARCH64, .X86_64 => 0x200000,
9851212 .PPC, .PPC64 => 0x10000000,
......@@ -1070,35 +1297,48 @@ fn initHeaders(
10701297 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_data);
10711298 ph_vaddr += @intCast(data_size);
10721299
1073 if (have_dynamic_section) {
1074 const ph_dynamic = &phdr[dynamic_phndx];
1075 ph_dynamic.* = .{
1076 .type = .DYNAMIC,
1300 if (comp.config.any_non_single_threaded) {
1301 const ph_tls = &phdr[tls_phndx];
1302 ph_tls.* = .{
1303 .type = .TLS,
10771304 .offset = 0,
10781305 .vaddr = 0,
10791306 .paddr = 0,
10801307 .filesz = 0,
10811308 .memsz = 0,
1082 .flags = .{ .R = true, .W = true },
1083 .@"align" = @intCast(addr_align.toByteUnits()),
1309 .flags = .{ .R = true },
1310 .@"align" = @intCast(elf.mf.flags.block_size.toByteUnits()),
10841311 };
1085 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_dynamic);
1312 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_tls);
10861313 }
10871314
1088 if (comp.config.any_non_single_threaded) {
1089 const ph_tls = &phdr[tls_phndx];
1090 ph_tls.* = .{
1091 .type = .TLS,
1315 if (have_dynamic_section) {
1316 const ph_dynamic = &phdr[dynamic_phndx];
1317 ph_dynamic.* = .{
1318 .type = .DYNAMIC,
10921319 .offset = 0,
10931320 .vaddr = 0,
10941321 .paddr = 0,
10951322 .filesz = 0,
10961323 .memsz = 0,
1097 .flags = .{ .R = true },
1098 .@"align" = @intCast(elf.mf.flags.block_size.toByteUnits()),
1324 .flags = .{ .R = true, .W = true },
1325 .@"align" = @intCast(addr_align.toByteUnits()),
10991326 };
1100 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_tls);
1327 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_dynamic);
11011328 }
1329
1330 const ph_relro = &phdr[relro_phndx];
1331 ph_relro.* = .{
1332 .type = .GNU_RELRO,
1333 .offset = 0,
1334 .vaddr = 0,
1335 .paddr = 0,
1336 .filesz = 0,
1337 .memsz = 0,
1338 .flags = .{ .R = true },
1339 .@"align" = @intCast(elf.mf.flags.block_size.toByteUnits()),
1340 };
1341 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_relro);
11021342 }
11031343
11041344 const sh_undef: *ElfN.Shdr = @ptrCast(@alignCast(elf.ni.shdr.slice(&elf.mf)));
......@@ -1117,7 +1357,6 @@ fn initHeaders(
11171357 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Shdr, sh_undef);
11181358 elf.shdrs.appendAssumeCapacity(.{ .si = .null, .rela_si = .null, .rela_free = .none });
11191359
1120 try elf.symtab.ensureTotalCapacity(gpa, 1);
11211360 elf.symtab.addOneAssumeCapacity().* = .{
11221361 .ni = .none,
11231362 .loc_relocs = .none,
......@@ -1163,7 +1402,9 @@ fn initHeaders(
11631402 .entsize = 1,
11641403 .node_align = elf.mf.flags.block_size,
11651404 }));
1166 try elf.linkSections(.symtab, .strtab);
1405 switch (elf.shdrPtr(elf.si.symtab.shndx(elf))) {
1406 inline else => |shdr| elf.targetStore(&shdr.link, @intFromEnum(elf.si.strtab.shndx(elf))),
1407 }
11671408 elf.si.strtab.node(elf).slice(&elf.mf)[0] = 0;
11681409
11691410 assert(elf.si.rodata == try elf.addSection(elf.ni.rodata, .{
......@@ -1181,7 +1422,50 @@ fn initHeaders(
11811422 .flags = .{ .WRITE = true, .ALLOC = true },
11821423 .addralign = elf.mf.flags.block_size,
11831424 }));
1425 assert(elf.si.data_rel_ro == try elf.addSection(elf.ni.data_rel_ro, .{
1426 .name = ".data.rel.ro",
1427 .flags = .{ .WRITE = true, .ALLOC = true },
1428 .addralign = elf.mf.flags.block_size,
1429 }));
11841430 if (@"type" != .REL) {
1431 assert(elf.si.got == try elf.addSection(elf.ni.data_rel_ro, .{
1432 .name = ".got",
1433 .flags = .{ .WRITE = true, .ALLOC = true },
1434 .addralign = addr_align,
1435 }));
1436 assert(elf.si.got_plt == try elf.addSection(
1437 if (elf.options.z_now) elf.ni.data_rel_ro else elf.ni.data,
1438 .{
1439 .name = ".got.plt",
1440 .type = .PROGBITS,
1441 .flags = .{ .WRITE = true, .ALLOC = true },
1442 .size = switch (machine) {
1443 else => @panic(@tagName(machine)),
1444 .@"386" => 3 * 4,
1445 .X86_64 => 3 * 8,
1446 },
1447 .addralign = addr_align,
1448 },
1449 ));
1450 const plt_size: std.elf.Xword, const plt_align: std.mem.Alignment, const plt_sec =
1451 switch (machine) {
1452 else => @panic(@tagName(machine)),
1453 .X86_64 => .{ 16, .@"16", true },
1454 };
1455 assert(elf.si.plt == try elf.addSection(elf.ni.text, .{
1456 .name = ".plt",
1457 .type = .PROGBITS,
1458 .flags = .{ .ALLOC = true, .EXECINSTR = true },
1459 .size = plt_size,
1460 .addralign = plt_align,
1461 .node_align = elf.mf.flags.block_size,
1462 }));
1463 if (plt_sec) assert(elf.si.plt_sec == try elf.addSection(elf.ni.text, .{
1464 .name = ".plt.sec",
1465 .flags = .{ .ALLOC = true, .EXECINSTR = true },
1466 .addralign = plt_align,
1467 .node_align = elf.mf.flags.block_size,
1468 }));
11851469 if (maybe_interp) |interp| {
11861470 const interp_ni = try elf.mf.addLastChildNode(gpa, elf.ni.rodata, .{
11871471 .size = interp.len + 1,
......@@ -1193,8 +1477,8 @@ fn initHeaders(
11931477 elf.phdrs.items[interp_phndx] = interp_ni;
11941478
11951479 const sec_interp_si = try elf.addSection(interp_ni, .{
1196 .type = .PROGBITS,
11971480 .name = ".interp",
1481 .type = .PROGBITS,
11981482 .flags = .{ .ALLOC = true },
11991483 .size = @intCast(interp.len + 1),
12001484 });
......@@ -1203,13 +1487,24 @@ fn initHeaders(
12031487 sec_interp[interp.len] = 0;
12041488 }
12051489 if (have_dynamic_section) {
1206 const dynamic_ni = try elf.mf.addLastChildNode(gpa, elf.ni.data, .{
1490 const dynamic_ni = try elf.mf.addLastChildNode(gpa, elf.ni.data_rel_ro, .{
1491 .alignment = addr_align,
12071492 .moved = true,
12081493 .bubbles_moved = false,
12091494 });
12101495 elf.nodes.appendAssumeCapacity(.{ .segment = dynamic_phndx });
12111496 elf.phdrs.items[dynamic_phndx] = dynamic_ni;
12121497
1498 elf.si.dynstr = try elf.addSection(elf.ni.rodata, .{
1499 .name = ".dynstr",
1500 .type = .STRTAB,
1501 .flags = .{ .ALLOC = true },
1502 .size = 1,
1503 .entsize = 1,
1504 .node_align = elf.mf.flags.block_size,
1505 });
1506 const dynstr_shndx = elf.si.dynstr.shndx(elf);
1507 elf.dynsym.putAssumeCapacityNoClobber(.null, {});
12131508 switch (class) {
12141509 .NONE, _ => unreachable,
12151510 inline else => |ct_class| {
......@@ -1217,7 +1512,10 @@ fn initHeaders(
12171512 elf.si.dynsym = try elf.addSection(elf.ni.rodata, .{
12181513 .name = ".dynsym",
12191514 .type = .DYNSYM,
1515 .flags = .{ .ALLOC = true },
12201516 .size = @sizeOf(Sym) * 1,
1517 .link = @intFromEnum(dynstr_shndx),
1518 .info = 1,
12211519 .addralign = addr_align,
12221520 .entsize = @sizeOf(Sym),
12231521 .node_align = elf.mf.flags.block_size,
......@@ -1237,21 +1535,66 @@ fn initHeaders(
12371535 );
12381536 },
12391537 }
1240 elf.si.dynstr = try elf.addSection(elf.ni.rodata, .{
1241 .name = ".dynstr",
1242 .type = .STRTAB,
1243 .size = 1,
1244 .entsize = 1,
1538 const rela_size: std.elf.Word = switch (class) {
1539 .NONE, _ => unreachable,
1540 inline else => |ct_class| @sizeOf(ct_class.ElfN().Rela),
1541 };
1542 elf.si.got.shndx(elf).get(elf).rela_si = try elf.addSection(elf.ni.rodata, .{
1543 .name = ".rela.dyn",
1544 .type = .RELA,
1545 .flags = .{ .ALLOC = true },
1546 .link = @intFromEnum(elf.si.dynsym.shndx(elf)),
1547 .addralign = addr_align,
1548 .entsize = rela_size,
1549 .node_align = elf.mf.flags.block_size,
1550 });
1551 const got_plt_shndx = elf.si.got_plt.shndx(elf);
1552 got_plt_shndx.get(elf).rela_si = try elf.addSection(elf.ni.rodata, .{
1553 .name = ".rela.plt",
1554 .type = .RELA,
1555 .flags = .{ .ALLOC = true, .INFO_LINK = true },
1556 .link = @intFromEnum(elf.si.dynsym.shndx(elf)),
1557 .info = @intFromEnum(got_plt_shndx),
1558 .addralign = addr_align,
1559 .entsize = rela_size,
12451560 .node_align = elf.mf.flags.block_size,
12461561 });
12471562 elf.si.dynamic = try elf.addSection(dynamic_ni, .{
12481563 .name = ".dynamic",
12491564 .type = .DYNAMIC,
12501565 .flags = .{ .ALLOC = true, .WRITE = true },
1566 .link = @intFromEnum(dynstr_shndx),
1567 .entsize = @intCast(addr_align.toByteUnits() * 2),
12511568 .node_align = addr_align,
12521569 });
1253 try elf.linkSections(elf.si.dynamic, elf.si.dynstr);
1254 try elf.linkSections(elf.si.dynsym, elf.si.dynstr);
1570 switch (machine) {
1571 else => @panic(@tagName(machine)),
1572 .X86_64 => {
1573 @memcpy(elf.si.plt.node(elf).slice(&elf.mf)[0..16], &[16]u8{
1574 0xff, 0x35, 0x00, 0x00, 0x00, 0x00, // push 0x0(%rip)
1575 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *0x0(%rip)
1576 0x0f, 0x1f, 0x40, 0x00, // nopl 0x0(%rax)
1577 });
1578 const plt_sym = elf.si.plt.get(elf);
1579 assert(plt_sym.loc_relocs == .none);
1580 plt_sym.loc_relocs = @enumFromInt(elf.relocs.items.len);
1581 try elf.ensureUnusedRelocCapacity(elf.si.plt, 2);
1582 elf.addRelocAssumeCapacity(
1583 elf.si.plt,
1584 2,
1585 elf.si.got_plt,
1586 8 * 1 - 4,
1587 .{ .X86_64 = .PC32 },
1588 );
1589 elf.addRelocAssumeCapacity(
1590 elf.si.plt,
1591 8,
1592 elf.si.got_plt,
1593 8 * 2 - 4,
1594 .{ .X86_64 = .PC32 },
1595 );
1596 },
1597 }
12551598 }
12561599 if (comp.config.any_non_single_threaded) {
12571600 elf.ni.tls = try elf.mf.addLastChildNode(gpa, elf.ni.rodata, .{
......@@ -1305,7 +1648,8 @@ fn getNode(elf: *const Elf, ni: MappedFile.Node.Index) Node {
13051648}
13061649fn computeNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 {
13071650 const parent_vaddr = parent_vaddr: {
1308 const parent_si = switch (elf.getNode(ni.parent(&elf.mf))) {
1651 const parent_ni = ni.parent(&elf.mf);
1652 const parent_si = switch (elf.getNode(parent_ni)) {
13091653 .file => return 0,
13101654 .ehdr, .shdr => unreachable,
13111655 .segment => |phndx| break :parent_vaddr switch (elf.phdrSlice()) {
......@@ -1444,15 +1788,9 @@ pub fn symtabSlice(elf: *Elf) SymtabSlice {
14441788 const slice = elf.si.symtab.node(elf).slice(&elf.mf);
14451789 return switch (elf.identClass()) {
14461790 .NONE, _ => unreachable,
1447 inline else => |class| @unionInit(
1448 SymtabSlice,
1449 @tagName(class),
1450 @ptrCast(@alignCast(slice[0..std.mem.alignBackwardAnyAlign(
1451 usize,
1452 slice.len,
1453 @sizeOf(class.ElfN().Sym),
1454 )])),
1455 ),
1791 inline else => |class| @unionInit(SymtabSlice, @tagName(class), @ptrCast(@alignCast(
1792 slice[0..std.mem.alignBackwardAnyAlign(usize, slice.len, @sizeOf(class.ElfN().Sym))],
1793 ))),
14561794 };
14571795}
14581796
......@@ -1471,11 +1809,9 @@ pub fn dynsymSlice(elf: *Elf) SymtabSlice {
14711809 const slice = elf.si.dynsym.node(elf).slice(&elf.mf);
14721810 return switch (elf.identClass()) {
14731811 .NONE, _ => unreachable,
1474 inline else => |class| @unionInit(
1475 SymtabSlice,
1476 @tagName(class),
1477 @ptrCast(@alignCast(slice)),
1478 ),
1812 inline else => |class| @unionInit(SymtabSlice, @tagName(class), @ptrCast(@alignCast(
1813 slice[0..std.mem.alignBackwardAnyAlign(usize, slice.len, @sizeOf(class.ElfN().Sym))],
1814 ))),
14791815 };
14801816}
14811817
......@@ -1638,7 +1974,7 @@ pub fn lazySymbol(elf: *Elf, lazy: link.File.LazySymbol) !Symbol.Index {
16381974}
16391975
16401976pub fn loadInput(elf: *Elf, input: link.Input) (std.fs.File.Reader.SizeError ||
1641 std.Io.File.Reader.Error || MappedFile.Error || error{ EndOfStream, LinkFailure })!void {
1977 std.Io.File.Reader.Error || MappedFile.Error || error{ EndOfStream, BadMagic, LinkFailure })!void {
16421978 const io = elf.base.comp.io;
16431979 var buf: [4096]u8 = undefined;
16441980 switch (input) {
......@@ -1678,8 +2014,7 @@ fn loadArchive(elf: *Elf, path: std.Build.Cache.Path, fr: *std.Io.File.Reader) !
16782014 const r = &fr.interface;
16792015
16802016 log.debug("loadArchive({f})", .{path.fmtEscapeString()});
1681 if (!std.mem.eql(u8, try r.take(std.elf.ARMAG.len), std.elf.ARMAG))
1682 return diags.failParse(path, "bad magic", .{});
2017 if (!std.mem.eql(u8, try r.take(std.elf.ARMAG.len), std.elf.ARMAG)) return error.BadMagic;
16832018 var strtab: std.Io.Writer.Allocating = .init(gpa);
16842019 defer strtab.deinit();
16852020 while (r.takeStruct(std.elf.ar_hdr, native_endian)) |header| {
......@@ -1742,8 +2077,9 @@ fn loadObject(
17422077
17432078 const ii: Node.InputIndex = @enumFromInt(elf.inputs.items.len);
17442079 log.debug("loadObject({f}{f})", .{ path.fmtEscapeString(), fmtMemberString(member) });
1745 const ident = try r.peek(std.elf.EI.NIDENT);
1746 if (!std.mem.eql(u8, ident, elf.mf.contents[0..std.elf.EI.NIDENT]))
2080 const ident = try r.peek(std.elf.EI.OSABI);
2081 if (!std.mem.eql(u8, ident[0..std.elf.MAGIC.len], std.elf.MAGIC)) return error.BadMagic;
2082 if (!std.mem.eql(u8, ident[std.elf.MAGIC.len..], elf.mf.contents[std.elf.MAGIC.len..ident.len]))
17472083 return diags.failParse(path, "bad ident", .{});
17482084 try elf.symtab.ensureUnusedCapacity(gpa, 1);
17492085 try elf.inputs.ensureUnusedCapacity(gpa, 1);
......@@ -1853,7 +2189,7 @@ fn loadObject(
18532189 break :strtab strtab;
18542190 };
18552191 defer gpa.free(strtab);
1856 const symnum = std.math.divExact(
2192 const symnum = std.math.sub(u32, std.math.divExact(
18572193 u32,
18582194 @intCast(symtab.shdr.size),
18592195 @intCast(symtab.shdr.entsize),
......@@ -1861,9 +2197,9 @@ fn loadObject(
18612197 path,
18622198 "symtab section size (0x{x}) is not a multiple of entsize (0x{x})",
18632199 .{ symtab.shdr.size, symtab.shdr.entsize },
1864 );
2200 ), 1) catch continue;
18652201 symmap.clearRetainingCapacity();
1866 try symmap.resize(gpa, std.math.sub(u32, symnum, 1) catch continue);
2202 try symmap.resize(gpa, symnum);
18672203 try elf.symtab.ensureUnusedCapacity(gpa, symnum);
18682204 try elf.globals.ensureUnusedCapacity(gpa, symnum);
18692205 try fr.seekTo(fl.offset + symtab.shdr.offset + symtab.shdr.entsize);
......@@ -1874,13 +2210,13 @@ fn loadObject(
18742210 if (input_sym.name >= strtab.len or input_sym.shndx == std.elf.SHN_UNDEF or
18752211 input_sym.shndx >= ehdr.shnum) continue;
18762212 switch (input_sym.info.type) {
1877 else => continue,
2213 .NOTYPE, .OBJECT, .FUNC => {},
18782214 .SECTION => {
18792215 const section = &sections[input_sym.shndx];
18802216 if (input_sym.value == section.shdr.addr) si.* = section.si;
18812217 continue;
18822218 },
1883 .OBJECT, .FUNC => {},
2219 else => continue,
18842220 }
18852221 const name = std.mem.sliceTo(strtab[input_sym.name..], 0);
18862222 const parent_si = sections[input_sym.shndx].si;
......@@ -1935,8 +2271,13 @@ fn loadObject(
19352271 };
19362272 if (rels.shdr.entsize < @sizeOf(Rel))
19372273 return diags.failParse(path, "unsupported rel entsize", .{});
2274
19382275 const loc_sec = &sections[rels.shdr.info];
19392276 if (loc_sec.si == .null) continue;
2277 const loc_sym = loc_sec.si.get(elf);
2278 assert(loc_sym.loc_relocs == .none);
2279 loc_sym.loc_relocs = @enumFromInt(elf.relocs.items.len);
2280
19402281 const relnum = std.math.divExact(
19412282 u32,
19422283 @intCast(rels.shdr.size),
......@@ -1951,7 +2292,7 @@ fn loadObject(
19512292 for (0..relnum) |_| {
19522293 const rel = try r.peekStruct(Rel, target_endian);
19532294 try r.discardAll64(rels.shdr.entsize);
1954 if (rel.info.sym >= symnum) continue;
2295 if (rel.info.sym == 0 or rel.info.sym > symnum) continue;
19552296 const target_si = symmap.items[rel.info.sym - 1];
19562297 if (target_si == .null) continue;
19572298 elf.addRelocAssumeCapacity(
......@@ -1976,7 +2317,8 @@ fn loadDso(elf: *Elf, path: std.Build.Cache.Path, fr: *std.Io.File.Reader) !void
19762317
19772318 log.debug("loadDso({f})", .{path.fmtEscapeString()});
19782319 const ident = try r.peek(std.elf.EI.NIDENT);
1979 if (!std.mem.eql(u8, ident, elf.mf.contents[0..std.elf.EI.NIDENT]))
2320 if (!std.mem.eql(u8, ident[0..std.elf.MAGIC.len], std.elf.MAGIC)) return error.BadMagic;
2321 if (!std.mem.eql(u8, ident[std.elf.MAGIC.len..], elf.mf.contents[std.elf.MAGIC.len..ident.len]))
19802322 return diags.failParse(path, "bad ident", .{});
19812323 const target_endian = elf.targetEndian();
19822324 switch (elf.identClass()) {
......@@ -2056,7 +2398,8 @@ pub fn prelink(elf: *Elf, prog_node: std.Progress.Node) !void {
20562398 };
20572399}
20582400fn prelinkInner(elf: *Elf) !void {
2059 const gpa = elf.base.comp.gpa;
2401 const comp = elf.base.comp;
2402 const gpa = comp.gpa;
20602403 try elf.symtab.ensureUnusedCapacity(gpa, 1);
20612404 try elf.inputs.ensureUnusedCapacity(gpa, 1);
20622405 const zcu_name = try std.fmt.allocPrint(gpa, "{s}_zcu", .{
......@@ -2074,11 +2417,18 @@ fn prelinkInner(elf: *Elf) !void {
20742417 .NONE, _ => unreachable,
20752418 inline else => |ct_class| {
20762419 const ElfN = ct_class.ElfN();
2420 const flags: ElfN.Addr = if (elf.options.z_now) std.elf.DF_BIND_NOW else 0;
2421 const flags_1: ElfN.Addr = if (elf.options.z_now) std.elf.DF_1_NOW else 0;
20772422 const needed_len = elf.needed.count();
2078 const dynamic_len = needed_len + @intFromBool(elf.options.soname != null) + 5;
2423 const dynamic_len = needed_len + @intFromBool(elf.options.soname != null) +
2424 @intFromBool(flags != 0) + @intFromBool(flags_1 != 0) +
2425 @intFromBool(comp.config.output_mode == .Exe) + 12;
20792426 const dynamic_size: u32 = @intCast(@sizeOf(ElfN.Addr) * 2 * dynamic_len);
20802427 const dynamic_ni = elf.si.dynamic.node(elf);
20812428 try dynamic_ni.resize(&elf.mf, gpa, dynamic_size);
2429 switch (elf.shdrPtr(elf.si.dynamic.shndx(elf))) {
2430 inline else => |shdr| elf.targetStore(&shdr.size, dynamic_size),
2431 }
20822432 const sec_dynamic = dynamic_ni.slice(&elf.mf);
20832433 const dynamic_entries: [][2]ElfN.Addr = @ptrCast(@alignCast(sec_dynamic));
20842434 var dynamic_index: usize = 0;
......@@ -2091,14 +2441,41 @@ fn prelinkInner(elf: *Elf) !void {
20912441 dynamic_entries[dynamic_index] = .{ std.elf.DT_SONAME, try elf.string(.dynstr, soname) };
20922442 dynamic_index += 1;
20932443 }
2094 dynamic_entries[dynamic_index..][0..5].* = .{
2095 .{ std.elf.DT_SYMTAB, 0 },
2444 if (flags != 0) {
2445 dynamic_entries[dynamic_index] = .{ std.elf.DT_FLAGS, flags };
2446 dynamic_index += 1;
2447 }
2448 if (flags_1 != 0) {
2449 dynamic_entries[dynamic_index] = .{ std.elf.DT_FLAGS_1, flags_1 };
2450 dynamic_index += 1;
2451 }
2452 if (comp.config.output_mode == .Exe) {
2453 dynamic_entries[dynamic_index] = .{ std.elf.DT_DEBUG, 0 };
2454 dynamic_index += 1;
2455 }
2456 const rela_dyn_si = elf.si.got.shndx(elf).get(elf).rela_si;
2457 const rela_plt_si = elf.si.got_plt.shndx(elf).get(elf).rela_si;
2458 dynamic_entries[dynamic_index..][0..12].* = .{
2459 .{ std.elf.DT_RELA, @intCast(elf.computeNodeVAddr(rela_dyn_si.node(elf))) },
2460 .{ std.elf.DT_RELASZ, elf.targetLoad(
2461 &@field(elf.shdrPtr(rela_dyn_si.shndx(elf)), @tagName(ct_class)).size,
2462 ) },
2463 .{ std.elf.DT_RELAENT, @sizeOf(ElfN.Rela) },
2464 .{ std.elf.DT_JMPREL, @intCast(elf.computeNodeVAddr(rela_plt_si.node(elf))) },
2465 .{ std.elf.DT_PLTRELSZ, elf.targetLoad(
2466 &@field(elf.shdrPtr(rela_plt_si.shndx(elf)), @tagName(ct_class)).size,
2467 ) },
2468 .{ std.elf.DT_PLTGOT, @intCast(elf.computeNodeVAddr(elf.si.got_plt.node(elf))) },
2469 .{ std.elf.DT_PLTREL, std.elf.DT_RELA },
2470 .{ std.elf.DT_SYMTAB, @intCast(elf.computeNodeVAddr(elf.si.dynsym.node(elf))) },
20962471 .{ std.elf.DT_SYMENT, @sizeOf(ElfN.Sym) },
2097 .{ std.elf.DT_STRTAB, 0 },
2098 .{ std.elf.DT_STRSZ, 0 },
2472 .{ std.elf.DT_STRTAB, @intCast(elf.computeNodeVAddr(elf.si.dynstr.node(elf))) },
2473 .{ std.elf.DT_STRSZ, elf.targetLoad(
2474 &@field(elf.shdrPtr(elf.si.dynstr.shndx(elf)), @tagName(ct_class)).size,
2475 ) },
20992476 .{ std.elf.DT_NULL, 0 },
21002477 };
2101 dynamic_index += 5;
2478 dynamic_index += 12;
21022479 assert(dynamic_index == dynamic_len);
21032480 if (elf.targetEndian() != native_endian) for (dynamic_entries) |*dynamic_entry|
21042481 std.mem.byteSwapAllFields(@TypeOf(dynamic_entry.*), dynamic_entry);
......@@ -2106,26 +2483,41 @@ fn prelinkInner(elf: *Elf) !void {
21062483 const dynamic_sym = elf.si.dynamic.get(elf);
21072484 assert(dynamic_sym.loc_relocs == .none);
21082485 dynamic_sym.loc_relocs = @enumFromInt(elf.relocs.items.len);
2109 try elf.addReloc(
2486 try elf.ensureUnusedRelocCapacity(elf.si.dynamic, 5);
2487 elf.addRelocAssumeCapacity(
21102488 elf.si.dynamic,
2111 @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 5) + 1),
2112 elf.si.dynsym,
2489 @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 12) + 1),
2490 rela_dyn_si,
21132491 0,
21142492 .absAddr(elf),
21152493 );
2116 try elf.addReloc(
2494 elf.addRelocAssumeCapacity(
21172495 elf.si.dynamic,
2118 @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 3) + 1),
2119 elf.si.dynstr,
2496 @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 9) + 1),
2497 rela_plt_si,
21202498 0,
21212499 .absAddr(elf),
21222500 );
2123 try elf.addReloc(
2501 elf.addRelocAssumeCapacity(
21242502 elf.si.dynamic,
2125 @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 2) + 1),
2503 @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 7) + 1),
2504 elf.si.got_plt,
2505 0,
2506 .absAddr(elf),
2507 );
2508 elf.addRelocAssumeCapacity(
2509 elf.si.dynamic,
2510 @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 5) + 1),
2511 elf.si.dynsym,
2512 0,
2513 .absAddr(elf),
2514 );
2515 elf.addRelocAssumeCapacity(
2516 elf.si.dynamic,
2517 @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 3) + 1),
21262518 elf.si.dynstr,
21272519 0,
2128 .sizeAddr(elf),
2520 .absAddr(elf),
21292521 );
21302522 },
21312523 };
......@@ -2171,6 +2563,7 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
21712563 addralign: std.mem.Alignment = .@"1",
21722564 entsize: std.elf.Word = 0,
21732565 node_align: std.mem.Alignment = .@"1",
2566 fixed: bool = false,
21742567}) !Symbol.Index {
21752568 switch (opts.type) {
21762569 .NULL => assert(opts.size == 0),
......@@ -2218,8 +2611,9 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
22182611 .REL => elf.ni.file,
22192612 .EXEC, .DYN => segment_ni,
22202613 }, .{
2221 .alignment = opts.addralign.max(opts.node_align),
22222614 .size = opts.size,
2615 .alignment = opts.addralign.max(opts.node_align),
2616 .fixed = opts.fixed,
22232617 .resized = opts.size > 0,
22242618 });
22252619 const si = elf.addSymbolAssumeCapacity();
......@@ -2256,12 +2650,6 @@ fn renameSection(elf: *Elf, si: Symbol.Index, name: []const u8) !void {
22562650 }
22572651}
22582652
2259fn linkSections(elf: *Elf, si: Symbol.Index, link_si: Symbol.Index) !void {
2260 switch (elf.shdrPtr(si.shndx(elf))) {
2261 inline else => |shdr| elf.targetStore(&shdr.link, @intFromEnum(link_si.shndx(elf))),
2262 }
2263}
2264
22652653fn sectionName(elf: *Elf, si: Symbol.Index) [:0]const u8 {
22662654 const name = elf.si.shstrtab.node(elf).slice(&elf.mf)[switch (elf.shdrPtr(si.shndx(elf))) {
22672655 inline else => |shdr| elf.targetLoad(&shdr.name),
......@@ -2288,41 +2676,60 @@ pub fn addReloc(
22882676pub fn ensureUnusedRelocCapacity(elf: *Elf, loc_si: Symbol.Index, len: usize) !void {
22892677 if (len == 0) return;
22902678 const gpa = elf.base.comp.gpa;
2291
22922679 try elf.relocs.ensureUnusedCapacity(gpa, len);
2293 if (elf.ehdrField(.type) != .REL) return;
2294
2295 const shndx = loc_si.shndx(elf);
2296 const sh = shndx.get(elf);
2297 if (sh.rela_si == .null) {
2298 var stack = std.heap.stackFallback(32, gpa);
2299 const allocator = stack.get();
2300
2301 const rela_name = try std.fmt.allocPrint(allocator, ".rela{s}", .{elf.sectionName(sh.si)});
2302 defer allocator.free(rela_name);
2303
2304 const class = elf.identClass();
2305 sh.rela_si = try elf.addSection(.none, .{
2306 .name = rela_name,
2307 .type = .RELA,
2308 .link = @intFromEnum(elf.si.symtab.shndx(elf)),
2309 .info = @intFromEnum(shndx),
2310 .addralign = switch (class) {
2311 .NONE, _ => unreachable,
2312 .@"32" => .@"4",
2313 .@"64" => .@"8",
2314 },
2315 .entsize = switch (class) {
2316 .NONE, _ => unreachable,
2317 inline else => |ct_class| @sizeOf(ct_class.ElfN().Rela),
2318 },
2319 .node_align = elf.mf.flags.block_size,
2320 });
2321 }
2322 const rela_ni = sh.rela_si.node(elf);
2680 const class = elf.identClass();
2681 const rela_si, const rela_len = rela: switch (elf.ehdrField(.type)) {
2682 .NONE, .CORE, _ => unreachable,
2683 .REL => {
2684 const shndx = loc_si.shndx(elf);
2685 const sh = shndx.get(elf);
2686 if (sh.rela_si == .null) {
2687 var stack = std.heap.stackFallback(32, gpa);
2688 const allocator = stack.get();
2689
2690 const rela_name =
2691 try std.fmt.allocPrint(allocator, ".rela{s}", .{elf.sectionName(sh.si)});
2692 defer allocator.free(rela_name);
2693
2694 sh.rela_si = try elf.addSection(.none, .{
2695 .name = rela_name,
2696 .type = .RELA,
2697 .link = @intFromEnum(elf.si.symtab.shndx(elf)),
2698 .info = @intFromEnum(shndx),
2699 .addralign = switch (class) {
2700 .NONE, _ => unreachable,
2701 .@"32" => .@"4",
2702 .@"64" => .@"8",
2703 },
2704 .entsize = switch (class) {
2705 .NONE, _ => unreachable,
2706 inline else => |ct_class| @sizeOf(ct_class.ElfN().Rela),
2707 },
2708 .node_align = elf.mf.flags.block_size,
2709 });
2710 }
2711 break :rela .{ sh.rela_si, len };
2712 },
2713 .EXEC, .DYN => switch (elf.got.tlsld) {
2714 _ => return,
2715 .none => if (elf.si.dynamic != .null) {
2716 try elf.mf.updates.ensureUnusedCapacity(gpa, 1);
2717 const got_ni = elf.si.got.node(elf);
2718 _, const got_node_size = got_ni.location(&elf.mf).resolve(&elf.mf);
2719 const got_size = switch (class) {
2720 .NONE, _ => unreachable,
2721 inline else => |ct_class| (elf.got.len + 2) * @sizeOf(ct_class.ElfN().Addr),
2722 };
2723 if (got_size > got_node_size)
2724 try got_ni.resize(&elf.mf, gpa, got_size +| got_size / MappedFile.growth_factor);
2725 break :rela .{ elf.si.got.shndx(elf).get(elf).rela_si, 1 };
2726 } else return,
2727 },
2728 };
2729 const rela_ni = rela_si.node(elf);
23232730 _, const rela_node_size = rela_ni.location(&elf.mf).resolve(&elf.mf);
2324 const rela_size = switch (elf.shdrPtr(sh.rela_si.shndx(elf))) {
2325 inline else => |shdr| elf.targetLoad(&shdr.size) + elf.targetLoad(&shdr.entsize) * len,
2731 const rela_size = switch (elf.shdrPtr(rela_si.shndx(elf))) {
2732 inline else => |shdr| elf.targetLoad(&shdr.size) + elf.targetLoad(&shdr.entsize) * rela_len,
23262733 };
23272734 if (rela_size > rela_node_size)
23282735 try rela_ni.resize(&elf.mf, gpa, rela_size +| rela_size / MappedFile.growth_factor);
......@@ -2380,7 +2787,59 @@ pub fn addRelocAssumeCapacity(
23802787 },
23812788 }
23822789 },
2383 .EXEC, .DYN => .none,
2790 .EXEC, .DYN => {
2791 switch (elf.ehdrField(.machine)) {
2792 else => |machine| @panic(@tagName(machine)),
2793 .AARCH64, .PPC64, .RISCV => {},
2794 .X86_64 => switch (@"type".X86_64) {
2795 else => {},
2796 .TLSLD => switch (elf.got.tlsld) {
2797 _ => {},
2798 .none => if (elf.si.dynamic != .null) {
2799 const tlsld_index = elf.got.len;
2800 elf.got.tlsld = .wrap(tlsld_index);
2801 elf.got.len = tlsld_index + 2;
2802 const got_addr = got_addr: switch (elf.shdrPtr(elf.si.got.shndx(elf))) {
2803 inline else => |shdr, class| {
2804 const addr_size = @sizeOf(class.ElfN().Addr);
2805 const old_size = addr_size * tlsld_index;
2806 const new_size = old_size + addr_size * 2;
2807 @memset(
2808 elf.si.got.node(elf).slice(&elf.mf)[old_size..new_size],
2809 0,
2810 );
2811 break :got_addr elf.targetLoad(&shdr.addr) + old_size;
2812 },
2813 };
2814 const rela_dyn_si = elf.si.got.shndx(elf).get(elf).rela_si;
2815 const rela_dyn_ni = rela_dyn_si.node(elf);
2816 switch (elf.shdrPtr(rela_dyn_si.shndx(elf))) {
2817 inline else => |shdr, class| {
2818 const Rela = class.ElfN().Rela;
2819 const old_size = elf.targetLoad(&shdr.size);
2820 const new_size = old_size + elf.targetLoad(&shdr.entsize);
2821 elf.targetStore(&shdr.size, new_size);
2822 const rela: *Rela = @ptrCast(@alignCast(rela_dyn_ni
2823 .slice(&elf.mf)[@intCast(old_size)..@intCast(new_size)]));
2824 rela.* = .{
2825 .offset = @intCast(got_addr),
2826 .info = .{
2827 .type = @intFromEnum(std.elf.R_X86_64.DTPMOD64),
2828 .sym = 0,
2829 },
2830 .addend = 0,
2831 };
2832 if (elf.targetEndian() != native_endian)
2833 std.mem.byteSwapAllFields(Rela, rela);
2834 },
2835 }
2836 rela_dyn_ni.resizedAssumeCapacity(&elf.mf);
2837 },
2838 },
2839 },
2840 }
2841 break :index .none;
2842 },
23842843 },
23852844 .offset = offset,
23862845 .addend = addend,
......@@ -2854,10 +3313,12 @@ fn flushInputSection(elf: *Elf, isi: Node.InputSectionIndex) !void {
28543313 var fr = file.reader(comp.io, &.{});
28553314 try fr.seekTo(file_loc.offset);
28563315 var nw: MappedFile.Node.Writer = undefined;
2857 isi.symbol(elf).node(elf).writer(&elf.mf, gpa, &nw);
3316 const si = isi.symbol(elf);
3317 si.node(elf).writer(&elf.mf, gpa, &nw);
28583318 defer nw.deinit();
28593319 if (try nw.interface.sendFileAll(&fr, .limited(@intCast(file_loc.size))) != file_loc.size)
28603320 return error.EndOfStream;
3321 si.applyLocationRelocs(elf);
28613322}
28623323
28633324fn flushFileOffset(elf: *Elf, ni: MappedFile.Node.Index) !void {
......@@ -2902,7 +3363,7 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {
29023363 .NULL, .LOAD => return,
29033364 .DYNAMIC, .INTERP => {},
29043365 .PHDR => @field(elf.ehdrPtr(), @tagName(class)).phoff = ph.offset,
2905 .TLS => {},
3366 .TLS, std.elf.PT.GNU_RELRO => {},
29063367 }
29073368 elf.targetStore(&ph.vaddr, @intCast(elf.computeNodeVAddr(ni)));
29083369 ph.paddr = ph.vaddr;
......@@ -2912,10 +3373,101 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {
29123373 .section => |si| {
29133374 try elf.flushFileOffset(ni);
29143375 const addr = elf.computeNodeVAddr(ni);
2915 switch (elf.shdrPtr(si.shndx(elf))) {
3376 const shndx = si.shndx(elf);
3377 switch (elf.shdrPtr(shndx)) {
29163378 inline else => |shdr, class| {
29173379 const flags = elf.targetLoad(&shdr.flags).shf;
29183380 if (flags.ALLOC) {
3381 if (elf.si.dynamic != .null) {
3382 if (si == elf.si.got) {
3383 const old_addr = elf.targetLoad(&shdr.addr);
3384 const rela_dyn_si = shndx.get(elf).rela_si;
3385 const relas: []class.ElfN().Rela = @ptrCast(@alignCast(
3386 rela_dyn_si.node(elf).slice(&elf.mf)[0..@intCast(
3387 elf.targetLoad(&@field(
3388 elf.shdrPtr(rela_dyn_si.shndx(elf)),
3389 @tagName(class),
3390 ).size),
3391 )],
3392 ));
3393 switch (elf.ehdrField(.machine)) {
3394 else => |machine| @panic(@tagName(machine)),
3395 .AARCH64, .PPC64, .RISCV => {},
3396 .X86_64 => for (relas) |*rela| switch (@as(
3397 std.elf.R_X86_64,
3398 @enumFromInt(elf.targetLoad(&rela.info).type),
3399 )) {
3400 else => |@"type"| @panic(@tagName(@"type")),
3401 .RELATIVE => {},
3402 .GLOB_DAT, .DTPMOD64, .DTPOFF64 => elf.targetStore(
3403 &rela.offset,
3404 @intCast(elf.targetLoad(&rela.offset) - old_addr + addr),
3405 ),
3406 },
3407 }
3408 } else if (si == elf.si.got_plt) {
3409 const target_endian = elf.targetEndian();
3410 const old_addr = elf.targetLoad(&shdr.addr);
3411 const rela_plt_si = shndx.get(elf).rela_si;
3412 const relas: []class.ElfN().Rela = @ptrCast(@alignCast(
3413 rela_plt_si.node(elf).slice(&elf.mf)[0..@intCast(
3414 elf.targetLoad(&@field(
3415 elf.shdrPtr(rela_plt_si.shndx(elf)),
3416 @tagName(class),
3417 ).size),
3418 )],
3419 ));
3420 const plt_sec_slice = elf.si.plt_sec.node(elf).slice(&elf.mf);
3421 switch (elf.ehdrField(.machine)) {
3422 else => |machine| @panic(@tagName(machine)),
3423 .AARCH64, .PPC64, .RISCV => {},
3424 .X86_64 => {
3425 for (relas) |*rela| switch (@as(
3426 std.elf.R_X86_64,
3427 @enumFromInt(elf.targetLoad(&rela.info).type),
3428 )) {
3429 else => |@"type"| @panic(@tagName(@"type")),
3430 .JUMP_SLOT => elf.targetStore(
3431 &rela.offset,
3432 @intCast(elf.targetLoad(&rela.offset) - old_addr + addr),
3433 ),
3434 };
3435 for (0..elf.got.plt.count()) |plt_index| {
3436 const slice = plt_sec_slice[16 * plt_index + 6 ..][0..4];
3437 std.mem.writeInt(
3438 i32,
3439 slice,
3440 @intCast(@as(i64, @bitCast(@as(u64, @bitCast(@as(
3441 i64,
3442 std.mem.readInt(i32, slice, target_endian),
3443 ))) -% old_addr +% addr))),
3444 target_endian,
3445 );
3446 }
3447 },
3448 }
3449 } else if (si == elf.si.plt_sec) {
3450 const target_endian = elf.targetEndian();
3451 const old_addr = elf.targetLoad(&shdr.addr);
3452 const plt_sec_slice = ni.slice(&elf.mf);
3453 switch (elf.ehdrField(.machine)) {
3454 else => |machine| @panic(@tagName(machine)),
3455 .AARCH64, .PPC64, .RISCV => {},
3456 .X86_64 => for (0..elf.got.plt.count()) |plt_index| {
3457 const slice = plt_sec_slice[16 * plt_index + 6 ..][0..4];
3458 std.mem.writeInt(
3459 i32,
3460 slice,
3461 @intCast(@as(i64, @bitCast(@as(u64, @bitCast(@as(
3462 i64,
3463 std.mem.readInt(i32, slice, target_endian),
3464 ))) -% addr +% old_addr))),
3465 target_endian,
3466 );
3467 },
3468 }
3469 }
3470 }
29193471 elf.targetStore(&shdr.addr, @intCast(addr));
29203472 @field(elf.symPtr(si), @tagName(class)).value = shdr.addr;
29213473 }
......@@ -2961,15 +3513,21 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void {
29613513 const ph = &phdr[phndx];
29623514 elf.targetStore(&ph.filesz, @intCast(size));
29633515 if (size > elf.targetLoad(&ph.memsz)) {
2964 const memsz = ni.alignment(&elf.mf).forward(@intCast(size * 4));
2965 elf.targetStore(&ph.memsz, @intCast(memsz));
29663516 switch (elf.targetLoad(&ph.type)) {
29673517 else => unreachable,
29683518 .NULL => if (size > 0) elf.targetStore(&ph.type, .LOAD),
29693519 .LOAD => if (size == 0) elf.targetStore(&ph.type, .NULL),
2970 .DYNAMIC, .INTERP, .PHDR => return,
2971 .TLS => return ni.childrenMoved(elf.base.comp.gpa, &elf.mf),
3520 .DYNAMIC, .INTERP, .PHDR, std.elf.PT.GNU_RELRO => {
3521 elf.targetStore(&ph.memsz, @intCast(size));
3522 return;
3523 },
3524 .TLS => {
3525 elf.targetStore(&ph.memsz, @intCast(size));
3526 return ni.childrenMoved(elf.base.comp.gpa, &elf.mf);
3527 },
29723528 }
3529 const memsz = ni.alignment(&elf.mf).forward(@intCast(size * 4));
3530 elf.targetStore(&ph.memsz, @intCast(memsz));
29733531 var vaddr = elf.targetLoad(&ph.vaddr);
29743532 var new_phndx = phndx;
29753533 for (phdr[phndx + 1 ..], phndx + 1..) |*next_ph, next_phndx| {
......@@ -2999,18 +3557,56 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void {
29993557 },
30003558 },
30013559 .section => |si| switch (elf.shdrPtr(si.shndx(elf))) {
3002 inline else => |shdr| {
3560 inline else => |shdr, class| {
30033561 switch (elf.targetLoad(&shdr.type)) {
30043562 else => unreachable,
30053563 .NULL => if (size > 0) elf.targetStore(&shdr.type, .PROGBITS),
30063564 .PROGBITS => if (size == 0) elf.targetStore(&shdr.type, .NULL),
3007 .SYMTAB, .STRTAB, .RELA, .DYNAMIC, .REL, .DYNSYM => return,
3565 .SYMTAB, .DYNAMIC, .REL, .DYNSYM => return,
3566 .STRTAB => {
3567 if (elf.si.dynamic != .null) {
3568 if (si == elf.si.dynstr) {
3569 const dynamic_entries: [][2]class.ElfN().Addr = @ptrCast(@alignCast(
3570 elf.si.dynamic.node(elf).slice(&elf.mf),
3571 ));
3572 for (dynamic_entries) |*dynamic_entry|
3573 switch (elf.targetLoad(&dynamic_entry[0])) {
3574 else => {},
3575 std.elf.DT_STRSZ => dynamic_entry[1] = shdr.size,
3576 };
3577 }
3578 }
3579 return;
3580 },
3581 .RELA => {
3582 if (elf.si.dynamic != .null) {
3583 if (si == elf.si.got.shndx(elf).get(elf).rela_si) {
3584 const dynamic_entries: [][2]class.ElfN().Addr = @ptrCast(@alignCast(
3585 elf.si.dynamic.node(elf).slice(&elf.mf),
3586 ));
3587 for (dynamic_entries) |*dynamic_entry|
3588 switch (elf.targetLoad(&dynamic_entry[0])) {
3589 else => {},
3590 std.elf.DT_RELASZ => dynamic_entry[1] = shdr.size,
3591 };
3592 } else if (si == elf.si.got_plt.shndx(elf).get(elf).rela_si) {
3593 const dynamic_entries: [][2]class.ElfN().Addr = @ptrCast(@alignCast(
3594 elf.si.dynamic.node(elf).slice(&elf.mf),
3595 ));
3596 for (dynamic_entries) |*dynamic_entry|
3597 switch (elf.targetLoad(&dynamic_entry[0])) {
3598 else => {},
3599 std.elf.DT_PLTRELSZ => dynamic_entry[1] = shdr.size,
3600 };
3601 }
3602 }
3603 return;
3604 },
30083605 }
30093606 elf.targetStore(&shdr.size, @intCast(size));
30103607 },
30113608 },
3012 .input_section => {},
3013 .nav, .uav, .lazy_code, .lazy_const_data => {},
3609 .input_section, .nav, .uav, .lazy_code, .lazy_const_data => {},
30143610 }
30153611}
30163612
......@@ -3070,7 +3666,11 @@ fn updateExportsInner(
30703666 while (try elf.idle(pt.tid)) {}
30713667 const exported_ni = exported_si.node(elf);
30723668 const value, const size, const shndx = switch (elf.symPtr(exported_si)) {
3073 inline else => |exported_sym| .{ exported_sym.value, exported_sym.size, exported_sym.shndx },
3669 inline else => |exported_sym| .{
3670 elf.targetLoad(&exported_sym.value),
3671 exported_sym.size,
3672 exported_sym.shndx,
3673 },
30743674 };
30753675 for (export_indices) |export_index| {
30763676 const @"export" = export_index.ptr(zcu);
......@@ -3093,18 +3693,11 @@ fn updateExportsInner(
30933693 export_si.get(elf).ni = exported_ni;
30943694 switch (elf.symPtr(export_si)) {
30953695 inline else => |export_sym| {
3096 export_sym.value = @intCast(value);
30973696 export_sym.size = @intCast(size);
30983697 export_sym.shndx = shndx;
30993698 },
31003699 }
3101 export_si.applyTargetRelocs(elf);
3102 if (std.mem.eql(u8, name, "_start")) {
3103 elf.entry_hack = exported_si;
3104 switch (elf.ehdrPtr()) {
3105 inline else => |ehdr| ehdr.entry = @intCast(value),
3106 }
3107 }
3700 export_si.flushMoved(elf, value);
31083701 }
31093702}
31103703
src/link/MappedFile.zig+2-2
......@@ -213,7 +213,7 @@ pub const Node = extern struct {
213213 defer node_moved.* = false;
214214 return node_moved.*;
215215 }
216 fn movedAssumeCapacity(ni: Node.Index, mf: *MappedFile) void {
216 pub fn movedAssumeCapacity(ni: Node.Index, mf: *MappedFile) void {
217217 if (ni.hasMoved(mf)) return;
218218 const node = ni.get(mf);
219219 node.flags.moved = true;
......@@ -234,7 +234,7 @@ pub const Node = extern struct {
234234 defer node_resized.* = false;
235235 return node_resized.*;
236236 }
237 fn resizedAssumeCapacity(ni: Node.Index, mf: *MappedFile) void {
237 pub fn resizedAssumeCapacity(ni: Node.Index, mf: *MappedFile) void {
238238 const node = ni.get(mf);
239239 if (node.flags.resized) return;
240240 node.flags.resized = true;