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) {
164164 }
165165};
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
169188pub const StringTable = struct {
170189 map: std.HashMapUnmanaged(u32, void, StringTable.Context, std.hash_map.default_max_load_percentage),
......@@ -462,7 +481,7 @@ pub const Reloc = extern struct {
462481 next: Reloc.Index,
463482 loc: Symbol.Index,
464483 target: Symbol.Index,
465 rel_index: u32,
484 index: Section.RelIndex,
466485 offset: u64,
467486 addend: i64,
468487
......@@ -472,6 +491,16 @@ pub const Reloc = extern struct {
472491 RISCV: std.elf.R_RISCV,
473492 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
475504 pub fn absAddr(elf: *Elf) Reloc.Type {
476505 return switch (elf.ehdrField(.machine)) {
477506 else => unreachable,
......@@ -481,12 +510,35 @@ pub const Reloc = extern struct {
481510 .X86_64 => .{ .X86_64 = .@"64" },
482511 };
483512 }
513
484514 pub fn sizeAddr(elf: *Elf) Reloc.Type {
485515 return switch (elf.ehdrField(.machine)) {
486516 else => unreachable,
487517 .X86_64 => .{ .X86_64 = .SIZE64 },
488518 };
489519 }
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 }
490542 };
491543
492544 pub const Index = enum(u32) {
......@@ -590,6 +642,33 @@ pub const Reloc = extern struct {
590642 .none => {},
591643 else => |next| next.get(elf).prev = reloc.prev,
592644 }
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 }
593672 reloc.* = undefined;
594673 }
595674
......@@ -1036,7 +1115,7 @@ fn initHeaders(
10361115 .entsize = 0,
10371116 };
10381117 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
10411120 try elf.symtab.ensureTotalCapacity(gpa, 1);
10421121 elf.symtab.addOneAssumeCapacity().* = .{
......@@ -1880,18 +1959,7 @@ fn loadObject(
18801959 rel.offset - loc_sec.shdr.addr,
18811960 target_si,
18821961 rel.addend,
1883 switch (elf.ehdrField(.machine)) {
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 },
1962 .wrap(rel.info.type, elf),
18951963 );
18961964 }
18971965 },
......@@ -2156,7 +2224,7 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
21562224 });
21572225 const si = elf.addSymbolAssumeCapacity();
21582226 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 });
21602228 si.get(elf).ni = ni;
21612229 const addr = elf.computeNodeVAddr(ni);
21622230 const offset = ni.fileLocation(&elf.mf, false).offset;
......@@ -2275,39 +2343,44 @@ pub fn addRelocAssumeCapacity(
22752343 .next = target.target_relocs,
22762344 .loc = loc_si,
22772345 .target = target_si,
2278 .rel_index = switch (elf.ehdrField(.type)) {
2346 .index = index: switch (elf.ehdrField(.type)) {
22792347 .NONE, .CORE, _ => unreachable,
2280 .REL => rel_index: {
2281 const rela_si = loc_si.shndx(elf).get(elf).rela_si;
2282 switch (elf.shdrPtr(rela_si.shndx(elf))) {
2348 .REL => {
2349 const sh = loc_si.shndx(elf).get(elf);
2350 switch (elf.shdrPtr(sh.rela_si.shndx(elf))) {
22832351 inline else => |shdr, class| {
22842352 const Rela = class.ElfN().Rela;
2285 const old_size = elf.targetLoad(&shdr.size);
22862353 const ent_size = elf.targetLoad(&shdr.entsize);
2287 const new_size = old_size + ent_size;
2288 elf.targetStore(&shdr.size, @intCast(new_size));
2354 const rela_slice = sh.rela_si.node(elf).slice(&elf.mf);
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 };
22892367 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)],
22912369 ));
22922370 rela.* = .{
22932371 .offset = @intCast(offset),
22942372 .info = .{
2295 .type = switch (elf.ehdrField(.machine)) {
2296 else => |machine| @panic(@tagName(machine)),
2297 inline .X86_64, .AARCH64, .RISCV, .PPC64 => |machine| @intCast(
2298 @intFromEnum(@field(@"type", @tagName(machine))),
2299 ),
2300 },
2373 .type = @intCast(@"type".unwrap(elf)),
23012374 .sym = @intCast(@intFromEnum(target_si)),
23022375 },
23032376 .addend = @intCast(addend),
23042377 };
23052378 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);
23072380 },
23082381 }
23092382 },
2310 .EXEC, .DYN => 0,
2383 .EXEC, .DYN => .none,
23112384 },
23122385 .offset = offset,
23132386 .addend = addend,