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...@@ -881,7 +881,7 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI
881 end_offset - 4,881 end_offset - 4,
882 @enumFromInt(reloc.target.index),882 @enumFromInt(reloc.target.index),
883 reloc.off - 4,883 reloc.off - 4,
884 .{ .X86_64 = .PC32 },884 .{ .X86_64 = .PLT32 },
885 ) else if (emit.bin_file.cast(.macho)) |macho_file| {885 ) else if (emit.bin_file.cast(.macho)) |macho_file| {
886 const zo = macho_file.getZigObject().?;886 const zo = macho_file.getZigObject().?;
887 const atom = zo.symbols.items[emit.atom_index].getAtom(macho_file).?;887 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...@@ -916,7 +916,13 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI
916 .r_info = @as(u64, reloc.target.index) << 32 | @intFromEnum(r_type),916 .r_info = @as(u64, reloc.target.index) << 32 | @intFromEnum(r_type),
917 .r_addend = reloc.off - 4,917 .r_addend = reloc.off - 4,
918 }, zo);918 }, 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}", .{
920 @tagName(reloc.target.type), @tagName(emit.bin_file.tag),926 @tagName(reloc.target.type), @tagName(emit.bin_file.tag),
921 }),927 }),
922 .tlv => if (emit.bin_file.cast(.elf)) |elf_file| {928 .tlv => if (emit.bin_file.cast(.elf)) |elf_file| {
...@@ -933,7 +939,7 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI...@@ -933,7 +939,7 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI
933 end_offset - 4,939 end_offset - 4,
934 @enumFromInt(reloc.target.index),940 @enumFromInt(reloc.target.index),
935 reloc.off,941 reloc.off,
936 .{ .X86_64 = .TPOFF32 },942 .{ .X86_64 = if (emit.pic) .DTPOFF32 else .TPOFF32 },
937 ) else if (emit.bin_file.cast(.macho)) |macho_file| {943 ) else if (emit.bin_file.cast(.macho)) |macho_file| {
938 const zo = macho_file.getZigObject().?;944 const zo = macho_file.getZigObject().?;
939 const atom = zo.symbols.items[emit.atom_index].getAtom(macho_file).?;945 const atom = zo.symbols.items[emit.atom_index].getAtom(macho_file).?;
src/link.zig+10-5
...@@ -1069,7 +1069,7 @@ pub const File = struct {...@@ -1069,7 +1069,7 @@ pub const File = struct {
1069 errdefer archive.file.close();1069 errdefer archive.file.close();
1070 loadInput(base, .{ .archive = archive }) catch |err| switch (err) {1070 loadInput(base, .{ .archive = archive }) catch |err| switch (err) {
1071 error.BadMagic, error.UnexpectedEndOfFile => {1071 error.BadMagic, error.UnexpectedEndOfFile => {
1072 if (base.tag != .elf) return err;1072 if (base.tag != .elf and base.tag != .elf2) return err;
1073 try loadGnuLdScript(base, path, query, archive.file);1073 try loadGnuLdScript(base, path, query, archive.file);
1074 archive.file.close();1074 archive.file.close();
1075 return;1075 return;
...@@ -1091,7 +1091,7 @@ pub const File = struct {...@@ -1091,7 +1091,7 @@ pub const File = struct {
1091 errdefer dso.file.close();1091 errdefer dso.file.close();
1092 loadInput(base, .{ .dso = dso }) catch |err| switch (err) {1092 loadInput(base, .{ .dso = dso }) catch |err| switch (err) {
1093 error.BadMagic, error.UnexpectedEndOfFile => {1093 error.BadMagic, error.UnexpectedEndOfFile => {
1094 if (base.tag != .elf) return err;1094 if (base.tag != .elf and base.tag != .elf2) return err;
1095 try loadGnuLdScript(base, path, query, dso.file);1095 try loadGnuLdScript(base, path, query, dso.file);
1096 dso.file.close();1096 dso.file.close();
1097 return;1097 return;
...@@ -1101,8 +1101,9 @@ pub const File = struct {...@@ -1101,8 +1101,9 @@ pub const File = struct {
1101 }1101 }
11021102
1103 fn loadGnuLdScript(base: *File, path: Path, parent_query: UnresolvedInput.Query, file: fs.File) anyerror!void {1103 fn loadGnuLdScript(base: *File, path: Path, parent_query: UnresolvedInput.Query, file: fs.File) anyerror!void {
1104 const diags = &base.comp.link_diags;1104 const comp = base.comp;
1105 const gpa = base.comp.gpa;1105 const diags = &comp.link_diags;
1106 const gpa = comp.gpa;
1106 const stat = try file.stat();1107 const stat = try file.stat();
1107 const size = std.math.cast(u32, stat.size) orelse return error.FileTooBig;1108 const size = std.math.cast(u32, stat.size) orelse return error.FileTooBig;
1108 const buf = try gpa.alloc(u8, size);1109 const buf = try gpa.alloc(u8, size);
...@@ -1124,7 +1125,11 @@ pub const File = struct {...@@ -1124,7 +1125,11 @@ pub const File = struct {
1124 @panic("TODO");1125 @panic("TODO");
1125 } else {1126 } else {
1126 if (fs.path.isAbsolute(arg.path)) {1127 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 });
1128 switch (Compilation.classifyFileExt(arg.path)) {1133 switch (Compilation.classifyFileExt(arg.path)) {
1129 .shared_library => try openLoadDso(base, new_path, query),1134 .shared_library => try openLoadDso(base, new_path, query),
1130 .object => try openLoadObject(base, new_path),1135 .object => try openLoadObject(base, new_path),
src/link/Elf2.zig+787-193
...@@ -9,8 +9,13 @@ si: Symbol.Known,...@@ -9,8 +9,13 @@ si: Symbol.Known,
9symtab: std.ArrayList(Symbol),9symtab: std.ArrayList(Symbol),
10shstrtab: StringTable,10shstrtab: StringTable,
11strtab: StringTable,11strtab: StringTable,
12dynsym: std.ArrayList(Symbol.Index),12dynsym: std.AutoArrayHashMapUnmanaged(Symbol.Index, void),
13dynstr: StringTable,13dynstr: StringTable,
14got: struct {
15 len: u32,
16 tlsld: GotIndex,
17 plt: std.AutoArrayHashMapUnmanaged(Symbol.Index, void),
18},
14needed: std.AutoArrayHashMapUnmanaged(u32, void),19needed: std.AutoArrayHashMapUnmanaged(u32, void),
15inputs: std.ArrayList(struct {20inputs: std.ArrayList(struct {
16 path: std.Build.Cache.Path,21 path: std.Build.Cache.Path,
...@@ -35,8 +40,6 @@ pending_uavs: std.AutoArrayHashMapUnmanaged(Node.UavMapIndex, struct {...@@ -35,8 +40,6 @@ pending_uavs: std.AutoArrayHashMapUnmanaged(Node.UavMapIndex, struct {
35 src_loc: Zcu.LazySrcLoc,40 src_loc: Zcu.LazySrcLoc,
36}),41}),
37relocs: std.ArrayList(Reloc),42relocs: std.ArrayList(Reloc),
38/// This is hiding actual bugs with global symbols! Reconsider once they are implemented correctly.
39entry_hack: Symbol.Index,
40const_prog_node: std.Progress.Node,43const_prog_node: std.Progress.Node,
41synth_prog_node: std.Progress.Node,44synth_prog_node: std.Progress.Node,
42input_prog_node: std.Progress.Node,45input_prog_node: std.Progress.Node,
...@@ -156,6 +159,7 @@ pub const Node = union(enum) {...@@ -156,6 +159,7 @@ pub const Node = union(enum) {
156 comptime phdr: MappedFile.Node.Index = @enumFromInt(4),159 comptime phdr: MappedFile.Node.Index = @enumFromInt(4),
157 comptime text: MappedFile.Node.Index = @enumFromInt(5),160 comptime text: MappedFile.Node.Index = @enumFromInt(5),
158 comptime data: MappedFile.Node.Index = @enumFromInt(6),161 comptime data: MappedFile.Node.Index = @enumFromInt(6),
162 comptime data_rel_ro: MappedFile.Node.Index = @enumFromInt(7),
159 tls: MappedFile.Node.Index,163 tls: MappedFile.Node.Index,
160 };164 };
161165
...@@ -179,71 +183,12 @@ pub const Section = struct {...@@ -179,71 +183,12 @@ pub const Section = struct {
179 pub fn unwrap(ri: RelIndex) ?u32 {183 pub fn unwrap(ri: RelIndex) ?u32 {
180 return switch (ri) {184 return switch (ri) {
181 .none => null,185 .none => null,
182 else => @intFromEnum(ri) - 1,186 _ => @intFromEnum(ri) - 1,
183 };187 };
184 }188 }
185 };189 };
186};190};
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
247pub const Symbol = struct {192pub const Symbol = struct {
248 ni: MappedFile.Node.Index,193 ni: MappedFile.Node.Index,
249 /// Relocations contained within this symbol194 /// Relocations contained within this symbol
...@@ -260,6 +205,11 @@ pub const Symbol = struct {...@@ -260,6 +205,11 @@ pub const Symbol = struct {
260 rodata,205 rodata,
261 text,206 text,
262 data,207 data,
208 data_rel_ro,
209 got,
210 got_plt,
211 plt,
212 plt_sec,
263 _,213 _,
264214
265 pub fn get(si: Symbol.Index, elf: *Elf) *Symbol {215 pub fn get(si: Symbol.Index, elf: *Elf) *Symbol {
...@@ -333,7 +283,8 @@ pub const Symbol = struct {...@@ -333,7 +283,8 @@ pub const Symbol = struct {
333 shndx: Shndx = .UNDEF,283 shndx: Shndx = .UNDEF,
334 };284 };
335 pub fn init(si: Symbol.Index, elf: *Elf, opts: InitOptions) !void {285 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;
337 const target_endian = elf.targetEndian();288 const target_endian = elf.targetEndian();
338 const name_strtab_entry = try elf.string(.strtab, opts.name);289 const name_strtab_entry = try elf.string(.strtab, opts.name);
339 switch (elf.shdrPtr(elf.si.symtab.shndx(elf))) {290 switch (elf.shdrPtr(elf.si.symtab.shndx(elf))) {
...@@ -373,15 +324,34 @@ pub const Symbol = struct {...@@ -373,15 +324,34 @@ pub const Symbol = struct {
373 @intFromEnum(si) + 1,324 @intFromEnum(si) + 1,
374 )),325 )),
375 }326 }
376 if (opts.bind == .LOCAL or elf.si.dynsym == .null) return;327
377 const dsi = elf.dynsym.items.len;328 if (opts.bind == .LOCAL) return;
378 try elf.dynsym.append(gpa, si);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, {});
379 const name_dynstr_entry = try elf.string(.dynstr, opts.name);349 const name_dynstr_entry = try elf.string(.dynstr, opts.name);
380 switch (elf.shdrPtr(elf.si.dynsym.shndx(elf))) {350 switch (elf.shdrPtr(elf.si.dynsym.shndx(elf))) {
381 inline else => |shdr| {351 inline else => |shdr| {
382 const old_size = elf.targetLoad(&shdr.size);352 const old_size = elf.targetLoad(&shdr.size);
383 const ent_size = elf.targetLoad(&shdr.entsize);353 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();
385 if (new_size > old_size) {355 if (new_size > old_size) {
386 elf.targetStore(&shdr.size, @intCast(new_size));356 elf.targetStore(&shdr.size, @intCast(new_size));
387 const dynsym_ni = elf.si.dynsym.node(elf);357 const dynsym_ni = elf.si.dynsym.node(elf);
...@@ -409,13 +379,136 @@ pub const Symbol = struct {...@@ -409,13 +379,136 @@ pub const Symbol = struct {
409 if (target_endian != native_endian) std.mem.byteSwapAllFields(Sym, dynsym);379 if (target_endian != native_endian) std.mem.byteSwapAllFields(Sym, dynsym);
410 },380 },
411 }381 }
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 }
412 }505 }
413506
414 pub fn flushMoved(si: Symbol.Index, elf: *Elf, value: u64) void {507 pub fn flushMoved(si: Symbol.Index, elf: *Elf, value: u64) void {
415 switch (elf.symPtr(si)) {508 switch (elf.symPtr(si)) {
416 inline else => |sym, class| {509 inline else => |sym, class| {
417 elf.targetStore(&sym.value, @intCast(value));510 elf.targetStore(&sym.value, @intCast(value));
418 if (si == elf.entry_hack) {511 if (si == elf.si.entry) {
419 @branchHint(.unlikely);512 @branchHint(.unlikely);
420 @field(elf.ehdrPtr(), @tagName(class)).entry = sym.value;513 @field(elf.ehdrPtr(), @tagName(class)).entry = sym.value;
421 }514 }
...@@ -464,10 +557,16 @@ pub const Symbol = struct {...@@ -464,10 +557,16 @@ pub const Symbol = struct {
464 comptime rodata: Symbol.Index = .rodata,557 comptime rodata: Symbol.Index = .rodata,
465 comptime text: Symbol.Index = .text,558 comptime text: Symbol.Index = .text,
466 comptime data: Symbol.Index = .data,559 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,
467 dynsym: Symbol.Index,565 dynsym: Symbol.Index,
468 dynstr: Symbol.Index,566 dynstr: Symbol.Index,
469 dynamic: Symbol.Index,567 dynamic: Symbol.Index,
470 tdata: Symbol.Index,568 tdata: Symbol.Index,
569 entry: Symbol.Index,
471 };570 };
472571
473 comptime {572 comptime {
...@@ -475,6 +574,83 @@ pub const Symbol = struct {...@@ -475,6 +574,83 @@ pub const Symbol = struct {
475 }574 }
476};575};
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
478pub const Reloc = extern struct {654pub const Reloc = extern struct {
479 type: Reloc.Type,655 type: Reloc.Type,
480 prev: Reloc.Index,656 prev: Reloc.Index,
...@@ -500,7 +676,6 @@ pub const Reloc = extern struct {...@@ -500,7 +676,6 @@ pub const Reloc = extern struct {
500 .X86_64 => .{ .X86_64 = .NONE },676 .X86_64 => .{ .X86_64 = .NONE },
501 };677 };
502 }678 }
503
504 pub fn absAddr(elf: *Elf) Reloc.Type {679 pub fn absAddr(elf: *Elf) Reloc.Type {
505 return switch (elf.ehdrField(.machine)) {680 return switch (elf.ehdrField(.machine)) {
506 else => unreachable,681 else => unreachable,
...@@ -510,7 +685,6 @@ pub const Reloc = extern struct {...@@ -510,7 +685,6 @@ pub const Reloc = extern struct {
510 .X86_64 => .{ .X86_64 = .@"64" },685 .X86_64 => .{ .X86_64 = .@"64" },
511 };686 };
512 }687 }
513
514 pub fn sizeAddr(elf: *Elf) Reloc.Type {688 pub fn sizeAddr(elf: *Elf) Reloc.Type {
515 return switch (elf.ehdrField(.machine)) {689 return switch (elf.ehdrField(.machine)) {
516 else => unreachable,690 else => unreachable,
...@@ -528,7 +702,6 @@ pub const Reloc = extern struct {...@@ -528,7 +702,6 @@ pub const Reloc = extern struct {
528 => |machine| @unionInit(Reloc.Type, @tagName(machine), @enumFromInt(int)),702 => |machine| @unionInit(Reloc.Type, @tagName(machine), @enumFromInt(int)),
529 };703 };
530 }704 }
531
532 pub fn unwrap(rt: Reloc.Type, elf: *Elf) u32 {705 pub fn unwrap(rt: Reloc.Type, elf: *Elf) u32 {
533 return switch (elf.ehdrField(.machine)) {706 return switch (elf.ehdrField(.machine)) {
534 else => unreachable,707 else => unreachable,
...@@ -558,7 +731,7 @@ pub const Reloc = extern struct {...@@ -558,7 +731,7 @@ pub const Reloc = extern struct {
558 else => |ni| if (ni.hasMoved(&elf.mf)) return,731 else => |ni| if (ni.hasMoved(&elf.mf)) return,
559 }732 }
560 switch (reloc.target.get(elf).ni) {733 switch (reloc.target.get(elf).ni) {
561 .none => return,734 .none => {},
562 else => |ni| if (ni.hasMoved(&elf.mf)) return,735 else => |ni| if (ni.hasMoved(&elf.mf)) return,
563 }736 }
564 const loc_slice = loc_ni.slice(&elf.mf)[@intCast(reloc.offset)..];737 const loc_slice = loc_ni.slice(&elf.mf)[@intCast(reloc.offset)..];
...@@ -568,7 +741,6 @@ pub const Reloc = extern struct {...@@ -568,7 +741,6 @@ pub const Reloc = extern struct {
568 const loc_sym = &symtab[@intFromEnum(reloc.loc)];741 const loc_sym = &symtab[@intFromEnum(reloc.loc)];
569 const loc_shndx = elf.targetLoad(&loc_sym.shndx);742 const loc_shndx = elf.targetLoad(&loc_sym.shndx);
570 assert(loc_shndx != std.elf.SHN_UNDEF);743 assert(loc_shndx != std.elf.SHN_UNDEF);
571 const loc_value = elf.targetLoad(&loc_sym.value) + reloc.offset;
572 const target_sym = &symtab[@intFromEnum(reloc.target)];744 const target_sym = &symtab[@intFromEnum(reloc.target)];
573 const target_value =745 const target_value =
574 elf.targetLoad(&target_sym.value) +% @as(u64, @bitCast(reloc.addend));746 elf.targetLoad(&target_sym.value) +% @as(u64, @bitCast(reloc.addend));
...@@ -582,10 +754,28 @@ pub const Reloc = extern struct {...@@ -582,10 +754,28 @@ pub const Reloc = extern struct {
582 target_value,754 target_value,
583 target_endian,755 target_endian,
584 ),756 ),
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(
586 i32,765 i32,
587 loc_slice[0..4],766 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 ))),
589 target_endian,779 target_endian,
590 ),780 ),
591 .@"32" => std.mem.writeInt(781 .@"32" => std.mem.writeInt(
...@@ -600,6 +790,23 @@ pub const Reloc = extern struct {...@@ -600,6 +790,23 @@ pub const Reloc = extern struct {
600 @intCast(@as(i64, @bitCast(target_value))),790 @intCast(@as(i64, @bitCast(target_value))),
601 target_endian,791 target_endian,
602 ),792 ),
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 ),
603 .TPOFF32 => {810 .TPOFF32 => {
604 const phdr = @field(elf.phdrSlice(), @tagName(class));811 const phdr = @field(elf.phdrSlice(), @tagName(class));
605 const ph = &phdr[elf.getNode(elf.ni.tls).segment];812 const ph = &phdr[elf.getNode(elf.ni.tls).segment];
...@@ -614,13 +821,15 @@ pub const Reloc = extern struct {...@@ -614,13 +821,15 @@ pub const Reloc = extern struct {
614 .SIZE32 => std.mem.writeInt(821 .SIZE32 => std.mem.writeInt(
615 u32,822 u32,
616 loc_slice[0..4],823 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 ),
618 target_endian,827 target_endian,
619 ),828 ),
620 .SIZE64 => std.mem.writeInt(829 .SIZE64 => std.mem.writeInt(
621 u64,830 u64,
622 loc_slice[0..8],831 loc_slice[0..8],
623 @intCast(elf.targetLoad(&target_sym.size)),832 elf.targetLoad(&target_sym.size) +% @as(u64, @bitCast(reloc.addend)),
624 target_endian,833 target_endian,
625 ),834 ),
626 },835 },
...@@ -711,7 +920,7 @@ fn create(...@@ -711,7 +920,7 @@ fn create(
711 .big => .@"2MSB",920 .big => .@"2MSB",
712 };921 };
713 const osabi: std.elf.OSABI = switch (target.os.tag) {922 const osabi: std.elf.OSABI = switch (target.os.tag) {
714 else => .NONE,923 else => if (target.abi.isGnu()) .GNU else .NONE,
715 .freestanding, .other => .STANDALONE,924 .freestanding, .other => .STANDALONE,
716 .netbsd => .NETBSD,925 .netbsd => .NETBSD,
717 .illumos => .SOLARIS,926 .illumos => .SOLARIS,
...@@ -776,6 +985,7 @@ fn create(...@@ -776,6 +985,7 @@ fn create(
776 .dynstr = .null,985 .dynstr = .null,
777 .dynamic = .null,986 .dynamic = .null,
778 .tdata = .null,987 .tdata = .null,
988 .entry = .null,
779 },989 },
780 .symtab = .empty,990 .symtab = .empty,
781 .shstrtab = .{991 .shstrtab = .{
...@@ -788,6 +998,11 @@ fn create(...@@ -788,6 +998,11 @@ fn create(
788 .dynstr = .{998 .dynstr = .{
789 .map = .empty,999 .map = .empty,
790 },1000 },
1001 .got = .{
1002 .len = 0,
1003 .tlsld = .none,
1004 .plt = .empty,
1005 },
791 .needed = .empty,1006 .needed = .empty,
792 .inputs = .empty,1007 .inputs = .empty,
793 .input_sections = .empty,1008 .input_sections = .empty,
...@@ -801,7 +1016,6 @@ fn create(...@@ -801,7 +1016,6 @@ fn create(
801 }),1016 }),
802 .pending_uavs = .empty,1017 .pending_uavs = .empty,
803 .relocs = .empty,1018 .relocs = .empty,
804 .entry_hack = .null,
805 .const_prog_node = .none,1019 .const_prog_node = .none,
806 .synth_prog_node = .none,1020 .synth_prog_node = .none,
807 .input_prog_node = .none,1021 .input_prog_node = .none,
...@@ -823,6 +1037,7 @@ pub fn deinit(elf: *Elf) void {...@@ -823,6 +1037,7 @@ pub fn deinit(elf: *Elf) void {
823 elf.strtab.map.deinit(gpa);1037 elf.strtab.map.deinit(gpa);
824 elf.dynsym.deinit(gpa);1038 elf.dynsym.deinit(gpa);
825 elf.dynstr.map.deinit(gpa);1039 elf.dynstr.map.deinit(gpa);
1040 elf.got.plt.deinit(gpa);
826 elf.needed.deinit(gpa);1041 elf.needed.deinit(gpa);
827 for (elf.inputs.items) |input| if (input.member) |m| gpa.free(m);1042 for (elf.inputs.items) |input| if (input.member) |m| gpa.free(m);
828 elf.inputs.deinit(gpa);1043 elf.inputs.deinit(gpa);
...@@ -873,14 +1088,16 @@ fn initHeaders(...@@ -873,14 +1088,16 @@ fn initHeaders(
873 phnum += 1;1088 phnum += 1;
874 const data_phndx = phnum;1089 const data_phndx = phnum;
875 phnum += 1;1090 phnum += 1;
876 const dynamic_phndx = if (have_dynamic_section) phndx: {1091 const tls_phndx = if (comp.config.any_non_single_threaded) phndx: {
877 defer phnum += 1;1092 defer phnum += 1;
878 break :phndx phnum;1093 break :phndx phnum;
879 } else undefined;1094 } else undefined;
880 const tls_phndx = if (comp.config.any_non_single_threaded) phndx: {1095 const dynamic_phndx = if (have_dynamic_section) phndx: {
881 defer phnum += 1;1096 defer phnum += 1;
882 break :phndx phnum;1097 break :phndx phnum;
883 } else undefined;1098 } else undefined;
1099 const relro_phndx = phnum;
1100 phnum += 1;
8841101
885 const expected_nodes_len = expected_nodes_len: switch (@"type") {1102 const expected_nodes_len = expected_nodes_len: switch (@"type") {
886 .NONE, .CORE, _ => unreachable,1103 .NONE, .CORE, _ => unreachable,
...@@ -888,12 +1105,14 @@ fn initHeaders(...@@ -888,12 +1105,14 @@ fn initHeaders(
888 defer phnum = 0;1105 defer phnum = 0;
889 break :expected_nodes_len 5 + phnum;1106 break :expected_nodes_len 5 + phnum;
890 },1107 },
891 .EXEC, .DYN => break :expected_nodes_len 5 + phnum * 2 +1108 .EXEC, .DYN => break :expected_nodes_len 9 + phnum * 2 +
892 @as(usize, 2) * @intFromBool(have_dynamic_section),1109 @as(usize, 4) * @intFromBool(have_dynamic_section),
893 };1110 };
894 try elf.nodes.ensureTotalCapacity(gpa, expected_nodes_len);1111 try elf.nodes.ensureTotalCapacity(gpa, expected_nodes_len);
895 try elf.shdrs.ensureTotalCapacity(gpa, shnum);1112 try elf.shdrs.ensureTotalCapacity(gpa, shnum);
896 try elf.phdrs.resize(gpa, phnum);1113 try elf.phdrs.resize(gpa, phnum);
1114 try elf.symtab.ensureTotalCapacity(gpa, 1);
1115 if (have_dynamic_section) try elf.dynsym.ensureTotalCapacity(gpa, 1);
897 elf.nodes.appendAssumeCapacity(.file);1116 elf.nodes.appendAssumeCapacity(.file);
8981117
899 switch (class) {1118 switch (class) {
...@@ -976,10 +1195,18 @@ fn initHeaders(...@@ -976,10 +1195,18 @@ fn initHeaders(
976 elf.nodes.appendAssumeCapacity(.{ .segment = data_phndx });1195 elf.nodes.appendAssumeCapacity(.{ .segment = data_phndx });
977 elf.phdrs.items[data_phndx] = elf.ni.data;1196 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
979 break :ph_vaddr switch (elf.ehdrField(.type)) {1206 break :ph_vaddr switch (elf.ehdrField(.type)) {
980 .NONE, .CORE, _ => unreachable,1207 .NONE, .CORE, _ => unreachable,
981 .REL, .DYN => 0,1208 .REL, .DYN => 0,
982 .EXEC => switch (elf.ehdrField(.machine)) {1209 .EXEC => switch (machine) {
983 .@"386" => 0x400000,1210 .@"386" => 0x400000,
984 .AARCH64, .X86_64 => 0x200000,1211 .AARCH64, .X86_64 => 0x200000,
985 .PPC, .PPC64 => 0x10000000,1212 .PPC, .PPC64 => 0x10000000,
...@@ -1070,35 +1297,48 @@ fn initHeaders(...@@ -1070,35 +1297,48 @@ fn initHeaders(
1070 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_data);1297 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_data);
1071 ph_vaddr += @intCast(data_size);1298 ph_vaddr += @intCast(data_size);
10721299
1073 if (have_dynamic_section) {1300 if (comp.config.any_non_single_threaded) {
1074 const ph_dynamic = &phdr[dynamic_phndx];1301 const ph_tls = &phdr[tls_phndx];
1075 ph_dynamic.* = .{1302 ph_tls.* = .{
1076 .type = .DYNAMIC,1303 .type = .TLS,
1077 .offset = 0,1304 .offset = 0,
1078 .vaddr = 0,1305 .vaddr = 0,
1079 .paddr = 0,1306 .paddr = 0,
1080 .filesz = 0,1307 .filesz = 0,
1081 .memsz = 0,1308 .memsz = 0,
1082 .flags = .{ .R = true, .W = true },1309 .flags = .{ .R = true },
1083 .@"align" = @intCast(addr_align.toByteUnits()),1310 .@"align" = @intCast(elf.mf.flags.block_size.toByteUnits()),
1084 };1311 };
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);
1086 }1313 }
10871314
1088 if (comp.config.any_non_single_threaded) {1315 if (have_dynamic_section) {
1089 const ph_tls = &phdr[tls_phndx];1316 const ph_dynamic = &phdr[dynamic_phndx];
1090 ph_tls.* = .{1317 ph_dynamic.* = .{
1091 .type = .TLS,1318 .type = .DYNAMIC,
1092 .offset = 0,1319 .offset = 0,
1093 .vaddr = 0,1320 .vaddr = 0,
1094 .paddr = 0,1321 .paddr = 0,
1095 .filesz = 0,1322 .filesz = 0,
1096 .memsz = 0,1323 .memsz = 0,
1097 .flags = .{ .R = true },1324 .flags = .{ .R = true, .W = true },
1098 .@"align" = @intCast(elf.mf.flags.block_size.toByteUnits()),1325 .@"align" = @intCast(addr_align.toByteUnits()),
1099 };1326 };
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);
1101 }1328 }
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);
1102 }1342 }
11031343
1104 const sh_undef: *ElfN.Shdr = @ptrCast(@alignCast(elf.ni.shdr.slice(&elf.mf)));1344 const sh_undef: *ElfN.Shdr = @ptrCast(@alignCast(elf.ni.shdr.slice(&elf.mf)));
...@@ -1117,7 +1357,6 @@ fn initHeaders(...@@ -1117,7 +1357,6 @@ fn initHeaders(
1117 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Shdr, sh_undef);1357 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Shdr, sh_undef);
1118 elf.shdrs.appendAssumeCapacity(.{ .si = .null, .rela_si = .null, .rela_free = .none });1358 elf.shdrs.appendAssumeCapacity(.{ .si = .null, .rela_si = .null, .rela_free = .none });
11191359
1120 try elf.symtab.ensureTotalCapacity(gpa, 1);
1121 elf.symtab.addOneAssumeCapacity().* = .{1360 elf.symtab.addOneAssumeCapacity().* = .{
1122 .ni = .none,1361 .ni = .none,
1123 .loc_relocs = .none,1362 .loc_relocs = .none,
...@@ -1163,7 +1402,9 @@ fn initHeaders(...@@ -1163,7 +1402,9 @@ fn initHeaders(
1163 .entsize = 1,1402 .entsize = 1,
1164 .node_align = elf.mf.flags.block_size,1403 .node_align = elf.mf.flags.block_size,
1165 }));1404 }));
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 }
1167 elf.si.strtab.node(elf).slice(&elf.mf)[0] = 0;1408 elf.si.strtab.node(elf).slice(&elf.mf)[0] = 0;
11681409
1169 assert(elf.si.rodata == try elf.addSection(elf.ni.rodata, .{1410 assert(elf.si.rodata == try elf.addSection(elf.ni.rodata, .{
...@@ -1181,7 +1422,50 @@ fn initHeaders(...@@ -1181,7 +1422,50 @@ fn initHeaders(
1181 .flags = .{ .WRITE = true, .ALLOC = true },1422 .flags = .{ .WRITE = true, .ALLOC = true },
1182 .addralign = elf.mf.flags.block_size,1423 .addralign = elf.mf.flags.block_size,
1183 }));1424 }));
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 }));
1184 if (@"type" != .REL) {1430 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 }));
1185 if (maybe_interp) |interp| {1469 if (maybe_interp) |interp| {
1186 const interp_ni = try elf.mf.addLastChildNode(gpa, elf.ni.rodata, .{1470 const interp_ni = try elf.mf.addLastChildNode(gpa, elf.ni.rodata, .{
1187 .size = interp.len + 1,1471 .size = interp.len + 1,
...@@ -1193,8 +1477,8 @@ fn initHeaders(...@@ -1193,8 +1477,8 @@ fn initHeaders(
1193 elf.phdrs.items[interp_phndx] = interp_ni;1477 elf.phdrs.items[interp_phndx] = interp_ni;
11941478
1195 const sec_interp_si = try elf.addSection(interp_ni, .{1479 const sec_interp_si = try elf.addSection(interp_ni, .{
1196 .type = .PROGBITS,
1197 .name = ".interp",1480 .name = ".interp",
1481 .type = .PROGBITS,
1198 .flags = .{ .ALLOC = true },1482 .flags = .{ .ALLOC = true },
1199 .size = @intCast(interp.len + 1),1483 .size = @intCast(interp.len + 1),
1200 });1484 });
...@@ -1203,13 +1487,24 @@ fn initHeaders(...@@ -1203,13 +1487,24 @@ fn initHeaders(
1203 sec_interp[interp.len] = 0;1487 sec_interp[interp.len] = 0;
1204 }1488 }
1205 if (have_dynamic_section) {1489 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,
1207 .moved = true,1492 .moved = true,
1208 .bubbles_moved = false,1493 .bubbles_moved = false,
1209 });1494 });
1210 elf.nodes.appendAssumeCapacity(.{ .segment = dynamic_phndx });1495 elf.nodes.appendAssumeCapacity(.{ .segment = dynamic_phndx });
1211 elf.phdrs.items[dynamic_phndx] = dynamic_ni;1496 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, {});
1213 switch (class) {1508 switch (class) {
1214 .NONE, _ => unreachable,1509 .NONE, _ => unreachable,
1215 inline else => |ct_class| {1510 inline else => |ct_class| {
...@@ -1217,7 +1512,10 @@ fn initHeaders(...@@ -1217,7 +1512,10 @@ fn initHeaders(
1217 elf.si.dynsym = try elf.addSection(elf.ni.rodata, .{1512 elf.si.dynsym = try elf.addSection(elf.ni.rodata, .{
1218 .name = ".dynsym",1513 .name = ".dynsym",
1219 .type = .DYNSYM,1514 .type = .DYNSYM,
1515 .flags = .{ .ALLOC = true },
1220 .size = @sizeOf(Sym) * 1,1516 .size = @sizeOf(Sym) * 1,
1517 .link = @intFromEnum(dynstr_shndx),
1518 .info = 1,
1221 .addralign = addr_align,1519 .addralign = addr_align,
1222 .entsize = @sizeOf(Sym),1520 .entsize = @sizeOf(Sym),
1223 .node_align = elf.mf.flags.block_size,1521 .node_align = elf.mf.flags.block_size,
...@@ -1237,21 +1535,66 @@ fn initHeaders(...@@ -1237,21 +1535,66 @@ fn initHeaders(
1237 );1535 );
1238 },1536 },
1239 }1537 }
1240 elf.si.dynstr = try elf.addSection(elf.ni.rodata, .{1538 const rela_size: std.elf.Word = switch (class) {
1241 .name = ".dynstr",1539 .NONE, _ => unreachable,
1242 .type = .STRTAB,1540 inline else => |ct_class| @sizeOf(ct_class.ElfN().Rela),
1243 .size = 1,1541 };
1244 .entsize = 1,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,
1245 .node_align = elf.mf.flags.block_size,1560 .node_align = elf.mf.flags.block_size,
1246 });1561 });
1247 elf.si.dynamic = try elf.addSection(dynamic_ni, .{1562 elf.si.dynamic = try elf.addSection(dynamic_ni, .{
1248 .name = ".dynamic",1563 .name = ".dynamic",
1249 .type = .DYNAMIC,1564 .type = .DYNAMIC,
1250 .flags = .{ .ALLOC = true, .WRITE = true },1565 .flags = .{ .ALLOC = true, .WRITE = true },
1566 .link = @intFromEnum(dynstr_shndx),
1567 .entsize = @intCast(addr_align.toByteUnits() * 2),
1251 .node_align = addr_align,1568 .node_align = addr_align,
1252 });1569 });
1253 try elf.linkSections(elf.si.dynamic, elf.si.dynstr);1570 switch (machine) {
1254 try elf.linkSections(elf.si.dynsym, elf.si.dynstr);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 }
1255 }1598 }
1256 if (comp.config.any_non_single_threaded) {1599 if (comp.config.any_non_single_threaded) {
1257 elf.ni.tls = try elf.mf.addLastChildNode(gpa, elf.ni.rodata, .{1600 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 {...@@ -1305,7 +1648,8 @@ fn getNode(elf: *const Elf, ni: MappedFile.Node.Index) Node {
1305}1648}
1306fn computeNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 {1649fn computeNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 {
1307 const parent_vaddr = parent_vaddr: {1650 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)) {
1309 .file => return 0,1653 .file => return 0,
1310 .ehdr, .shdr => unreachable,1654 .ehdr, .shdr => unreachable,
1311 .segment => |phndx| break :parent_vaddr switch (elf.phdrSlice()) {1655 .segment => |phndx| break :parent_vaddr switch (elf.phdrSlice()) {
...@@ -1630,7 +1974,7 @@ pub fn lazySymbol(elf: *Elf, lazy: link.File.LazySymbol) !Symbol.Index {...@@ -1630,7 +1974,7 @@ pub fn lazySymbol(elf: *Elf, lazy: link.File.LazySymbol) !Symbol.Index {
1630}1974}
16311975
1632pub fn loadInput(elf: *Elf, input: link.Input) (std.fs.File.Reader.SizeError ||1976pub 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 {
1634 const io = elf.base.comp.io;1978 const io = elf.base.comp.io;
1635 var buf: [4096]u8 = undefined;1979 var buf: [4096]u8 = undefined;
1636 switch (input) {1980 switch (input) {
...@@ -1670,8 +2014,7 @@ fn loadArchive(elf: *Elf, path: std.Build.Cache.Path, fr: *std.Io.File.Reader) !...@@ -1670,8 +2014,7 @@ fn loadArchive(elf: *Elf, path: std.Build.Cache.Path, fr: *std.Io.File.Reader) !
1670 const r = &fr.interface;2014 const r = &fr.interface;
16712015
1672 log.debug("loadArchive({f})", .{path.fmtEscapeString()});2016 log.debug("loadArchive({f})", .{path.fmtEscapeString()});
1673 if (!std.mem.eql(u8, try r.take(std.elf.ARMAG.len), std.elf.ARMAG))2017 if (!std.mem.eql(u8, try r.take(std.elf.ARMAG.len), std.elf.ARMAG)) return error.BadMagic;
1674 return diags.failParse(path, "bad magic", .{});
1675 var strtab: std.Io.Writer.Allocating = .init(gpa);2018 var strtab: std.Io.Writer.Allocating = .init(gpa);
1676 defer strtab.deinit();2019 defer strtab.deinit();
1677 while (r.takeStruct(std.elf.ar_hdr, native_endian)) |header| {2020 while (r.takeStruct(std.elf.ar_hdr, native_endian)) |header| {
...@@ -1734,8 +2077,9 @@ fn loadObject(...@@ -1734,8 +2077,9 @@ fn loadObject(
17342077
1735 const ii: Node.InputIndex = @enumFromInt(elf.inputs.items.len);2078 const ii: Node.InputIndex = @enumFromInt(elf.inputs.items.len);
1736 log.debug("loadObject({f}{f})", .{ path.fmtEscapeString(), fmtMemberString(member) });2079 log.debug("loadObject({f}{f})", .{ path.fmtEscapeString(), fmtMemberString(member) });
1737 const ident = try r.peek(std.elf.EI.NIDENT);2080 const ident = try r.peek(std.elf.EI.OSABI);
1738 if (!std.mem.eql(u8, ident, elf.mf.contents[0..std.elf.EI.NIDENT]))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]))
1739 return diags.failParse(path, "bad ident", .{});2083 return diags.failParse(path, "bad ident", .{});
1740 try elf.symtab.ensureUnusedCapacity(gpa, 1);2084 try elf.symtab.ensureUnusedCapacity(gpa, 1);
1741 try elf.inputs.ensureUnusedCapacity(gpa, 1);2085 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...@@ -1973,7 +2317,8 @@ fn loadDso(elf: *Elf, path: std.Build.Cache.Path, fr: *std.Io.File.Reader) !void
19732317
1974 log.debug("loadDso({f})", .{path.fmtEscapeString()});2318 log.debug("loadDso({f})", .{path.fmtEscapeString()});
1975 const ident = try r.peek(std.elf.EI.NIDENT);2319 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]))
1977 return diags.failParse(path, "bad ident", .{});2322 return diags.failParse(path, "bad ident", .{});
1978 const target_endian = elf.targetEndian();2323 const target_endian = elf.targetEndian();
1979 switch (elf.identClass()) {2324 switch (elf.identClass()) {
...@@ -2053,7 +2398,8 @@ pub fn prelink(elf: *Elf, prog_node: std.Progress.Node) !void {...@@ -2053,7 +2398,8 @@ pub fn prelink(elf: *Elf, prog_node: std.Progress.Node) !void {
2053 };2398 };
2054}2399}
2055fn prelinkInner(elf: *Elf) !void {2400fn prelinkInner(elf: *Elf) !void {
2056 const gpa = elf.base.comp.gpa;2401 const comp = elf.base.comp;
2402 const gpa = comp.gpa;
2057 try elf.symtab.ensureUnusedCapacity(gpa, 1);2403 try elf.symtab.ensureUnusedCapacity(gpa, 1);
2058 try elf.inputs.ensureUnusedCapacity(gpa, 1);2404 try elf.inputs.ensureUnusedCapacity(gpa, 1);
2059 const zcu_name = try std.fmt.allocPrint(gpa, "{s}_zcu", .{2405 const zcu_name = try std.fmt.allocPrint(gpa, "{s}_zcu", .{
...@@ -2071,11 +2417,18 @@ fn prelinkInner(elf: *Elf) !void {...@@ -2071,11 +2417,18 @@ fn prelinkInner(elf: *Elf) !void {
2071 .NONE, _ => unreachable,2417 .NONE, _ => unreachable,
2072 inline else => |ct_class| {2418 inline else => |ct_class| {
2073 const ElfN = ct_class.ElfN();2419 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;
2074 const needed_len = elf.needed.count();2422 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;
2076 const dynamic_size: u32 = @intCast(@sizeOf(ElfN.Addr) * 2 * dynamic_len);2426 const dynamic_size: u32 = @intCast(@sizeOf(ElfN.Addr) * 2 * dynamic_len);
2077 const dynamic_ni = elf.si.dynamic.node(elf);2427 const dynamic_ni = elf.si.dynamic.node(elf);
2078 try dynamic_ni.resize(&elf.mf, gpa, dynamic_size);2428 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 }
2079 const sec_dynamic = dynamic_ni.slice(&elf.mf);2432 const sec_dynamic = dynamic_ni.slice(&elf.mf);
2080 const dynamic_entries: [][2]ElfN.Addr = @ptrCast(@alignCast(sec_dynamic));2433 const dynamic_entries: [][2]ElfN.Addr = @ptrCast(@alignCast(sec_dynamic));
2081 var dynamic_index: usize = 0;2434 var dynamic_index: usize = 0;
...@@ -2088,14 +2441,41 @@ fn prelinkInner(elf: *Elf) !void {...@@ -2088,14 +2441,41 @@ fn prelinkInner(elf: *Elf) !void {
2088 dynamic_entries[dynamic_index] = .{ std.elf.DT_SONAME, try elf.string(.dynstr, soname) };2441 dynamic_entries[dynamic_index] = .{ std.elf.DT_SONAME, try elf.string(.dynstr, soname) };
2089 dynamic_index += 1;2442 dynamic_index += 1;
2090 }2443 }
2091 dynamic_entries[dynamic_index..][0..5].* = .{2444 if (flags != 0) {
2092 .{ std.elf.DT_SYMTAB, 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))) },
2093 .{ std.elf.DT_SYMENT, @sizeOf(ElfN.Sym) },2471 .{ std.elf.DT_SYMENT, @sizeOf(ElfN.Sym) },
2094 .{ std.elf.DT_STRTAB, 0 },2472 .{ std.elf.DT_STRTAB, @intCast(elf.computeNodeVAddr(elf.si.dynstr.node(elf))) },
2095 .{ std.elf.DT_STRSZ, 0 },2473 .{ std.elf.DT_STRSZ, elf.targetLoad(
2474 &@field(elf.shdrPtr(elf.si.dynstr.shndx(elf)), @tagName(ct_class)).size,
2475 ) },
2096 .{ std.elf.DT_NULL, 0 },2476 .{ std.elf.DT_NULL, 0 },
2097 };2477 };
2098 dynamic_index += 5;2478 dynamic_index += 12;
2099 assert(dynamic_index == dynamic_len);2479 assert(dynamic_index == dynamic_len);
2100 if (elf.targetEndian() != native_endian) for (dynamic_entries) |*dynamic_entry|2480 if (elf.targetEndian() != native_endian) for (dynamic_entries) |*dynamic_entry|
2101 std.mem.byteSwapAllFields(@TypeOf(dynamic_entry.*), dynamic_entry);2481 std.mem.byteSwapAllFields(@TypeOf(dynamic_entry.*), dynamic_entry);
...@@ -2103,26 +2483,41 @@ fn prelinkInner(elf: *Elf) !void {...@@ -2103,26 +2483,41 @@ fn prelinkInner(elf: *Elf) !void {
2103 const dynamic_sym = elf.si.dynamic.get(elf);2483 const dynamic_sym = elf.si.dynamic.get(elf);
2104 assert(dynamic_sym.loc_relocs == .none);2484 assert(dynamic_sym.loc_relocs == .none);
2105 dynamic_sym.loc_relocs = @enumFromInt(elf.relocs.items.len);2485 dynamic_sym.loc_relocs = @enumFromInt(elf.relocs.items.len);
2106 try elf.addReloc(2486 try elf.ensureUnusedRelocCapacity(elf.si.dynamic, 5);
2487 elf.addRelocAssumeCapacity(
2107 elf.si.dynamic,2488 elf.si.dynamic,
2108 @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 5) + 1),2489 @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 12) + 1),
2109 elf.si.dynsym,2490 rela_dyn_si,
2110 0,2491 0,
2111 .absAddr(elf),2492 .absAddr(elf),
2112 );2493 );
2113 try elf.addReloc(2494 elf.addRelocAssumeCapacity(
2114 elf.si.dynamic,2495 elf.si.dynamic,
2115 @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 3) + 1),2496 @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 9) + 1),
2116 elf.si.dynstr,2497 rela_plt_si,
2117 0,2498 0,
2118 .absAddr(elf),2499 .absAddr(elf),
2119 );2500 );
2120 try elf.addReloc(2501 elf.addRelocAssumeCapacity(
2121 elf.si.dynamic,2502 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),
2123 elf.si.dynstr,2518 elf.si.dynstr,
2124 0,2519 0,
2125 .sizeAddr(elf),2520 .absAddr(elf),
2126 );2521 );
2127 },2522 },
2128 };2523 };
...@@ -2168,6 +2563,7 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {...@@ -2168,6 +2563,7 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
2168 addralign: std.mem.Alignment = .@"1",2563 addralign: std.mem.Alignment = .@"1",
2169 entsize: std.elf.Word = 0,2564 entsize: std.elf.Word = 0,
2170 node_align: std.mem.Alignment = .@"1",2565 node_align: std.mem.Alignment = .@"1",
2566 fixed: bool = false,
2171}) !Symbol.Index {2567}) !Symbol.Index {
2172 switch (opts.type) {2568 switch (opts.type) {
2173 .NULL => assert(opts.size == 0),2569 .NULL => assert(opts.size == 0),
...@@ -2215,8 +2611,9 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {...@@ -2215,8 +2611,9 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
2215 .REL => elf.ni.file,2611 .REL => elf.ni.file,
2216 .EXEC, .DYN => segment_ni,2612 .EXEC, .DYN => segment_ni,
2217 }, .{2613 }, .{
2218 .alignment = opts.addralign.max(opts.node_align),
2219 .size = opts.size,2614 .size = opts.size,
2615 .alignment = opts.addralign.max(opts.node_align),
2616 .fixed = opts.fixed,
2220 .resized = opts.size > 0,2617 .resized = opts.size > 0,
2221 });2618 });
2222 const si = elf.addSymbolAssumeCapacity();2619 const si = elf.addSymbolAssumeCapacity();
...@@ -2253,12 +2650,6 @@ fn renameSection(elf: *Elf, si: Symbol.Index, name: []const u8) !void {...@@ -2253,12 +2650,6 @@ fn renameSection(elf: *Elf, si: Symbol.Index, name: []const u8) !void {
2253 }2650 }
2254}2651}
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
2262fn sectionName(elf: *Elf, si: Symbol.Index) [:0]const u8 {2653fn sectionName(elf: *Elf, si: Symbol.Index) [:0]const u8 {
2263 const name = elf.si.shstrtab.node(elf).slice(&elf.mf)[switch (elf.shdrPtr(si.shndx(elf))) {2654 const name = elf.si.shstrtab.node(elf).slice(&elf.mf)[switch (elf.shdrPtr(si.shndx(elf))) {
2264 inline else => |shdr| elf.targetLoad(&shdr.name),2655 inline else => |shdr| elf.targetLoad(&shdr.name),
...@@ -2285,41 +2676,60 @@ pub fn addReloc(...@@ -2285,41 +2676,60 @@ pub fn addReloc(
2285pub fn ensureUnusedRelocCapacity(elf: *Elf, loc_si: Symbol.Index, len: usize) !void {2676pub fn ensureUnusedRelocCapacity(elf: *Elf, loc_si: Symbol.Index, len: usize) !void {
2286 if (len == 0) return;2677 if (len == 0) return;
2287 const gpa = elf.base.comp.gpa;2678 const gpa = elf.base.comp.gpa;
2288
2289 try elf.relocs.ensureUnusedCapacity(gpa, len);2679 try elf.relocs.ensureUnusedCapacity(gpa, len);
2290 if (elf.ehdrField(.type) != .REL) return;2680 const class = elf.identClass();
22912681 const rela_si, const rela_len = rela: switch (elf.ehdrField(.type)) {
2292 const shndx = loc_si.shndx(elf);2682 .NONE, .CORE, _ => unreachable,
2293 const sh = shndx.get(elf);2683 .REL => {
2294 if (sh.rela_si == .null) {2684 const shndx = loc_si.shndx(elf);
2295 var stack = std.heap.stackFallback(32, gpa);2685 const sh = shndx.get(elf);
2296 const allocator = stack.get();2686 if (sh.rela_si == .null) {
22972687 var stack = std.heap.stackFallback(32, gpa);
2298 const rela_name = try std.fmt.allocPrint(allocator, ".rela{s}", .{elf.sectionName(sh.si)});2688 const allocator = stack.get();
2299 defer allocator.free(rela_name);2689
23002690 const rela_name =
2301 const class = elf.identClass();2691 try std.fmt.allocPrint(allocator, ".rela{s}", .{elf.sectionName(sh.si)});
2302 sh.rela_si = try elf.addSection(.none, .{2692 defer allocator.free(rela_name);
2303 .name = rela_name,2693
2304 .type = .RELA,2694 sh.rela_si = try elf.addSection(.none, .{
2305 .link = @intFromEnum(elf.si.symtab.shndx(elf)),2695 .name = rela_name,
2306 .info = @intFromEnum(shndx),2696 .type = .RELA,
2307 .addralign = switch (class) {2697 .link = @intFromEnum(elf.si.symtab.shndx(elf)),
2308 .NONE, _ => unreachable,2698 .info = @intFromEnum(shndx),
2309 .@"32" => .@"4",2699 .addralign = switch (class) {
2310 .@"64" => .@"8",2700 .NONE, _ => unreachable,
2311 },2701 .@"32" => .@"4",
2312 .entsize = switch (class) {2702 .@"64" => .@"8",
2313 .NONE, _ => unreachable,2703 },
2314 inline else => |ct_class| @sizeOf(ct_class.ElfN().Rela),2704 .entsize = switch (class) {
2315 },2705 .NONE, _ => unreachable,
2316 .node_align = elf.mf.flags.block_size,2706 inline else => |ct_class| @sizeOf(ct_class.ElfN().Rela),
2317 });2707 },
2318 }2708 .node_align = elf.mf.flags.block_size,
2319 const rela_ni = sh.rela_si.node(elf);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);
2320 _, const rela_node_size = rela_ni.location(&elf.mf).resolve(&elf.mf);2730 _, const rela_node_size = rela_ni.location(&elf.mf).resolve(&elf.mf);
2321 const rela_size = switch (elf.shdrPtr(sh.rela_si.shndx(elf))) {2731 const rela_size = switch (elf.shdrPtr(rela_si.shndx(elf))) {
2322 inline else => |shdr| elf.targetLoad(&shdr.size) + elf.targetLoad(&shdr.entsize) * len,2732 inline else => |shdr| elf.targetLoad(&shdr.size) + elf.targetLoad(&shdr.entsize) * rela_len,
2323 };2733 };
2324 if (rela_size > rela_node_size)2734 if (rela_size > rela_node_size)
2325 try rela_ni.resize(&elf.mf, gpa, rela_size +| rela_size / MappedFile.growth_factor);2735 try rela_ni.resize(&elf.mf, gpa, rela_size +| rela_size / MappedFile.growth_factor);
...@@ -2377,7 +2787,59 @@ pub fn addRelocAssumeCapacity(...@@ -2377,7 +2787,59 @@ pub fn addRelocAssumeCapacity(
2377 },2787 },
2378 }2788 }
2379 },2789 },
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 },
2381 },2843 },
2382 .offset = offset,2844 .offset = offset,
2383 .addend = addend,2845 .addend = addend,
...@@ -2901,7 +3363,7 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {...@@ -2901,7 +3363,7 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {
2901 .NULL, .LOAD => return,3363 .NULL, .LOAD => return,
2902 .DYNAMIC, .INTERP => {},3364 .DYNAMIC, .INTERP => {},
2903 .PHDR => @field(elf.ehdrPtr(), @tagName(class)).phoff = ph.offset,3365 .PHDR => @field(elf.ehdrPtr(), @tagName(class)).phoff = ph.offset,
2904 .TLS => {},3366 .TLS, std.elf.PT.GNU_RELRO => {},
2905 }3367 }
2906 elf.targetStore(&ph.vaddr, @intCast(elf.computeNodeVAddr(ni)));3368 elf.targetStore(&ph.vaddr, @intCast(elf.computeNodeVAddr(ni)));
2907 ph.paddr = ph.vaddr;3369 ph.paddr = ph.vaddr;
...@@ -2911,10 +3373,101 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {...@@ -2911,10 +3373,101 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {
2911 .section => |si| {3373 .section => |si| {
2912 try elf.flushFileOffset(ni);3374 try elf.flushFileOffset(ni);
2913 const addr = elf.computeNodeVAddr(ni);3375 const addr = elf.computeNodeVAddr(ni);
2914 switch (elf.shdrPtr(si.shndx(elf))) {3376 const shndx = si.shndx(elf);
3377 switch (elf.shdrPtr(shndx)) {
2915 inline else => |shdr, class| {3378 inline else => |shdr, class| {
2916 const flags = elf.targetLoad(&shdr.flags).shf;3379 const flags = elf.targetLoad(&shdr.flags).shf;
2917 if (flags.ALLOC) {3380 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 }
2918 elf.targetStore(&shdr.addr, @intCast(addr));3471 elf.targetStore(&shdr.addr, @intCast(addr));
2919 @field(elf.symPtr(si), @tagName(class)).value = shdr.addr;3472 @field(elf.symPtr(si), @tagName(class)).value = shdr.addr;
2920 }3473 }
...@@ -2960,15 +3513,21 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void {...@@ -2960,15 +3513,21 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void {
2960 const ph = &phdr[phndx];3513 const ph = &phdr[phndx];
2961 elf.targetStore(&ph.filesz, @intCast(size));3514 elf.targetStore(&ph.filesz, @intCast(size));
2962 if (size > elf.targetLoad(&ph.memsz)) {3515 if (size > elf.targetLoad(&ph.memsz)) {
2963 const memsz = ni.alignment(&elf.mf).forward(@intCast(size * 4));
2964 elf.targetStore(&ph.memsz, @intCast(memsz));
2965 switch (elf.targetLoad(&ph.type)) {3516 switch (elf.targetLoad(&ph.type)) {
2966 else => unreachable,3517 else => unreachable,
2967 .NULL => if (size > 0) elf.targetStore(&ph.type, .LOAD),3518 .NULL => if (size > 0) elf.targetStore(&ph.type, .LOAD),
2968 .LOAD => if (size == 0) elf.targetStore(&ph.type, .NULL),3519 .LOAD => if (size == 0) elf.targetStore(&ph.type, .NULL),
2969 .DYNAMIC, .INTERP, .PHDR => return,3520 .DYNAMIC, .INTERP, .PHDR, std.elf.PT.GNU_RELRO => {
2970 .TLS => return ni.childrenMoved(elf.base.comp.gpa, &elf.mf),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 },
2971 }3528 }
3529 const memsz = ni.alignment(&elf.mf).forward(@intCast(size * 4));
3530 elf.targetStore(&ph.memsz, @intCast(memsz));
2972 var vaddr = elf.targetLoad(&ph.vaddr);3531 var vaddr = elf.targetLoad(&ph.vaddr);
2973 var new_phndx = phndx;3532 var new_phndx = phndx;
2974 for (phdr[phndx + 1 ..], phndx + 1..) |*next_ph, next_phndx| {3533 for (phdr[phndx + 1 ..], phndx + 1..) |*next_ph, next_phndx| {
...@@ -2998,18 +3557,56 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void {...@@ -2998,18 +3557,56 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void {
2998 },3557 },
2999 },3558 },
3000 .section => |si| switch (elf.shdrPtr(si.shndx(elf))) {3559 .section => |si| switch (elf.shdrPtr(si.shndx(elf))) {
3001 inline else => |shdr| {3560 inline else => |shdr, class| {
3002 switch (elf.targetLoad(&shdr.type)) {3561 switch (elf.targetLoad(&shdr.type)) {
3003 else => unreachable,3562 else => unreachable,
3004 .NULL => if (size > 0) elf.targetStore(&shdr.type, .PROGBITS),3563 .NULL => if (size > 0) elf.targetStore(&shdr.type, .PROGBITS),
3005 .PROGBITS => if (size == 0) elf.targetStore(&shdr.type, .NULL),3564 .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 },
3007 }3605 }
3008 elf.targetStore(&shdr.size, @intCast(size));3606 elf.targetStore(&shdr.size, @intCast(size));
3009 },3607 },
3010 },3608 },
3011 .input_section => {},3609 .input_section, .nav, .uav, .lazy_code, .lazy_const_data => {},
3012 .nav, .uav, .lazy_code, .lazy_const_data => {},
3013 }3610 }
3014}3611}
30153612
...@@ -3069,7 +3666,11 @@ fn updateExportsInner(...@@ -3069,7 +3666,11 @@ fn updateExportsInner(
3069 while (try elf.idle(pt.tid)) {}3666 while (try elf.idle(pt.tid)) {}
3070 const exported_ni = exported_si.node(elf);3667 const exported_ni = exported_si.node(elf);
3071 const value, const size, const shndx = switch (elf.symPtr(exported_si)) {3668 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 },
3073 };3674 };
3074 for (export_indices) |export_index| {3675 for (export_indices) |export_index| {
3075 const @"export" = export_index.ptr(zcu);3676 const @"export" = export_index.ptr(zcu);
...@@ -3092,18 +3693,11 @@ fn updateExportsInner(...@@ -3092,18 +3693,11 @@ fn updateExportsInner(
3092 export_si.get(elf).ni = exported_ni;3693 export_si.get(elf).ni = exported_ni;
3093 switch (elf.symPtr(export_si)) {3694 switch (elf.symPtr(export_si)) {
3094 inline else => |export_sym| {3695 inline else => |export_sym| {
3095 export_sym.value = @intCast(value);
3096 export_sym.size = @intCast(size);3696 export_sym.size = @intCast(size);
3097 export_sym.shndx = shndx;3697 export_sym.shndx = shndx;
3098 },3698 },
3099 }3699 }
3100 export_si.applyTargetRelocs(elf);3700 export_si.flushMoved(elf, value);
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 }
3107 }3701 }
3108}3702}
31093703
src/link/MappedFile.zig+2-2
...@@ -213,7 +213,7 @@ pub const Node = extern struct {...@@ -213,7 +213,7 @@ pub const Node = extern struct {
213 defer node_moved.* = false;213 defer node_moved.* = false;
214 return node_moved.*;214 return node_moved.*;
215 }215 }
216 fn movedAssumeCapacity(ni: Node.Index, mf: *MappedFile) void {216 pub fn movedAssumeCapacity(ni: Node.Index, mf: *MappedFile) void {
217 if (ni.hasMoved(mf)) return;217 if (ni.hasMoved(mf)) return;
218 const node = ni.get(mf);218 const node = ni.get(mf);
219 node.flags.moved = true;219 node.flags.moved = true;
...@@ -234,7 +234,7 @@ pub const Node = extern struct {...@@ -234,7 +234,7 @@ pub const Node = extern struct {
234 defer node_resized.* = false;234 defer node_resized.* = false;
235 return node_resized.*;235 return node_resized.*;
236 }236 }
237 fn resizedAssumeCapacity(ni: Node.Index, mf: *MappedFile) void {237 pub fn resizedAssumeCapacity(ni: Node.Index, mf: *MappedFile) void {
238 const node = ni.get(mf);238 const node = ni.get(mf);
239 if (node.flags.resized) return;239 if (node.flags.resized) return;
240 node.flags.resized = true;240 node.flags.resized = true;