Skip to content

Commit

Permalink
macho: emit relocs for atoms
Browse files Browse the repository at this point in the history
  • Loading branch information
kubkon committed Jan 3, 2024
1 parent e76b134 commit d20dc30
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 8 deletions.
83 changes: 83 additions & 0 deletions src/MachO/Atom.zig
Original file line number Diff line number Diff line change
Expand Up @@ -669,6 +669,89 @@ fn encode(insts: []const Instruction, code: []u8) !void {
}
}

pub fn calcNumRelocs(self: Atom, macho_file: *MachO) u32 {
switch (macho_file.options.cpu_arch.?) {
.aarch64 => {
var nreloc: u32 = 0;
for (self.getRelocs(macho_file)) |rel| {
nreloc += 1;
if (rel.addend > 0) nreloc += 1;
}
return nreloc;
},
.x86_64 => return @intCast(self.getRelocs(macho_file).len),
else => unreachable,
}
}

pub fn writeRelocs(self: Atom, macho_file: *MachO, buffer: *std.ArrayList(macho.relocation_info)) !void {
const tracy = trace(@src());
defer tracy.end();

const cpu_arch = macho_file.options.cpu_arch.?;
const relocs = self.getRelocs(macho_file);

for (relocs) |rel| {
const rel_offset = rel.offset - self.off;
const r_address: i32 = math.cast(i32, self.value + rel_offset) orelse return error.Overflow;
const r_symbolnum = r_symbolnum: {
const r_symbolnum: u32 = switch (rel.tag) {
.local => rel.getTargetAtom(macho_file).out_n_sect + 1,
.@"extern" => rel.getTargetSymbol(macho_file).getOutputSymtabIndex(macho_file).?,
};
break :r_symbolnum math.cast(u24, r_symbolnum) orelse return error.Overflow;
};
const r_extern = rel.tag == .@"extern";
const addend = rel.addend + rel.getRelocAddend(cpu_arch);

switch (cpu_arch) {
.aarch64 => {
if (addend > 0 and rel.type != .unsigned) {
buffer.appendAssumeCapacity(.{
.r_address = r_address,
.r_symbolnum = @bitCast(math.cast(i24, addend) orelse return error.Overflow),
.r_pcrel = 0,
.r_length = 2,
.r_extern = 0,
.r_type = @intFromEnum(macho.reloc_type_arm64.ARM64_RELOC_ADDEND),
});
}

const r_type: macho.reloc_type_arm64 = switch (rel.type) {
.page => .ARM64_RELOC_PAGE21,
.pageoff => .ARM64_RELOC_PAGEOFF12,
.got_load_page => .ARM64_RELOC_GOT_LOAD_PAGE21,
.got_load_pageoff => .ARM64_RELOC_GOT_LOAD_PAGEOFF12,
.tlvp_page => .ARM64_RELOC_TLVP_LOAD_PAGE21,
.tlvp_pageoff => .ARM64_RELOC_TLVP_LOAD_PAGEOFF12,
.branch => .ARM64_RELOC_BRANCH26,
.got => .ARM64_RELOC_POINTER_TO_GOT,
.subtractor => .ARM64_RELOC_SUBTRACTOR,
.unsigned => .ARM64_RELOC_UNSIGNED,

.signed,
.signed1,
.signed2,
.signed4,
.got_load,
.tlv,
=> unreachable,
};
buffer.appendAssumeCapacity(.{
.r_address = r_address,
.r_symbolnum = r_symbolnum,
.r_pcrel = @intFromBool(rel.meta.pcrel),
.r_extern = @intFromBool(r_extern),
.r_length = rel.meta.length,
.r_type = @intFromEnum(r_type),
});
},
.x86_64 => @panic("TODO"),
else => unreachable,
}
}
}

pub fn format(
atom: Atom,
comptime unused_fmt_string: []const u8,
Expand Down
22 changes: 14 additions & 8 deletions src/MachO/relocatable.zig
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,13 @@ pub fn flush(macho_file: *MachO) !void {

state_log.debug("{}", .{macho_file.dumpState()});

try macho_file.calcSymtabSize();
try writeAtoms(macho_file);
try writeCompactUnwind(macho_file);
try writeEhFrame(macho_file);

off = mem.alignForward(u32, off, @alignOf(u64));
off = try writeDataInCode(macho_file, off);
try macho_file.calcSymtabSize();
off = mem.alignForward(u32, off, @alignOf(u64));
off = try macho_file.writeSymtab(off);
off = mem.alignForward(u32, off, @alignOf(u64));
Expand Down Expand Up @@ -141,7 +141,7 @@ fn calcSectionSizes(macho_file: *MachO) !void {
atom.value = offset;
header.size += padding + atom.size;
header.@"align" = @max(header.@"align", atom.alignment);
header.nreloc += @intCast(atom.relocs.len);
header.nreloc += atom.calcNumRelocs(macho_file);
}
}

Expand Down Expand Up @@ -224,20 +224,26 @@ fn writeAtoms(macho_file: *MachO) !void {
if (atoms.items.len == 0) continue;
if (header.isZerofill()) continue;

const buffer = try gpa.alloc(u8, header.size);
defer gpa.free(buffer);
const code = try gpa.alloc(u8, header.size);
defer gpa.free(code);
const padding_byte: u8 = if (header.isCode() and cpu_arch == .x86_64) 0xcc else 0;
@memset(buffer, padding_byte);
@memset(code, padding_byte);

var relocs = try std.ArrayList(macho.relocation_info).initCapacity(gpa, header.nreloc);
defer relocs.deinit();

for (atoms.items) |atom_index| {
const atom = macho_file.getAtom(atom_index).?;
assert(atom.flags.alive);
const off = atom.value - header.addr;
@memcpy(buffer[off..][0..atom.size], atom.getCode(macho_file));
// TODO write relocs
@memcpy(code[off..][0..atom.size], atom.getCode(macho_file));

try atom.writeRelocs(macho_file, &relocs);
}

try macho_file.base.file.pwriteAll(buffer, header.offset);
// TODO scattered writes?
try macho_file.base.file.pwriteAll(code, header.offset);
try macho_file.base.file.pwriteAll(mem.sliceAsBytes(relocs.items), header.reloff);
}
}

Expand Down

0 comments on commit d20dc30

Please sign in to comment.