Skip to content

Commit

Permalink
elf: store relative offsets in atom and symbol
Browse files Browse the repository at this point in the history
  • Loading branch information
kubkon committed Feb 13, 2024
1 parent c22bb38 commit e401930
Show file tree
Hide file tree
Showing 8 changed files with 61 additions and 78 deletions.
16 changes: 3 additions & 13 deletions src/link/Elf.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1332,7 +1332,6 @@ pub fn flushModule(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node)
try self.sortPhdrs();
try self.allocateNonAllocSections();
self.allocateSpecialPhdrs();
self.allocateAtoms();
self.allocateLinkerDefinedSymbols();

// Dump the state for easy debugging.
Expand All @@ -1352,7 +1351,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node)
if (shdr.sh_type == elf.SHT_NOBITS) continue;
const code = try zig_object.codeAlloc(self, atom_index);
defer gpa.free(code);
const file_offset = shdr.sh_offset + atom_ptr.value - shdr.sh_addr;
const file_offset = shdr.sh_offset + atom_ptr.value;
atom_ptr.resolveRelocsAlloc(self, code) catch |err| switch (err) {
// TODO
error.RelaxFail, error.InvalidInstruction, error.CannotEncode => {
Expand Down Expand Up @@ -2907,7 +2906,7 @@ pub fn writeElfHeader(self: *Elf) !void {
mem.writeInt(u32, hdr_buf[index..][0..4], 1, endian);
index += 4;

const e_entry = if (self.entry_index) |entry_index| self.symbol(entry_index).value else 0;
const e_entry = if (self.entry_index) |entry_index| self.symbol(entry_index).address(.{}, self) else 0;
const phdr_table_offset = if (self.phdr_table_index) |phndx| self.phdrs.items[phndx].p_offset else 0;
switch (self.ptr_width) {
.p32 => {
Expand Down Expand Up @@ -4402,15 +4401,6 @@ fn allocateSpecialPhdrs(self: *Elf) void {
}
}

pub fn allocateAtoms(self: *Elf) void {
if (self.zigObjectPtr()) |zig_object| {
zig_object.allocateTlvAtoms(self);
}
for (self.objects.items) |index| {
self.file(index).?.object.allocateAtoms(self);
}
}

fn writeAtoms(self: *Elf) !void {
const gpa = self.base.comp.gpa;

Expand Down Expand Up @@ -4464,7 +4454,7 @@ fn writeAtoms(self: *Elf) !void {
const atom_ptr = self.atom(atom_index).?;
assert(atom_ptr.flags.alive);

const offset = math.cast(usize, atom_ptr.value - shdr.sh_addr - base_offset) orelse
const offset = math.cast(usize, atom_ptr.value - base_offset) orelse
return error.Overflow;
const size = math.cast(usize, atom_ptr.size) orelse return error.Overflow;

Expand Down
39 changes: 24 additions & 15 deletions src/link/Elf/Atom.zig
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,12 @@ pub fn name(self: Atom, elf_file: *Elf) []const u8 {
};
}

pub fn address(self: Atom, elf_file: *Elf) u64 {
const shndx = self.outputShndx() orelse return self.value;
const shdr = elf_file.shdrs.items[shndx];
return shdr.sh_addr + self.value;
}

pub fn file(self: Atom, elf_file: *Elf) ?File {
return elf_file.file(self.file_index);
}
Expand Down Expand Up @@ -85,14 +91,17 @@ pub fn priority(self: Atom, elf_file: *Elf) u64 {
/// File offset relocation happens transparently, so it is not included in
/// this calculation.
pub fn capacity(self: Atom, elf_file: *Elf) u64 {
const next_value = if (elf_file.atom(self.next_index)) |next| next.value else std.math.maxInt(u32);
return next_value - self.value;
const next_addr = if (elf_file.atom(self.next_index)) |next|
next.address(elf_file)
else
std.math.maxInt(u32);
return next_addr - self.address(elf_file);
}

pub fn freeListEligible(self: Atom, elf_file: *Elf) bool {
// No need to keep a free list node for the last block.
const next = elf_file.atom(self.next_index) orelse return false;
const cap = next.value - self.value;
const cap = next.address(elf_file) - self.address(elf_file);
const ideal_cap = Elf.padToIdeal(self.size);
if (cap <= ideal_cap) return false;
const surplus = cap - ideal_cap;
Expand Down Expand Up @@ -160,23 +169,23 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {
atom_placement = last.atom_index;
break :blk new_start_vaddr;
} else {
break :blk shdr.sh_addr;
break :blk 0;
}
};

log.debug("allocated atom({d}) : '{s}' at 0x{x} to 0x{x}", .{
self.atom_index,
self.name(elf_file),
self.value,
self.value + self.size,
self.address(elf_file),
self.address(elf_file) + self.size,
});

const expand_section = if (atom_placement) |placement_index|
elf_file.atom(placement_index).?.next_index == 0
else
true;
if (expand_section) {
const needed_size = (self.value + self.size) - shdr.sh_addr;
const needed_size = self.value + self.size;
try elf_file.growAllocSection(self.outputShndx().?, needed_size);
last_atom_index.* = self.atom_index;

Expand Down Expand Up @@ -301,7 +310,7 @@ pub fn relocs(self: Atom, elf_file: *Elf) []align(1) const elf.Elf64_Rela {
}

pub fn writeRelocs(self: Atom, elf_file: *Elf, out_relocs: *std.ArrayList(elf.Elf64_Rela)) !void {
relocs_log.debug("0x{x}: {s}", .{ self.value, self.name(elf_file) });
relocs_log.debug("0x{x}: {s}", .{ self.address(elf_file), self.name(elf_file) });

const file_ptr = self.file(elf_file).?;
for (self.relocs(elf_file)) |rel| {
Expand All @@ -322,7 +331,7 @@ pub fn writeRelocs(self: Atom, elf_file: *Elf, out_relocs: *std.ArrayList(elf.El
var r_sym: u32 = 0;
switch (target.type(elf_file)) {
elf.STT_SECTION => {
r_addend += @intCast(target.value);
r_addend += @intCast(target.address(.{}, elf_file));
r_sym = elf_file.sectionSymbolOutputSymtabIndex(target.outputShndx().?);
},
else => {
Expand Down Expand Up @@ -778,7 +787,7 @@ fn reportUndefined(
}

pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) !void {
relocs_log.debug("0x{x}: {s}", .{ self.value, self.name(elf_file) });
relocs_log.debug("0x{x}: {s}", .{ self.address(elf_file), self.name(elf_file) });

const file_ptr = self.file(elf_file).?;
var stream = std.io.fixedBufferStream(code);
Expand All @@ -802,7 +811,7 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) !void {
// https://intezer.com/blog/malware-analysis/executable-and-linkable-format-101-part-3-relocations/
//
// Address of the source atom.
const P = @as(i64, @intCast(self.value + rel.r_offset));
const P = @as(i64, @intCast(self.address(elf_file) + rel.r_offset));
// Addend from the relocation.
const A = rel.r_addend;
// Address of the target symbol - can be address of the symbol within an atom or address of PLT stub.
Expand Down Expand Up @@ -969,7 +978,7 @@ fn resolveDynAbsReloc(
) !void {
const comp = elf_file.base.comp;
const gpa = comp.gpa;
const P = self.value + rel.r_offset;
const P = self.address(elf_file) + rel.r_offset;
const A = rel.r_addend;
const S = @as(i64, @intCast(target.address(.{}, elf_file)));
const is_writeable = self.inputShdr(elf_file).sh_flags & elf.SHF_WRITE != 0;
Expand Down Expand Up @@ -1058,7 +1067,7 @@ fn applyDynamicReloc(value: i64, elf_file: *Elf, writer: anytype) !void {
}

pub fn resolveRelocsNonAlloc(self: Atom, elf_file: *Elf, code: []u8, undefs: anytype) !void {
relocs_log.debug("0x{x}: {s}", .{ self.value, self.name(elf_file) });
relocs_log.debug("0x{x}: {s}", .{ self.address(elf_file), self.name(elf_file) });

const file_ptr = self.file(elf_file).?;
var stream = std.io.fixedBufferStream(code);
Expand Down Expand Up @@ -1097,7 +1106,7 @@ pub fn resolveRelocsNonAlloc(self: Atom, elf_file: *Elf, code: []u8, undefs: any
// We will use equation format to resolve relocations:
// https://intezer.com/blog/malware-analysis/executable-and-linkable-format-101-part-3-relocations/
//
const P = @as(i64, @intCast(self.value + rel.r_offset));
const P = @as(i64, @intCast(self.address(elf_file) + rel.r_offset));
// Addend from the relocation.
const A = rel.r_addend;
// Address of the target symbol - can be address of the symbol within an atom or address of PLT stub.
Expand Down Expand Up @@ -1248,7 +1257,7 @@ fn format2(
const atom = ctx.atom;
const elf_file = ctx.elf_file;
try writer.print("atom({d}) : {s} : @{x} : shdr({d}) : align({x}) : size({x})", .{
atom.atom_index, atom.name(elf_file), atom.value,
atom.atom_index, atom.name(elf_file), atom.address(elf_file),
atom.output_section_index, atom.alignment, atom.size,
});
if (atom.fde_start != atom.fde_end) {
Expand Down
11 changes: 0 additions & 11 deletions src/link/Elf/Object.zig
Original file line number Diff line number Diff line change
Expand Up @@ -718,21 +718,11 @@ pub fn addAtomsToOutputSections(self: *Object, elf_file: *Elf) !void {
if (!gop.found_existing) gop.value_ptr.* = .{};
try gop.value_ptr.append(gpa, atom_index);
}
}

pub fn allocateAtoms(self: Object, elf_file: *Elf) void {
for (self.atoms.items) |atom_index| {
const atom = elf_file.atom(atom_index) orelse continue;
if (!atom.flags.alive) continue;
const shdr = elf_file.shdrs.items[atom.output_section_index];
atom.value += shdr.sh_addr;
}

for (self.locals()) |local_index| {
const local = elf_file.symbol(local_index);
const atom = local.atom(elf_file) orelse continue;
if (!atom.flags.alive) continue;
local.value += atom.value;
local.output_section_index = atom.output_section_index;
}

Expand All @@ -741,7 +731,6 @@ pub fn allocateAtoms(self: Object, elf_file: *Elf) void {
const atom = global.atom(elf_file) orelse continue;
if (!atom.flags.alive) continue;
if (global.file(elf_file).?.index() != self.index) continue;
global.value += atom.value;
global.output_section_index = atom.output_section_index;
}
}
Expand Down
15 changes: 11 additions & 4 deletions src/link/Elf/Symbol.zig
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,9 @@ pub fn address(symbol: Symbol, opts: struct { plt: bool = true }, elf_file: *Elf
// Lazy-bound function it is!
return symbol.pltAddress(elf_file);
}
if (symbol.atom(elf_file)) |atom_ptr| {
return atom_ptr.address(elf_file) + symbol.value;
}
return symbol.value;
}

Expand Down Expand Up @@ -247,11 +250,11 @@ pub fn setOutputSym(symbol: Symbol, elf_file: *Elf, out: *elf.Elf64_Sym) void {
if (symbol.flags.is_canonical) break :blk symbol.address(.{}, elf_file);
break :blk 0;
}
if (st_shndx == elf.SHN_ABS or st_shndx == elf.SHN_COMMON) break :blk symbol.value;
if (st_shndx == elf.SHN_ABS or st_shndx == elf.SHN_COMMON) break :blk symbol.address(.{ .plt = false }, elf_file);
const shdr = &elf_file.shdrs.items[st_shndx];
if (shdr.sh_flags & elf.SHF_TLS != 0 and file_ptr != .linker_defined)
break :blk symbol.value - elf_file.tlsAddress();
break :blk symbol.value;
break :blk symbol.address(.{ .plt = false }, elf_file) - elf_file.tlsAddress();
break :blk symbol.address(.{ .plt = false }, elf_file);
};
out.st_info = (st_bind << 4) | st_type;
out.st_other = esym.st_other;
Expand Down Expand Up @@ -323,7 +326,11 @@ fn format2(
_ = options;
_ = unused_fmt_string;
const symbol = ctx.symbol;
try writer.print("%{d} : {s} : @{x}", .{ symbol.esym_index, symbol.fmtName(ctx.elf_file), symbol.value });
try writer.print("%{d} : {s} : @{x}", .{
symbol.esym_index,
symbol.fmtName(ctx.elf_file),
symbol.address(.{}, ctx.elf_file),
});
if (symbol.file(ctx.elf_file)) |file_ptr| {
if (symbol.isAbs(ctx.elf_file)) {
if (symbol.elfSym(ctx.elf_file).st_shndx == elf.SHN_UNDEF) {
Expand Down
Loading

0 comments on commit e401930

Please sign in to comment.