authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-02-13 16:42:28+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-02-13 20:33:01+01:00
loge401930fa862e3b9b3eedc8eb405c501fbf3de30
treedad8558d3ccf98880a4c7f8f6ecb443b52a34247
parentc22bb3805821d7ffe60e048f1efe362aad703668

elf: store relative offsets in atom and symbol


8 files changed, 61 insertions(+), 78 deletions(-)

src/link/Elf.zig+3-13
......@@ -1332,7 +1332,6 @@ pub fn flushModule(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node)
13321332 try self.sortPhdrs();
13331333 try self.allocateNonAllocSections();
13341334 self.allocateSpecialPhdrs();
1335 self.allocateAtoms();
13361335 self.allocateLinkerDefinedSymbols();
13371336
13381337 // Dump the state for easy debugging.
......@@ -1352,7 +1351,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node)
13521351 if (shdr.sh_type == elf.SHT_NOBITS) continue;
13531352 const code = try zig_object.codeAlloc(self, atom_index);
13541353 defer gpa.free(code);
1355 const file_offset = shdr.sh_offset + atom_ptr.value - shdr.sh_addr;
1354 const file_offset = shdr.sh_offset + atom_ptr.value;
13561355 atom_ptr.resolveRelocsAlloc(self, code) catch |err| switch (err) {
13571356 // TODO
13581357 error.RelaxFail, error.InvalidInstruction, error.CannotEncode => {
......@@ -2907,7 +2906,7 @@ pub fn writeElfHeader(self: *Elf) !void {
29072906 mem.writeInt(u32, hdr_buf[index..][0..4], 1, endian);
29082907 index += 4;
29092908
2910 const e_entry = if (self.entry_index) |entry_index| self.symbol(entry_index).value else 0;
2909 const e_entry = if (self.entry_index) |entry_index| self.symbol(entry_index).address(.{}, self) else 0;
29112910 const phdr_table_offset = if (self.phdr_table_index) |phndx| self.phdrs.items[phndx].p_offset else 0;
29122911 switch (self.ptr_width) {
29132912 .p32 => {
......@@ -4402,15 +4401,6 @@ fn allocateSpecialPhdrs(self: *Elf) void {
44024401 }
44034402}
44044403
4405pub fn allocateAtoms(self: *Elf) void {
4406 if (self.zigObjectPtr()) |zig_object| {
4407 zig_object.allocateTlvAtoms(self);
4408 }
4409 for (self.objects.items) |index| {
4410 self.file(index).?.object.allocateAtoms(self);
4411 }
4412}
4413
44144404fn writeAtoms(self: *Elf) !void {
44154405 const gpa = self.base.comp.gpa;
44164406
......@@ -4464,7 +4454,7 @@ fn writeAtoms(self: *Elf) !void {
44644454 const atom_ptr = self.atom(atom_index).?;
44654455 assert(atom_ptr.flags.alive);
44664456
4467 const offset = math.cast(usize, atom_ptr.value - shdr.sh_addr - base_offset) orelse
4457 const offset = math.cast(usize, atom_ptr.value - base_offset) orelse
44684458 return error.Overflow;
44694459 const size = math.cast(usize, atom_ptr.size) orelse return error.Overflow;
44704460
src/link/Elf/Atom.zig+24-15
......@@ -54,6 +54,12 @@ pub fn name(self: Atom, elf_file: *Elf) []const u8 {
5454 };
5555}
5656
57pub fn address(self: Atom, elf_file: *Elf) u64 {
58 const shndx = self.outputShndx() orelse return self.value;
59 const shdr = elf_file.shdrs.items[shndx];
60 return shdr.sh_addr + self.value;
61}
62
5763pub fn file(self: Atom, elf_file: *Elf) ?File {
5864 return elf_file.file(self.file_index);
5965}
......@@ -85,14 +91,17 @@ pub fn priority(self: Atom, elf_file: *Elf) u64 {
8591/// File offset relocation happens transparently, so it is not included in
8692/// this calculation.
8793pub fn capacity(self: Atom, elf_file: *Elf) u64 {
88 const next_value = if (elf_file.atom(self.next_index)) |next| next.value else std.math.maxInt(u32);
89 return next_value - self.value;
94 const next_addr = if (elf_file.atom(self.next_index)) |next|
95 next.address(elf_file)
96 else
97 std.math.maxInt(u32);
98 return next_addr - self.address(elf_file);
9099}
91100
92101pub fn freeListEligible(self: Atom, elf_file: *Elf) bool {
93102 // No need to keep a free list node for the last block.
94103 const next = elf_file.atom(self.next_index) orelse return false;
95 const cap = next.value - self.value;
104 const cap = next.address(elf_file) - self.address(elf_file);
96105 const ideal_cap = Elf.padToIdeal(self.size);
97106 if (cap <= ideal_cap) return false;
98107 const surplus = cap - ideal_cap;
......@@ -160,15 +169,15 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {
160169 atom_placement = last.atom_index;
161170 break :blk new_start_vaddr;
162171 } else {
163 break :blk shdr.sh_addr;
172 break :blk 0;
164173 }
165174 };
166175
167176 log.debug("allocated atom({d}) : '{s}' at 0x{x} to 0x{x}", .{
168177 self.atom_index,
169178 self.name(elf_file),
170 self.value,
171 self.value + self.size,
179 self.address(elf_file),
180 self.address(elf_file) + self.size,
172181 });
173182
174183 const expand_section = if (atom_placement) |placement_index|
......@@ -176,7 +185,7 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {
176185 else
177186 true;
178187 if (expand_section) {
179 const needed_size = (self.value + self.size) - shdr.sh_addr;
188 const needed_size = self.value + self.size;
180189 try elf_file.growAllocSection(self.outputShndx().?, needed_size);
181190 last_atom_index.* = self.atom_index;
182191
......@@ -301,7 +310,7 @@ pub fn relocs(self: Atom, elf_file: *Elf) []align(1) const elf.Elf64_Rela {
301310}
302311
303312pub fn writeRelocs(self: Atom, elf_file: *Elf, out_relocs: *std.ArrayList(elf.Elf64_Rela)) !void {
304 relocs_log.debug("0x{x}: {s}", .{ self.value, self.name(elf_file) });
313 relocs_log.debug("0x{x}: {s}", .{ self.address(elf_file), self.name(elf_file) });
305314
306315 const file_ptr = self.file(elf_file).?;
307316 for (self.relocs(elf_file)) |rel| {
......@@ -322,7 +331,7 @@ pub fn writeRelocs(self: Atom, elf_file: *Elf, out_relocs: *std.ArrayList(elf.El
322331 var r_sym: u32 = 0;
323332 switch (target.type(elf_file)) {
324333 elf.STT_SECTION => {
325 r_addend += @intCast(target.value);
334 r_addend += @intCast(target.address(.{}, elf_file));
326335 r_sym = elf_file.sectionSymbolOutputSymtabIndex(target.outputShndx().?);
327336 },
328337 else => {
......@@ -778,7 +787,7 @@ fn reportUndefined(
778787}
779788
780789pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) !void {
781 relocs_log.debug("0x{x}: {s}", .{ self.value, self.name(elf_file) });
790 relocs_log.debug("0x{x}: {s}", .{ self.address(elf_file), self.name(elf_file) });
782791
783792 const file_ptr = self.file(elf_file).?;
784793 var stream = std.io.fixedBufferStream(code);
......@@ -802,7 +811,7 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) !void {
802811 // https://intezer.com/blog/malware-analysis/executable-and-linkable-format-101-part-3-relocations/
803812 //
804813 // Address of the source atom.
805 const P = @as(i64, @intCast(self.value + rel.r_offset));
814 const P = @as(i64, @intCast(self.address(elf_file) + rel.r_offset));
806815 // Addend from the relocation.
807816 const A = rel.r_addend;
808817 // Address of the target symbol - can be address of the symbol within an atom or address of PLT stub.
......@@ -969,7 +978,7 @@ fn resolveDynAbsReloc(
969978) !void {
970979 const comp = elf_file.base.comp;
971980 const gpa = comp.gpa;
972 const P = self.value + rel.r_offset;
981 const P = self.address(elf_file) + rel.r_offset;
973982 const A = rel.r_addend;
974983 const S = @as(i64, @intCast(target.address(.{}, elf_file)));
975984 const is_writeable = self.inputShdr(elf_file).sh_flags & elf.SHF_WRITE != 0;
......@@ -1058,7 +1067,7 @@ fn applyDynamicReloc(value: i64, elf_file: *Elf, writer: anytype) !void {
10581067}
10591068
10601069pub fn resolveRelocsNonAlloc(self: Atom, elf_file: *Elf, code: []u8, undefs: anytype) !void {
1061 relocs_log.debug("0x{x}: {s}", .{ self.value, self.name(elf_file) });
1070 relocs_log.debug("0x{x}: {s}", .{ self.address(elf_file), self.name(elf_file) });
10621071
10631072 const file_ptr = self.file(elf_file).?;
10641073 var stream = std.io.fixedBufferStream(code);
......@@ -1097,7 +1106,7 @@ pub fn resolveRelocsNonAlloc(self: Atom, elf_file: *Elf, code: []u8, undefs: any
10971106 // We will use equation format to resolve relocations:
10981107 // https://intezer.com/blog/malware-analysis/executable-and-linkable-format-101-part-3-relocations/
10991108 //
1100 const P = @as(i64, @intCast(self.value + rel.r_offset));
1109 const P = @as(i64, @intCast(self.address(elf_file) + rel.r_offset));
11011110 // Addend from the relocation.
11021111 const A = rel.r_addend;
11031112 // Address of the target symbol - can be address of the symbol within an atom or address of PLT stub.
......@@ -1248,7 +1257,7 @@ fn format2(
12481257 const atom = ctx.atom;
12491258 const elf_file = ctx.elf_file;
12501259 try writer.print("atom({d}) : {s} : @{x} : shdr({d}) : align({x}) : size({x})", .{
1251 atom.atom_index, atom.name(elf_file), atom.value,
1260 atom.atom_index, atom.name(elf_file), atom.address(elf_file),
12521261 atom.output_section_index, atom.alignment, atom.size,
12531262 });
12541263 if (atom.fde_start != atom.fde_end) {
src/link/Elf/Object.zig-11
......@@ -718,21 +718,11 @@ pub fn addAtomsToOutputSections(self: *Object, elf_file: *Elf) !void {
718718 if (!gop.found_existing) gop.value_ptr.* = .{};
719719 try gop.value_ptr.append(gpa, atom_index);
720720 }
721}
722
723pub fn allocateAtoms(self: Object, elf_file: *Elf) void {
724 for (self.atoms.items) |atom_index| {
725 const atom = elf_file.atom(atom_index) orelse continue;
726 if (!atom.flags.alive) continue;
727 const shdr = elf_file.shdrs.items[atom.output_section_index];
728 atom.value += shdr.sh_addr;
729 }
730721
731722 for (self.locals()) |local_index| {
732723 const local = elf_file.symbol(local_index);
733724 const atom = local.atom(elf_file) orelse continue;
734725 if (!atom.flags.alive) continue;
735 local.value += atom.value;
736726 local.output_section_index = atom.output_section_index;
737727 }
738728
......@@ -741,7 +731,6 @@ pub fn allocateAtoms(self: Object, elf_file: *Elf) void {
741731 const atom = global.atom(elf_file) orelse continue;
742732 if (!atom.flags.alive) continue;
743733 if (global.file(elf_file).?.index() != self.index) continue;
744 global.value += atom.value;
745734 global.output_section_index = atom.output_section_index;
746735 }
747736}
src/link/Elf/Symbol.zig+11-4
......@@ -104,6 +104,9 @@ pub fn address(symbol: Symbol, opts: struct { plt: bool = true }, elf_file: *Elf
104104 // Lazy-bound function it is!
105105 return symbol.pltAddress(elf_file);
106106 }
107 if (symbol.atom(elf_file)) |atom_ptr| {
108 return atom_ptr.address(elf_file) + symbol.value;
109 }
107110 return symbol.value;
108111}
109112
......@@ -247,11 +250,11 @@ pub fn setOutputSym(symbol: Symbol, elf_file: *Elf, out: *elf.Elf64_Sym) void {
247250 if (symbol.flags.is_canonical) break :blk symbol.address(.{}, elf_file);
248251 break :blk 0;
249252 }
250 if (st_shndx == elf.SHN_ABS or st_shndx == elf.SHN_COMMON) break :blk symbol.value;
253 if (st_shndx == elf.SHN_ABS or st_shndx == elf.SHN_COMMON) break :blk symbol.address(.{ .plt = false }, elf_file);
251254 const shdr = &elf_file.shdrs.items[st_shndx];
252255 if (shdr.sh_flags & elf.SHF_TLS != 0 and file_ptr != .linker_defined)
253 break :blk symbol.value - elf_file.tlsAddress();
254 break :blk symbol.value;
256 break :blk symbol.address(.{ .plt = false }, elf_file) - elf_file.tlsAddress();
257 break :blk symbol.address(.{ .plt = false }, elf_file);
255258 };
256259 out.st_info = (st_bind << 4) | st_type;
257260 out.st_other = esym.st_other;
......@@ -323,7 +326,11 @@ fn format2(
323326 _ = options;
324327 _ = unused_fmt_string;
325328 const symbol = ctx.symbol;
326 try writer.print("%{d} : {s} : @{x}", .{ symbol.esym_index, symbol.fmtName(ctx.elf_file), symbol.value });
329 try writer.print("%{d} : {s} : @{x}", .{
330 symbol.esym_index,
331 symbol.fmtName(ctx.elf_file),
332 symbol.address(.{}, ctx.elf_file),
333 });
327334 if (symbol.file(ctx.elf_file)) |file_ptr| {
328335 if (symbol.isAbs(ctx.elf_file)) {
329336 if (symbol.elfSym(ctx.elf_file).st_shndx == elf.SHN_UNDEF) {
src/link/Elf/ZigObject.zig+20-31
......@@ -401,19 +401,6 @@ pub fn claimUnresolvedObject(self: ZigObject, elf_file: *Elf) void {
401401 }
402402}
403403
404pub fn allocateTlvAtoms(self: ZigObject, elf_file: *Elf) void {
405 for (self.tls_variables.keys(), self.tls_variables.values()) |atom_index, tlv| {
406 const atom = elf_file.atom(atom_index) orelse continue;
407 if (!atom.flags.alive) continue;
408 const local = elf_file.symbol(tlv.symbol_index);
409 const shdr = elf_file.shdrs.items[atom.output_section_index];
410 atom.value += shdr.sh_addr;
411 local.value = atom.value;
412
413 // TODO exported TLS vars
414 }
415}
416
417404pub fn scanRelocs(self: *ZigObject, elf_file: *Elf, undefs: anytype) !void {
418405 const gpa = elf_file.base.comp.gpa;
419406 for (self.atoms.items) |atom_index| {
......@@ -644,7 +631,7 @@ pub fn codeAlloc(self: ZigObject, elf_file: *Elf, atom_index: Atom.Index) ![]u8
644631 return code;
645632 }
646633
647 const file_offset = shdr.sh_offset + atom.value - shdr.sh_addr;
634 const file_offset = shdr.sh_offset + atom.value;
648635 const size = std.math.cast(usize, atom.size) orelse return error.Overflow;
649636 const code = try gpa.alloc(u8, size);
650637 errdefer gpa.free(code);
......@@ -664,7 +651,7 @@ pub fn getDeclVAddr(
664651) !u64 {
665652 const this_sym_index = try self.getOrCreateMetadataForDecl(elf_file, decl_index);
666653 const this_sym = elf_file.symbol(this_sym_index);
667 const vaddr = this_sym.value;
654 const vaddr = this_sym.address(.{}, elf_file);
668655 const parent_atom = elf_file.symbol(reloc_info.parent_atom_index).atom(elf_file).?;
669656 try parent_atom.addReloc(elf_file, .{
670657 .r_offset = reloc_info.offset,
......@@ -682,7 +669,7 @@ pub fn getAnonDeclVAddr(
682669) !u64 {
683670 const sym_index = self.anon_decls.get(decl_val).?.symbol_index;
684671 const sym = elf_file.symbol(sym_index);
685 const vaddr = sym.value;
672 const vaddr = sym.address(.{}, elf_file);
686673 const parent_atom = elf_file.symbol(reloc_info.parent_atom_index).atom(elf_file).?;
687674 try parent_atom.addReloc(elf_file, .{
688675 .r_offset = reloc_info.offset,
......@@ -941,13 +928,13 @@ fn updateDeclCode(
941928
942929 if (old_size > 0 and elf_file.base.child_pid == null) {
943930 const capacity = atom_ptr.capacity(elf_file);
944 const need_realloc = code.len > capacity or !required_alignment.check(sym.value);
931 const need_realloc = code.len > capacity or !required_alignment.check(atom_ptr.value);
945932 if (need_realloc) {
946933 try atom_ptr.grow(elf_file);
947934 log.debug("growing {s} from 0x{x} to 0x{x}", .{ decl_name, old_vaddr, atom_ptr.value });
948935 if (old_vaddr != atom_ptr.value) {
949 sym.value = atom_ptr.value;
950 esym.st_value = atom_ptr.value;
936 sym.value = 0;
937 esym.st_value = 0;
951938
952939 if (!elf_file.base.isRelocatable()) {
953940 log.debug(" (writing new offset table entry)", .{});
......@@ -963,9 +950,9 @@ fn updateDeclCode(
963950 try atom_ptr.allocate(elf_file);
964951 errdefer self.freeDeclMetadata(elf_file, sym_index);
965952
966 sym.value = atom_ptr.value;
953 sym.value = 0;
967954 sym.flags.needs_zig_got = true;
968 esym.st_value = atom_ptr.value;
955 esym.st_value = 0;
969956
970957 if (!elf_file.base.isRelocatable()) {
971958 const gop = try sym.getOrCreateZigGotEntry(sym_index, elf_file);
......@@ -981,7 +968,7 @@ fn updateDeclCode(
981968 .iov_len = code.len,
982969 }};
983970 var remote_vec: [1]std.os.iovec_const = .{.{
984 .iov_base = @as([*]u8, @ptrFromInt(@as(usize, @intCast(sym.value)))),
971 .iov_base = @as([*]u8, @ptrFromInt(@as(usize, @intCast(sym.address(.{}, elf_file))))),
985972 .iov_len = code.len,
986973 }};
987974 const rc = std.os.linux.process_vm_writev(pid, &code_vec, &remote_vec, 0);
......@@ -996,7 +983,7 @@ fn updateDeclCode(
996983
997984 const shdr = elf_file.shdrs.items[shdr_index];
998985 if (shdr.sh_type != elf.SHT_NOBITS) {
999 const file_offset = shdr.sh_offset + sym.value - shdr.sh_addr;
986 const file_offset = shdr.sh_offset + atom_ptr.value;
1000987 try elf_file.base.file.?.pwriteAll(code, file_offset);
1001988 }
1002989}
......@@ -1022,12 +1009,14 @@ fn updateTlv(
10221009 const esym = &self.local_esyms.items(.elf_sym)[sym.esym_index];
10231010 const atom_ptr = sym.atom(elf_file).?;
10241011
1012 sym.value = 0;
10251013 sym.output_section_index = shndx;
10261014 atom_ptr.output_section_index = shndx;
10271015
10281016 sym.name_offset = try self.strtab.insert(gpa, decl_name);
10291017 atom_ptr.flags.alive = true;
10301018 atom_ptr.name_offset = sym.name_offset;
1019 esym.st_value = 0;
10311020 esym.st_name = sym.name_offset;
10321021 esym.st_info = elf.STT_TLS;
10331022 esym.st_size = code.len;
......@@ -1117,7 +1106,7 @@ pub fn updateFunc(
11171106 try self.dwarf.?.commitDeclState(
11181107 mod,
11191108 decl_index,
1120 sym.value,
1109 sym.address(.{}, elf_file),
11211110 sym.atom(elf_file).?.size,
11221111 ds,
11231112 );
......@@ -1202,7 +1191,7 @@ pub fn updateDecl(
12021191 try self.dwarf.?.commitDeclState(
12031192 mod,
12041193 decl_index,
1205 sym.value,
1194 sym.address(.{}, elf_file),
12061195 sym.atom(elf_file).?.size,
12071196 ds,
12081197 );
......@@ -1281,9 +1270,9 @@ fn updateLazySymbol(
12811270 try atom_ptr.allocate(elf_file);
12821271 errdefer self.freeDeclMetadata(elf_file, symbol_index);
12831272
1284 local_sym.value = atom_ptr.value;
1273 local_sym.value = 0;
12851274 local_sym.flags.needs_zig_got = true;
1286 local_esym.st_value = atom_ptr.value;
1275 local_esym.st_value = 0;
12871276
12881277 if (!elf_file.base.isRelocatable()) {
12891278 const gop = try local_sym.getOrCreateZigGotEntry(symbol_index, elf_file);
......@@ -1291,7 +1280,7 @@ fn updateLazySymbol(
12911280 }
12921281
12931282 const shdr = elf_file.shdrs.items[output_section_index];
1294 const file_offset = shdr.sh_offset + atom_ptr.value - shdr.sh_addr;
1283 const file_offset = shdr.sh_offset + atom_ptr.value;
12951284 try elf_file.base.file.?.pwriteAll(code, file_offset);
12961285}
12971286
......@@ -1384,11 +1373,11 @@ fn lowerConst(
13841373 // TODO rename and re-audit this method
13851374 errdefer self.freeDeclMetadata(elf_file, sym_index);
13861375
1387 local_sym.value = atom_ptr.value;
1388 local_esym.st_value = atom_ptr.value;
1376 local_sym.value = 0;
1377 local_esym.st_value = 0;
13891378
13901379 const shdr = elf_file.shdrs.items[output_section_index];
1391 const file_offset = shdr.sh_offset + atom_ptr.value - shdr.sh_addr;
1380 const file_offset = shdr.sh_offset + atom_ptr.value;
13921381 try elf_file.base.file.?.pwriteAll(code, file_offset);
13931382
13941383 return .{ .ok = sym_index };
src/link/Elf/eh_frame.zig+1-1
......@@ -409,7 +409,7 @@ fn emitReloc(elf_file: *Elf, rec: anytype, sym: *const Symbol, rel: elf.Elf64_Re
409409 var r_sym: u32 = 0;
410410 switch (sym.type(elf_file)) {
411411 elf.STT_SECTION => {
412 r_addend += @intCast(sym.value);
412 r_addend += @intCast(sym.address(.{}, elf_file));
413413 r_sym = elf_file.sectionSymbolOutputSymtabIndex(sym.outputShndx().?);
414414 },
415415 else => {
src/link/Elf/relocatable.zig-1
......@@ -195,7 +195,6 @@ pub fn flushObject(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]const
195195
196196 try allocateAllocSections(elf_file);
197197 try elf_file.allocateNonAllocSections();
198 elf_file.allocateAtoms();
199198
200199 if (build_options.enable_logging) {
201200 state_log.debug("{}", .{elf_file.dumpState()});
src/link/Elf/synthetic_sections.zig+2-2
......@@ -297,7 +297,7 @@ pub const ZigGotSection = struct {
297297 const off = zig_got.entryOffset(index, elf_file);
298298 const vaddr = zig_got.entryAddress(index, elf_file);
299299 const entry = zig_got.entries.items[index];
300 const value = elf_file.symbol(entry).value;
300 const value = elf_file.symbol(entry).address(.{}, elf_file);
301301 switch (entry_size) {
302302 2 => {
303303 var buf: [2]u8 = undefined;
......@@ -1004,7 +1004,7 @@ pub const GotPltSection = struct {
10041004 {
10051005 // [0]: _DYNAMIC
10061006 const symbol = elf_file.symbol(elf_file.dynamic_index.?);
1007 try writer.writeInt(u64, symbol.value, .little);
1007 try writer.writeInt(u64, symbol.address(.{}, elf_file), .little);
10081008 }
10091009 // [1]: 0x0
10101010 // [2]: 0x0