authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2025-11-11 13:58:06-05:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2025-11-11 14:11:32-05:00
log61a1cefeb30fab3aa82e0d47385ca4f2c4b36c1b
tree5a53f185e35120eb85922978f68ecb34633b652e
parent79a9f3a4180dfe395c816b86a2afc79edc302e65

Elf2: implement PLT


4 files changed, 808 insertions(+), 203 deletions(-)

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+787-193
......@@ -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()) {
......@@ -1630,7 +1974,7 @@ pub fn lazySymbol(elf: *Elf, lazy: link.File.LazySymbol) !Symbol.Index {
16301974}
16311975
16321976pub fn loadInput(elf: *Elf, input: link.Input) (std.fs.File.Reader.SizeError ||
1633 std.Io.File.Reader.Error || MappedFile.Error || error{ EndOfStream, LinkFailure })!void {
1977 std.Io.File.Reader.Error || MappedFile.Error || error{ EndOfStream, BadMagic, LinkFailure })!void {
16341978 const io = elf.base.comp.io;
16351979 var buf: [4096]u8 = undefined;
16361980 switch (input) {
......@@ -1670,8 +2014,7 @@ fn loadArchive(elf: *Elf, path: std.Build.Cache.Path, fr: *std.Io.File.Reader) !
16702014 const r = &fr.interface;
16712015
16722016 log.debug("loadArchive({f})", .{path.fmtEscapeString()});
1673 if (!std.mem.eql(u8, try r.take(std.elf.ARMAG.len), std.elf.ARMAG))
1674 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;
16752018 var strtab: std.Io.Writer.Allocating = .init(gpa);
16762019 defer strtab.deinit();
16772020 while (r.takeStruct(std.elf.ar_hdr, native_endian)) |header| {
......@@ -1734,8 +2077,9 @@ fn loadObject(
17342077
17352078 const ii: Node.InputIndex = @enumFromInt(elf.inputs.items.len);
17362079 log.debug("loadObject({f}{f})", .{ path.fmtEscapeString(), fmtMemberString(member) });
1737 const ident = try r.peek(std.elf.EI.NIDENT);
1738 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]))
17392083 return diags.failParse(path, "bad ident", .{});
17402084 try elf.symtab.ensureUnusedCapacity(gpa, 1);
17412085 try elf.inputs.ensureUnusedCapacity(gpa, 1);
......@@ -1973,7 +2317,8 @@ fn loadDso(elf: *Elf, path: std.Build.Cache.Path, fr: *std.Io.File.Reader) !void
19732317
19742318 log.debug("loadDso({f})", .{path.fmtEscapeString()});
19752319 const ident = try r.peek(std.elf.EI.NIDENT);
1976 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]))
19772322 return diags.failParse(path, "bad ident", .{});
19782323 const target_endian = elf.targetEndian();
19792324 switch (elf.identClass()) {
......@@ -2053,7 +2398,8 @@ pub fn prelink(elf: *Elf, prog_node: std.Progress.Node) !void {
20532398 };
20542399}
20552400fn prelinkInner(elf: *Elf) !void {
2056 const gpa = elf.base.comp.gpa;
2401 const comp = elf.base.comp;
2402 const gpa = comp.gpa;
20572403 try elf.symtab.ensureUnusedCapacity(gpa, 1);
20582404 try elf.inputs.ensureUnusedCapacity(gpa, 1);
20592405 const zcu_name = try std.fmt.allocPrint(gpa, "{s}_zcu", .{
......@@ -2071,11 +2417,18 @@ fn prelinkInner(elf: *Elf) !void {
20712417 .NONE, _ => unreachable,
20722418 inline else => |ct_class| {
20732419 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;
20742422 const needed_len = elf.needed.count();
2075 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;
20762426 const dynamic_size: u32 = @intCast(@sizeOf(ElfN.Addr) * 2 * dynamic_len);
20772427 const dynamic_ni = elf.si.dynamic.node(elf);
20782428 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 }
20792432 const sec_dynamic = dynamic_ni.slice(&elf.mf);
20802433 const dynamic_entries: [][2]ElfN.Addr = @ptrCast(@alignCast(sec_dynamic));
20812434 var dynamic_index: usize = 0;
......@@ -2088,14 +2441,41 @@ fn prelinkInner(elf: *Elf) !void {
20882441 dynamic_entries[dynamic_index] = .{ std.elf.DT_SONAME, try elf.string(.dynstr, soname) };
20892442 dynamic_index += 1;
20902443 }
2091 dynamic_entries[dynamic_index..][0..5].* = .{
2092 .{ 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))) },
20932471 .{ std.elf.DT_SYMENT, @sizeOf(ElfN.Sym) },
2094 .{ std.elf.DT_STRTAB, 0 },
2095 .{ 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 ) },
20962476 .{ std.elf.DT_NULL, 0 },
20972477 };
2098 dynamic_index += 5;
2478 dynamic_index += 12;
20992479 assert(dynamic_index == dynamic_len);
21002480 if (elf.targetEndian() != native_endian) for (dynamic_entries) |*dynamic_entry|
21012481 std.mem.byteSwapAllFields(@TypeOf(dynamic_entry.*), dynamic_entry);
......@@ -2103,26 +2483,41 @@ fn prelinkInner(elf: *Elf) !void {
21032483 const dynamic_sym = elf.si.dynamic.get(elf);
21042484 assert(dynamic_sym.loc_relocs == .none);
21052485 dynamic_sym.loc_relocs = @enumFromInt(elf.relocs.items.len);
2106 try elf.addReloc(
2486 try elf.ensureUnusedRelocCapacity(elf.si.dynamic, 5);
2487 elf.addRelocAssumeCapacity(
21072488 elf.si.dynamic,
2108 @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 5) + 1),
2109 elf.si.dynsym,
2489 @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 12) + 1),
2490 rela_dyn_si,
21102491 0,
21112492 .absAddr(elf),
21122493 );
2113 try elf.addReloc(
2494 elf.addRelocAssumeCapacity(
21142495 elf.si.dynamic,
2115 @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 3) + 1),
2116 elf.si.dynstr,
2496 @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 9) + 1),
2497 rela_plt_si,
21172498 0,
21182499 .absAddr(elf),
21192500 );
2120 try elf.addReloc(
2501 elf.addRelocAssumeCapacity(
21212502 elf.si.dynamic,
2122 @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),
21232518 elf.si.dynstr,
21242519 0,
2125 .sizeAddr(elf),
2520 .absAddr(elf),
21262521 );
21272522 },
21282523 };
......@@ -2168,6 +2563,7 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
21682563 addralign: std.mem.Alignment = .@"1",
21692564 entsize: std.elf.Word = 0,
21702565 node_align: std.mem.Alignment = .@"1",
2566 fixed: bool = false,
21712567}) !Symbol.Index {
21722568 switch (opts.type) {
21732569 .NULL => assert(opts.size == 0),
......@@ -2215,8 +2611,9 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
22152611 .REL => elf.ni.file,
22162612 .EXEC, .DYN => segment_ni,
22172613 }, .{
2218 .alignment = opts.addralign.max(opts.node_align),
22192614 .size = opts.size,
2615 .alignment = opts.addralign.max(opts.node_align),
2616 .fixed = opts.fixed,
22202617 .resized = opts.size > 0,
22212618 });
22222619 const si = elf.addSymbolAssumeCapacity();
......@@ -2253,12 +2650,6 @@ fn renameSection(elf: *Elf, si: Symbol.Index, name: []const u8) !void {
22532650 }
22542651}
22552652
2256fn linkSections(elf: *Elf, si: Symbol.Index, link_si: Symbol.Index) !void {
2257 switch (elf.shdrPtr(si.shndx(elf))) {
2258 inline else => |shdr| elf.targetStore(&shdr.link, @intFromEnum(link_si.shndx(elf))),
2259 }
2260}
2261
22622653fn sectionName(elf: *Elf, si: Symbol.Index) [:0]const u8 {
22632654 const name = elf.si.shstrtab.node(elf).slice(&elf.mf)[switch (elf.shdrPtr(si.shndx(elf))) {
22642655 inline else => |shdr| elf.targetLoad(&shdr.name),
......@@ -2285,41 +2676,60 @@ pub fn addReloc(
22852676pub fn ensureUnusedRelocCapacity(elf: *Elf, loc_si: Symbol.Index, len: usize) !void {
22862677 if (len == 0) return;
22872678 const gpa = elf.base.comp.gpa;
2288
22892679 try elf.relocs.ensureUnusedCapacity(gpa, len);
2290 if (elf.ehdrField(.type) != .REL) return;
2291
2292 const shndx = loc_si.shndx(elf);
2293 const sh = shndx.get(elf);
2294 if (sh.rela_si == .null) {
2295 var stack = std.heap.stackFallback(32, gpa);
2296 const allocator = stack.get();
2297
2298 const rela_name = try std.fmt.allocPrint(allocator, ".rela{s}", .{elf.sectionName(sh.si)});
2299 defer allocator.free(rela_name);
2300
2301 const class = elf.identClass();
2302 sh.rela_si = try elf.addSection(.none, .{
2303 .name = rela_name,
2304 .type = .RELA,
2305 .link = @intFromEnum(elf.si.symtab.shndx(elf)),
2306 .info = @intFromEnum(shndx),
2307 .addralign = switch (class) {
2308 .NONE, _ => unreachable,
2309 .@"32" => .@"4",
2310 .@"64" => .@"8",
2311 },
2312 .entsize = switch (class) {
2313 .NONE, _ => unreachable,
2314 inline else => |ct_class| @sizeOf(ct_class.ElfN().Rela),
2315 },
2316 .node_align = elf.mf.flags.block_size,
2317 });
2318 }
2319 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);
23202730 _, const rela_node_size = rela_ni.location(&elf.mf).resolve(&elf.mf);
2321 const rela_size = switch (elf.shdrPtr(sh.rela_si.shndx(elf))) {
2322 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,
23232733 };
23242734 if (rela_size > rela_node_size)
23252735 try rela_ni.resize(&elf.mf, gpa, rela_size +| rela_size / MappedFile.growth_factor);
......@@ -2377,7 +2787,59 @@ pub fn addRelocAssumeCapacity(
23772787 },
23782788 }
23792789 },
2380 .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 },
23812843 },
23822844 .offset = offset,
23832845 .addend = addend,
......@@ -2901,7 +3363,7 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {
29013363 .NULL, .LOAD => return,
29023364 .DYNAMIC, .INTERP => {},
29033365 .PHDR => @field(elf.ehdrPtr(), @tagName(class)).phoff = ph.offset,
2904 .TLS => {},
3366 .TLS, std.elf.PT.GNU_RELRO => {},
29053367 }
29063368 elf.targetStore(&ph.vaddr, @intCast(elf.computeNodeVAddr(ni)));
29073369 ph.paddr = ph.vaddr;
......@@ -2911,10 +3373,101 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {
29113373 .section => |si| {
29123374 try elf.flushFileOffset(ni);
29133375 const addr = elf.computeNodeVAddr(ni);
2914 switch (elf.shdrPtr(si.shndx(elf))) {
3376 const shndx = si.shndx(elf);
3377 switch (elf.shdrPtr(shndx)) {
29153378 inline else => |shdr, class| {
29163379 const flags = elf.targetLoad(&shdr.flags).shf;
29173380 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 }
29183471 elf.targetStore(&shdr.addr, @intCast(addr));
29193472 @field(elf.symPtr(si), @tagName(class)).value = shdr.addr;
29203473 }
......@@ -2960,15 +3513,21 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void {
29603513 const ph = &phdr[phndx];
29613514 elf.targetStore(&ph.filesz, @intCast(size));
29623515 if (size > elf.targetLoad(&ph.memsz)) {
2963 const memsz = ni.alignment(&elf.mf).forward(@intCast(size * 4));
2964 elf.targetStore(&ph.memsz, @intCast(memsz));
29653516 switch (elf.targetLoad(&ph.type)) {
29663517 else => unreachable,
29673518 .NULL => if (size > 0) elf.targetStore(&ph.type, .LOAD),
29683519 .LOAD => if (size == 0) elf.targetStore(&ph.type, .NULL),
2969 .DYNAMIC, .INTERP, .PHDR => return,
2970 .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 },
29713528 }
3529 const memsz = ni.alignment(&elf.mf).forward(@intCast(size * 4));
3530 elf.targetStore(&ph.memsz, @intCast(memsz));
29723531 var vaddr = elf.targetLoad(&ph.vaddr);
29733532 var new_phndx = phndx;
29743533 for (phdr[phndx + 1 ..], phndx + 1..) |*next_ph, next_phndx| {
......@@ -2998,18 +3557,56 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void {
29983557 },
29993558 },
30003559 .section => |si| switch (elf.shdrPtr(si.shndx(elf))) {
3001 inline else => |shdr| {
3560 inline else => |shdr, class| {
30023561 switch (elf.targetLoad(&shdr.type)) {
30033562 else => unreachable,
30043563 .NULL => if (size > 0) elf.targetStore(&shdr.type, .PROGBITS),
30053564 .PROGBITS => if (size == 0) elf.targetStore(&shdr.type, .NULL),
3006 .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 },
30073605 }
30083606 elf.targetStore(&shdr.size, @intCast(size));
30093607 },
30103608 },
3011 .input_section => {},
3012 .nav, .uav, .lazy_code, .lazy_const_data => {},
3609 .input_section, .nav, .uav, .lazy_code, .lazy_const_data => {},
30133610 }
30143611}
30153612
......@@ -3069,7 +3666,11 @@ fn updateExportsInner(
30693666 while (try elf.idle(pt.tid)) {}
30703667 const exported_ni = exported_si.node(elf);
30713668 const value, const size, const shndx = switch (elf.symPtr(exported_si)) {
3072 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 },
30733674 };
30743675 for (export_indices) |export_index| {
30753676 const @"export" = export_index.ptr(zcu);
......@@ -3092,18 +3693,11 @@ fn updateExportsInner(
30923693 export_si.get(elf).ni = exported_ni;
30933694 switch (elf.symPtr(export_si)) {
30943695 inline else => |export_sym| {
3095 export_sym.value = @intCast(value);
30963696 export_sym.size = @intCast(size);
30973697 export_sym.shndx = shndx;
30983698 },
30993699 }
3100 export_si.applyTargetRelocs(elf);
3101 if (std.mem.eql(u8, name, "_start")) {
3102 elf.entry_hack = exported_si;
3103 switch (elf.ehdrPtr()) {
3104 inline else => |ehdr| ehdr.entry = @intCast(value),
3105 }
3106 }
3700 export_si.flushMoved(elf, value);
31073701 }
31083702}
31093703
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;