mirror of
https://github.com/ziglang/zig.git
synced 2026-01-12 10:25:13 +00:00
plan9 linker: do relocations
This commit is contained in:
parent
c114474190
commit
3e59c15025
@ -2557,16 +2557,56 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
|
||||
return self.fail(inst.base.src, "TODO implement calling runtime known function pointer", .{});
|
||||
}
|
||||
} else if (self.bin_file.cast(link.File.Plan9)) |p9| {
|
||||
if (inst.func.value()) |func_value| {
|
||||
if (func_value.castTag(.function)) |func_payload| {
|
||||
try p9.addCallReloc(self.code, .{
|
||||
.caller = p9.cur_decl,
|
||||
.callee = func_payload.data.owner_decl,
|
||||
.offset_in_caller = self.code.items.len,
|
||||
});
|
||||
} else return self.fail(inst.base.src, "TODO implement calling extern fn on plan9", .{});
|
||||
} else {
|
||||
return self.fail(inst.base.src, "TODO implement calling runtime known function pointer", .{});
|
||||
switch (arch) {
|
||||
.x86_64 => {
|
||||
for (info.args) |mc_arg, arg_i| {
|
||||
const arg = inst.args[arg_i];
|
||||
const arg_mcv = try self.resolveInst(inst.args[arg_i]);
|
||||
// Here we do not use setRegOrMem even though the logic is similar, because
|
||||
// the function call will move the stack pointer, so the offsets are different.
|
||||
switch (mc_arg) {
|
||||
.none => continue,
|
||||
.register => |reg| {
|
||||
try self.register_manager.getReg(reg, null);
|
||||
try self.genSetReg(arg.src, arg.ty, reg, arg_mcv);
|
||||
},
|
||||
.stack_offset => {
|
||||
// Here we need to emit instructions like this:
|
||||
// mov qword ptr [rsp + stack_offset], x
|
||||
return self.fail(inst.base.src, "TODO implement calling with parameters in memory", .{});
|
||||
},
|
||||
.ptr_stack_offset => {
|
||||
return self.fail(inst.base.src, "TODO implement calling with MCValue.ptr_stack_offset arg", .{});
|
||||
},
|
||||
.ptr_embedded_in_code => {
|
||||
return self.fail(inst.base.src, "TODO implement calling with MCValue.ptr_embedded_in_code arg", .{});
|
||||
},
|
||||
.undef => unreachable,
|
||||
.immediate => unreachable,
|
||||
.unreach => unreachable,
|
||||
.dead => unreachable,
|
||||
.embedded_in_code => unreachable,
|
||||
.memory => unreachable,
|
||||
.compare_flags_signed => unreachable,
|
||||
.compare_flags_unsigned => unreachable,
|
||||
}
|
||||
}
|
||||
if (inst.func.value()) |func_value| {
|
||||
if (func_value.castTag(.function)) |func_payload| {
|
||||
try self.genSetReg(inst.base.src, Type.initTag(.u64), .rax, .{ .immediate = 0xdeadbeefdeadbeef });
|
||||
try p9.addCallReloc(self.code, .{
|
||||
.caller = p9.cur_decl,
|
||||
.callee = func_payload.data.owner_decl,
|
||||
.offset_in_caller = self.code.items.len,
|
||||
});
|
||||
// call rax
|
||||
try self.code.appendSlice(&.{ 0xff, 0xd0 });
|
||||
} else return self.fail(inst.base.src, "TODO implement calling extern fn on plan9", .{});
|
||||
} else {
|
||||
return self.fail(inst.base.src, "TODO implement calling runtime known function pointer", .{});
|
||||
}
|
||||
},
|
||||
else => return self.fail(inst.base.src, "TODO implement call on plan9 for {}", .{self.target.cpu.arch}),
|
||||
}
|
||||
} else unreachable;
|
||||
|
||||
|
||||
@ -39,11 +39,12 @@ pub const DeclBlock = struct {
|
||||
type: enum { text, data },
|
||||
// offset in the text or data sects
|
||||
offset: u32,
|
||||
sym_index: usize,
|
||||
// offset into syms
|
||||
sym_index: ?usize,
|
||||
pub const empty = DeclBlock{
|
||||
.type = .text,
|
||||
.offset = 0,
|
||||
.sym_index = 0,
|
||||
.sym_index = null,
|
||||
};
|
||||
};
|
||||
|
||||
@ -98,6 +99,8 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
defer assert(self.hdr.entry != 0x0);
|
||||
|
||||
const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented;
|
||||
|
||||
self.text_buf.items.len = 0;
|
||||
@ -120,7 +123,7 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void {
|
||||
.type = .data,
|
||||
.sym_index = decl.link.plan9.sym_index,
|
||||
};
|
||||
if (decl.link.plan9.sym_index == 0) {
|
||||
if (decl.link.plan9.sym_index == null) {
|
||||
try self.syms.append(self.base.allocator, .{
|
||||
.value = decl.link.plan9.offset,
|
||||
.type = switch (decl.link.plan9.type) {
|
||||
@ -131,7 +134,7 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void {
|
||||
});
|
||||
decl.link.plan9.sym_index = self.syms.items.len - 1;
|
||||
} else {
|
||||
self.syms.items[decl.link.plan9.sym_index] = .{
|
||||
self.syms.items[decl.link.plan9.sym_index.?] = .{
|
||||
.value = decl.link.plan9.offset,
|
||||
.type = switch (decl.link.plan9.type) {
|
||||
.text => .t,
|
||||
@ -162,18 +165,40 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void {
|
||||
}
|
||||
}
|
||||
|
||||
// Do relocations.
|
||||
{
|
||||
for (self.call_relocs.items) |reloc| {
|
||||
const l: DeclBlock = reloc.caller.link.plan9;
|
||||
assert(l.sym_index != null); // we didn't process it already
|
||||
const endian = self.base.options.target.cpu.arch.endian();
|
||||
if (self.ptr_width == .p32) {
|
||||
const callee_offset = @truncate(u32, reloc.callee.link.plan9.offset + default_base_addr); // TODO this is different if its data
|
||||
const off = reloc.offset_in_caller + l.offset;
|
||||
std.mem.writeInt(u32, self.text_buf.items[off - 4 ..][0..4], callee_offset, endian);
|
||||
} else {
|
||||
// what we are writing
|
||||
const callee_offset = reloc.callee.link.plan9.offset + default_base_addr; // TODO this is different if its data
|
||||
const off = reloc.offset_in_caller + l.offset;
|
||||
std.mem.writeInt(u64, self.text_buf.items[off - 8 ..][0..8], callee_offset, endian);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var sym_buf = std.ArrayList(u8).init(self.base.allocator);
|
||||
defer sym_buf.deinit();
|
||||
try self.writeSyms(&sym_buf);
|
||||
|
||||
// generate the header
|
||||
self.hdr.magic = try aout.magicFromArch(self.base.options.target.cpu.arch);
|
||||
self.hdr.text = @intCast(u32, self.text_buf.items.len);
|
||||
self.hdr.data = @intCast(u32, self.data_buf.items.len);
|
||||
self.hdr.syms = @intCast(u32, sym_buf.items.len);
|
||||
self.hdr.bss = 0;
|
||||
self.hdr.pcsz = 0;
|
||||
self.hdr.spsz = 0;
|
||||
self.hdr = .{
|
||||
.magic = try aout.magicFromArch(self.base.options.target.cpu.arch),
|
||||
.text = @intCast(u32, self.text_buf.items.len),
|
||||
.data = @intCast(u32, self.data_buf.items.len),
|
||||
.syms = @intCast(u32, sym_buf.items.len),
|
||||
.bss = 0,
|
||||
.pcsz = 0,
|
||||
.spsz = 0,
|
||||
.entry = self.hdr.entry,
|
||||
};
|
||||
|
||||
const file = self.base.file.?;
|
||||
|
||||
@ -262,22 +287,26 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
|
||||
const self = try createEmpty(allocator, options);
|
||||
errdefer self.base.destroy();
|
||||
|
||||
if (std.builtin.mode == .Debug or std.builtin.mode == .ReleaseSafe)
|
||||
self.hdr.entry = 0x0;
|
||||
|
||||
self.base.file = file;
|
||||
return self;
|
||||
}
|
||||
|
||||
// tells its future self to write the addr of the callee decl into offset_in_caller.
|
||||
// writes it to the {4, 8} bytes before offset_in_caller
|
||||
pub fn addCallReloc(self: *Plan9, code: *std.ArrayList(u8), reloc: CallReloc) !void {
|
||||
try self.call_relocs.append(self.base.allocator, reloc);
|
||||
try code.writer().writeIntBig(u64, 0xdeadbeef);
|
||||
}
|
||||
|
||||
pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void {
|
||||
const writer = buf.writer();
|
||||
for (self.syms.items) |sym| {
|
||||
if (self.ptr_width == .p32) {
|
||||
try writer.writeIntBig(u32, @intCast(u32, sym.value));
|
||||
try writer.writeIntBig(u32, @intCast(u32, sym.value) + default_base_addr);
|
||||
} else {
|
||||
try writer.writeIntBig(u64, sym.value);
|
||||
try writer.writeIntBig(u64, sym.value + default_base_addr);
|
||||
}
|
||||
try writer.writeByte(@enumToInt(sym.type));
|
||||
try writer.writeAll(std.mem.span(sym.name));
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user