authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2025-11-08 02:45:38-05:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2025-11-09 03:31:26-05:00
log02a241f472bf0c5146ab73c105767178e4822a47
tree92cdffb3d71dbedd3b89de7dbe6c6f94857cf0ff
parentb1d46339b5aa647df2b61ca19694c613aef89c21

Elf2: incrementally update object relocs


1 files changed, 105 insertions(+), 32 deletions(-)

src/link/Elf2.zig+105-32
...@@ -164,7 +164,26 @@ pub const Node = union(enum) {...@@ -164,7 +164,26 @@ pub const Node = union(enum) {
164 }164 }
165};165};
166166
167pub const Section = struct { si: Symbol.Index, rela_si: Symbol.Index };167pub const Section = struct {
168 si: Symbol.Index,
169 rela_si: Symbol.Index,
170 rela_free: RelIndex,
171
172 pub const RelIndex = enum(u32) {
173 none,
174 _,
175
176 pub fn wrap(i: ?u32) RelIndex {
177 return @enumFromInt((i orelse return .none) + 1);
178 }
179 pub fn unwrap(ri: RelIndex) ?u32 {
180 return switch (ri) {
181 .none => null,
182 else => @intFromEnum(ri) - 1,
183 };
184 }
185 };
186};
168187
169pub const StringTable = struct {188pub const StringTable = struct {
170 map: std.HashMapUnmanaged(u32, void, StringTable.Context, std.hash_map.default_max_load_percentage),189 map: std.HashMapUnmanaged(u32, void, StringTable.Context, std.hash_map.default_max_load_percentage),
...@@ -462,7 +481,7 @@ pub const Reloc = extern struct {...@@ -462,7 +481,7 @@ pub const Reloc = extern struct {
462 next: Reloc.Index,481 next: Reloc.Index,
463 loc: Symbol.Index,482 loc: Symbol.Index,
464 target: Symbol.Index,483 target: Symbol.Index,
465 rel_index: u32,484 index: Section.RelIndex,
466 offset: u64,485 offset: u64,
467 addend: i64,486 addend: i64,
468487
...@@ -472,6 +491,16 @@ pub const Reloc = extern struct {...@@ -472,6 +491,16 @@ pub const Reloc = extern struct {
472 RISCV: std.elf.R_RISCV,491 RISCV: std.elf.R_RISCV,
473 PPC64: std.elf.R_PPC64,492 PPC64: std.elf.R_PPC64,
474493
494 pub fn none(elf: *Elf) Reloc.Type {
495 return switch (elf.ehdrField(.machine)) {
496 else => unreachable,
497 .AARCH64 => .{ .AARCH64 = .NONE },
498 .PPC64 => .{ .PPC64 = .NONE },
499 .RISCV => .{ .RISCV = .NONE },
500 .X86_64 => .{ .X86_64 = .NONE },
501 };
502 }
503
475 pub fn absAddr(elf: *Elf) Reloc.Type {504 pub fn absAddr(elf: *Elf) Reloc.Type {
476 return switch (elf.ehdrField(.machine)) {505 return switch (elf.ehdrField(.machine)) {
477 else => unreachable,506 else => unreachable,
...@@ -481,12 +510,35 @@ pub const Reloc = extern struct {...@@ -481,12 +510,35 @@ pub const Reloc = extern struct {
481 .X86_64 => .{ .X86_64 = .@"64" },510 .X86_64 => .{ .X86_64 = .@"64" },
482 };511 };
483 }512 }
513
484 pub fn sizeAddr(elf: *Elf) Reloc.Type {514 pub fn sizeAddr(elf: *Elf) Reloc.Type {
485 return switch (elf.ehdrField(.machine)) {515 return switch (elf.ehdrField(.machine)) {
486 else => unreachable,516 else => unreachable,
487 .X86_64 => .{ .X86_64 = .SIZE64 },517 .X86_64 => .{ .X86_64 = .SIZE64 },
488 };518 };
489 }519 }
520
521 pub fn wrap(int: u32, elf: *Elf) Reloc.Type {
522 return switch (elf.ehdrField(.machine)) {
523 else => unreachable,
524 inline .AARCH64,
525 .PPC64,
526 .RISCV,
527 .X86_64,
528 => |machine| @unionInit(Reloc.Type, @tagName(machine), @enumFromInt(int)),
529 };
530 }
531
532 pub fn unwrap(rt: Reloc.Type, elf: *Elf) u32 {
533 return switch (elf.ehdrField(.machine)) {
534 else => unreachable,
535 inline .AARCH64,
536 .PPC64,
537 .RISCV,
538 .X86_64,
539 => |machine| @intFromEnum(@field(rt, @tagName(machine))),
540 };
541 }
490 };542 };
491543
492 pub const Index = enum(u32) {544 pub const Index = enum(u32) {
...@@ -590,6 +642,33 @@ pub const Reloc = extern struct {...@@ -590,6 +642,33 @@ pub const Reloc = extern struct {
590 .none => {},642 .none => {},
591 else => |next| next.get(elf).prev = reloc.prev,643 else => |next| next.get(elf).prev = reloc.prev,
592 }644 }
645 switch (elf.ehdrField(.type)) {
646 .NONE, .CORE, _ => unreachable,
647 .REL => {
648 const sh = reloc.loc.shndx(elf).get(elf);
649 switch (elf.shdrPtr(sh.rela_si.shndx(elf))) {
650 inline else => |shdr, class| {
651 const Rela = class.ElfN().Rela;
652 const ent_size = elf.targetLoad(&shdr.entsize);
653 const start = ent_size * reloc.index.unwrap().?;
654 const rela_slice = sh.rela_si.node(elf).slice(&elf.mf);
655 const rela: *Rela = @ptrCast(@alignCast(
656 rela_slice[@intCast(start)..][0..@intCast(ent_size)],
657 ));
658 rela.* = .{
659 .offset = @intFromEnum(sh.rela_free),
660 .info = .{
661 .type = @intCast(Reloc.Type.none(elf).unwrap(elf)),
662 .sym = 0,
663 },
664 .addend = 0,
665 };
666 },
667 }
668 sh.rela_free = reloc.index;
669 },
670 .EXEC, .DYN => assert(reloc.index == .none),
671 }
593 reloc.* = undefined;672 reloc.* = undefined;
594 }673 }
595674
...@@ -1036,7 +1115,7 @@ fn initHeaders(...@@ -1036,7 +1115,7 @@ fn initHeaders(
1036 .entsize = 0,1115 .entsize = 0,
1037 };1116 };
1038 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Shdr, sh_undef);1117 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Shdr, sh_undef);
1039 elf.shdrs.appendAssumeCapacity(.{ .si = .null, .rela_si = .null });1118 elf.shdrs.appendAssumeCapacity(.{ .si = .null, .rela_si = .null, .rela_free = .none });
10401119
1041 try elf.symtab.ensureTotalCapacity(gpa, 1);1120 try elf.symtab.ensureTotalCapacity(gpa, 1);
1042 elf.symtab.addOneAssumeCapacity().* = .{1121 elf.symtab.addOneAssumeCapacity().* = .{
...@@ -1880,18 +1959,7 @@ fn loadObject(...@@ -1880,18 +1959,7 @@ fn loadObject(
1880 rel.offset - loc_sec.shdr.addr,1959 rel.offset - loc_sec.shdr.addr,
1881 target_si,1960 target_si,
1882 rel.addend,1961 rel.addend,
1883 switch (elf.ehdrField(.machine)) {1962 .wrap(rel.info.type, elf),
1884 else => unreachable,
1885 inline .AARCH64,
1886 .PPC64,
1887 .RISCV,
1888 .X86_64,
1889 => |machine| @unionInit(
1890 Reloc.Type,
1891 @tagName(machine),
1892 @enumFromInt(rel.info.type),
1893 ),
1894 },
1895 );1963 );
1896 }1964 }
1897 },1965 },
...@@ -2156,7 +2224,7 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {...@@ -2156,7 +2224,7 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
2156 });2224 });
2157 const si = elf.addSymbolAssumeCapacity();2225 const si = elf.addSymbolAssumeCapacity();
2158 elf.nodes.appendAssumeCapacity(.{ .section = si });2226 elf.nodes.appendAssumeCapacity(.{ .section = si });
2159 elf.shdrs.appendAssumeCapacity(.{ .si = si, .rela_si = .null });2227 elf.shdrs.appendAssumeCapacity(.{ .si = si, .rela_si = .null, .rela_free = .none });
2160 si.get(elf).ni = ni;2228 si.get(elf).ni = ni;
2161 const addr = elf.computeNodeVAddr(ni);2229 const addr = elf.computeNodeVAddr(ni);
2162 const offset = ni.fileLocation(&elf.mf, false).offset;2230 const offset = ni.fileLocation(&elf.mf, false).offset;
...@@ -2275,39 +2343,44 @@ pub fn addRelocAssumeCapacity(...@@ -2275,39 +2343,44 @@ pub fn addRelocAssumeCapacity(
2275 .next = target.target_relocs,2343 .next = target.target_relocs,
2276 .loc = loc_si,2344 .loc = loc_si,
2277 .target = target_si,2345 .target = target_si,
2278 .rel_index = switch (elf.ehdrField(.type)) {2346 .index = index: switch (elf.ehdrField(.type)) {
2279 .NONE, .CORE, _ => unreachable,2347 .NONE, .CORE, _ => unreachable,
2280 .REL => rel_index: {2348 .REL => {
2281 const rela_si = loc_si.shndx(elf).get(elf).rela_si;2349 const sh = loc_si.shndx(elf).get(elf);
2282 switch (elf.shdrPtr(rela_si.shndx(elf))) {2350 switch (elf.shdrPtr(sh.rela_si.shndx(elf))) {
2283 inline else => |shdr, class| {2351 inline else => |shdr, class| {
2284 const Rela = class.ElfN().Rela;2352 const Rela = class.ElfN().Rela;
2285 const old_size = elf.targetLoad(&shdr.size);
2286 const ent_size = elf.targetLoad(&shdr.entsize);2353 const ent_size = elf.targetLoad(&shdr.entsize);
2287 const new_size = old_size + ent_size;2354 const rela_slice = sh.rela_si.node(elf).slice(&elf.mf);
2288 elf.targetStore(&shdr.size, @intCast(new_size));2355 const index: u32 = if (sh.rela_free.unwrap()) |index| alloc_index: {
2356 const rela: *Rela = @ptrCast(@alignCast(
2357 rela_slice[@intCast(ent_size * index)..][0..@intCast(ent_size)],
2358 ));
2359 sh.rela_free = @enumFromInt(rela.offset);
2360 break :alloc_index index;
2361 } else alloc_index: {
2362 const old_size = elf.targetLoad(&shdr.size);
2363 const new_size = old_size + ent_size;
2364 elf.targetStore(&shdr.size, @intCast(new_size));
2365 break :alloc_index @intCast(@divExact(old_size, ent_size));
2366 };
2289 const rela: *Rela = @ptrCast(@alignCast(2367 const rela: *Rela = @ptrCast(@alignCast(
2290 rela_si.node(elf).slice(&elf.mf)[@intCast(old_size)..@intCast(new_size)],2368 rela_slice[@intCast(ent_size * index)..][0..@intCast(ent_size)],
2291 ));2369 ));
2292 rela.* = .{2370 rela.* = .{
2293 .offset = @intCast(offset),2371 .offset = @intCast(offset),
2294 .info = .{2372 .info = .{
2295 .type = switch (elf.ehdrField(.machine)) {2373 .type = @intCast(@"type".unwrap(elf)),
2296 else => |machine| @panic(@tagName(machine)),
2297 inline .X86_64, .AARCH64, .RISCV, .PPC64 => |machine| @intCast(
2298 @intFromEnum(@field(@"type", @tagName(machine))),
2299 ),
2300 },
2301 .sym = @intCast(@intFromEnum(target_si)),2374 .sym = @intCast(@intFromEnum(target_si)),
2302 },2375 },
2303 .addend = @intCast(addend),2376 .addend = @intCast(addend),
2304 };2377 };
2305 if (elf.targetEndian() != native_endian) std.mem.byteSwapAllFields(Rela, rela);2378 if (elf.targetEndian() != native_endian) std.mem.byteSwapAllFields(Rela, rela);
2306 break :rel_index @intCast(@divExact(old_size, ent_size));2379 break :index .wrap(index);
2307 },2380 },
2308 }2381 }
2309 },2382 },
2310 .EXEC, .DYN => 0,2383 .EXEC, .DYN => .none,
2311 },2384 },
2312 .offset = offset,2385 .offset = offset,
2313 .addend = addend,2386 .addend = addend,