Skip to content

Commit 438685f

Browse files
committed
Elf2: incrementally update object relocs
1 parent afa97bb commit 438685f

File tree

1 file changed

+105
-32
lines changed

1 file changed

+105
-32
lines changed

src/link/Elf2.zig

Lines changed: 105 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,26 @@ pub const Node = union(enum) {
164164
}
165165
};
166166

167-
pub const Section = struct { si: Symbol.Index, rela_si: Symbol.Index };
167+
pub 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

169188
pub 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,

0 commit comments

Comments
 (0)