authorgravatar for jacoblevgw@gmail.comJacob G-W <jacoblevgw@gmail.com> 2021-06-08 20:12:18-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-07-08 14:10:49-07:00
log3e59c1502556493b29171c2d22447dd70670ca02
treeda6e6ed293d124312623b931ef050de8829d7c30
parentc114474190fd6fe48b8c74becfb39ed82287d059

plan9 linker: do relocations


2 files changed, 93 insertions(+), 24 deletions(-)

src/codegen.zig+50-10
...@@ -2557,16 +2557,56 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -2557,16 +2557,56 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
2557 return self.fail(inst.base.src, "TODO implement calling runtime known function pointer", .{});2557 return self.fail(inst.base.src, "TODO implement calling runtime known function pointer", .{});
2558 }2558 }
2559 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {2559 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
2560 if (inst.func.value()) |func_value| {2560 switch (arch) {
2561 if (func_value.castTag(.function)) |func_payload| {2561 .x86_64 => {
2562 try p9.addCallReloc(self.code, .{2562 for (info.args) |mc_arg, arg_i| {
2563 .caller = p9.cur_decl,2563 const arg = inst.args[arg_i];
2564 .callee = func_payload.data.owner_decl,2564 const arg_mcv = try self.resolveInst(inst.args[arg_i]);
2565 .offset_in_caller = self.code.items.len,2565 // Here we do not use setRegOrMem even though the logic is similar, because
2566 });2566 // the function call will move the stack pointer, so the offsets are different.
2567 } else return self.fail(inst.base.src, "TODO implement calling extern fn on plan9", .{});2567 switch (mc_arg) {
2568 } else {2568 .none => continue,
2569 return self.fail(inst.base.src, "TODO implement calling runtime known function pointer", .{});2569 .register => |reg| {
2570 try self.register_manager.getReg(reg, null);
2571 try self.genSetReg(arg.src, arg.ty, reg, arg_mcv);
2572 },
2573 .stack_offset => {
2574 // Here we need to emit instructions like this:
2575 // mov qword ptr [rsp + stack_offset], x
2576 return self.fail(inst.base.src, "TODO implement calling with parameters in memory", .{});
2577 },
2578 .ptr_stack_offset => {
2579 return self.fail(inst.base.src, "TODO implement calling with MCValue.ptr_stack_offset arg", .{});
2580 },
2581 .ptr_embedded_in_code => {
2582 return self.fail(inst.base.src, "TODO implement calling with MCValue.ptr_embedded_in_code arg", .{});
2583 },
2584 .undef => unreachable,
2585 .immediate => unreachable,
2586 .unreach => unreachable,
2587 .dead => unreachable,
2588 .embedded_in_code => unreachable,
2589 .memory => unreachable,
2590 .compare_flags_signed => unreachable,
2591 .compare_flags_unsigned => unreachable,
2592 }
2593 }
2594 if (inst.func.value()) |func_value| {
2595 if (func_value.castTag(.function)) |func_payload| {
2596 try self.genSetReg(inst.base.src, Type.initTag(.u64), .rax, .{ .immediate = 0xdeadbeefdeadbeef });
2597 try p9.addCallReloc(self.code, .{
2598 .caller = p9.cur_decl,
2599 .callee = func_payload.data.owner_decl,
2600 .offset_in_caller = self.code.items.len,
2601 });
2602 // call rax
2603 try self.code.appendSlice(&.{ 0xff, 0xd0 });
2604 } else return self.fail(inst.base.src, "TODO implement calling extern fn on plan9", .{});
2605 } else {
2606 return self.fail(inst.base.src, "TODO implement calling runtime known function pointer", .{});
2607 }
2608 },
2609 else => return self.fail(inst.base.src, "TODO implement call on plan9 for {}", .{self.target.cpu.arch}),
2570 }2610 }
2571 } else unreachable;2611 } else unreachable;
25722612
src/link/Plan9.zig+43-14
...@@ -39,11 +39,12 @@ pub const DeclBlock = struct {...@@ -39,11 +39,12 @@ pub const DeclBlock = struct {
39 type: enum { text, data },39 type: enum { text, data },
40 // offset in the text or data sects40 // offset in the text or data sects
41 offset: u32,41 offset: u32,
42 sym_index: usize,42 // offset into syms
43 sym_index: ?usize,
43 pub const empty = DeclBlock{44 pub const empty = DeclBlock{
44 .type = .text,45 .type = .text,
45 .offset = 0,46 .offset = 0,
46 .sym_index = 0,47 .sym_index = null,
47 };48 };
48};49};
4950
...@@ -98,6 +99,8 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void {...@@ -98,6 +99,8 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void {
98 const tracy = trace(@src());99 const tracy = trace(@src());
99 defer tracy.end();100 defer tracy.end();
100101
102 defer assert(self.hdr.entry != 0x0);
103
101 const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented;104 const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented;
102105
103 self.text_buf.items.len = 0;106 self.text_buf.items.len = 0;
...@@ -120,7 +123,7 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void {...@@ -120,7 +123,7 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void {
120 .type = .data,123 .type = .data,
121 .sym_index = decl.link.plan9.sym_index,124 .sym_index = decl.link.plan9.sym_index,
122 };125 };
123 if (decl.link.plan9.sym_index == 0) {126 if (decl.link.plan9.sym_index == null) {
124 try self.syms.append(self.base.allocator, .{127 try self.syms.append(self.base.allocator, .{
125 .value = decl.link.plan9.offset,128 .value = decl.link.plan9.offset,
126 .type = switch (decl.link.plan9.type) {129 .type = switch (decl.link.plan9.type) {
...@@ -131,7 +134,7 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void {...@@ -131,7 +134,7 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void {
131 });134 });
132 decl.link.plan9.sym_index = self.syms.items.len - 1;135 decl.link.plan9.sym_index = self.syms.items.len - 1;
133 } else {136 } else {
134 self.syms.items[decl.link.plan9.sym_index] = .{137 self.syms.items[decl.link.plan9.sym_index.?] = .{
135 .value = decl.link.plan9.offset,138 .value = decl.link.plan9.offset,
136 .type = switch (decl.link.plan9.type) {139 .type = switch (decl.link.plan9.type) {
137 .text => .t,140 .text => .t,
...@@ -162,18 +165,40 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void {...@@ -162,18 +165,40 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void {
162 }165 }
163 }166 }
164167
168 // Do relocations.
169 {
170 for (self.call_relocs.items) |reloc| {
171 const l: DeclBlock = reloc.caller.link.plan9;
172 assert(l.sym_index != null); // we didn't process it already
173 const endian = self.base.options.target.cpu.arch.endian();
174 if (self.ptr_width == .p32) {
175 const callee_offset = @truncate(u32, reloc.callee.link.plan9.offset + default_base_addr); // TODO this is different if its data
176 const off = reloc.offset_in_caller + l.offset;
177 std.mem.writeInt(u32, self.text_buf.items[off - 4 ..][0..4], callee_offset, endian);
178 } else {
179 // what we are writing
180 const callee_offset = reloc.callee.link.plan9.offset + default_base_addr; // TODO this is different if its data
181 const off = reloc.offset_in_caller + l.offset;
182 std.mem.writeInt(u64, self.text_buf.items[off - 8 ..][0..8], callee_offset, endian);
183 }
184 }
185 }
186
165 var sym_buf = std.ArrayList(u8).init(self.base.allocator);187 var sym_buf = std.ArrayList(u8).init(self.base.allocator);
166 defer sym_buf.deinit();188 defer sym_buf.deinit();
167 try self.writeSyms(&sym_buf);189 try self.writeSyms(&sym_buf);
168190
169 // generate the header191 // generate the header
170 self.hdr.magic = try aout.magicFromArch(self.base.options.target.cpu.arch);192 self.hdr = .{
171 self.hdr.text = @intCast(u32, self.text_buf.items.len);193 .magic = try aout.magicFromArch(self.base.options.target.cpu.arch),
172 self.hdr.data = @intCast(u32, self.data_buf.items.len);194 .text = @intCast(u32, self.text_buf.items.len),
173 self.hdr.syms = @intCast(u32, sym_buf.items.len);195 .data = @intCast(u32, self.data_buf.items.len),
174 self.hdr.bss = 0;196 .syms = @intCast(u32, sym_buf.items.len),
175 self.hdr.pcsz = 0;197 .bss = 0,
176 self.hdr.spsz = 0;198 .pcsz = 0,
199 .spsz = 0,
200 .entry = self.hdr.entry,
201 };
177202
178 const file = self.base.file.?;203 const file = self.base.file.?;
179204
...@@ -262,22 +287,26 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio...@@ -262,22 +287,26 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
262 const self = try createEmpty(allocator, options);287 const self = try createEmpty(allocator, options);
263 errdefer self.base.destroy();288 errdefer self.base.destroy();
264289
290 if (std.builtin.mode == .Debug or std.builtin.mode == .ReleaseSafe)
291 self.hdr.entry = 0x0;
292
265 self.base.file = file;293 self.base.file = file;
266 return self;294 return self;
267}295}
268296
297// tells its future self to write the addr of the callee decl into offset_in_caller.
298// writes it to the {4, 8} bytes before offset_in_caller
269pub fn addCallReloc(self: *Plan9, code: *std.ArrayList(u8), reloc: CallReloc) !void {299pub fn addCallReloc(self: *Plan9, code: *std.ArrayList(u8), reloc: CallReloc) !void {
270 try self.call_relocs.append(self.base.allocator, reloc);300 try self.call_relocs.append(self.base.allocator, reloc);
271 try code.writer().writeIntBig(u64, 0xdeadbeef);
272}301}
273302
274pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void {303pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void {
275 const writer = buf.writer();304 const writer = buf.writer();
276 for (self.syms.items) |sym| {305 for (self.syms.items) |sym| {
277 if (self.ptr_width == .p32) {306 if (self.ptr_width == .p32) {
278 try writer.writeIntBig(u32, @intCast(u32, sym.value));307 try writer.writeIntBig(u32, @intCast(u32, sym.value) + default_base_addr);
279 } else {308 } else {
280 try writer.writeIntBig(u64, sym.value);309 try writer.writeIntBig(u64, sym.value + default_base_addr);
281 }310 }
282 try writer.writeByte(@enumToInt(sym.type));311 try writer.writeByte(@enumToInt(sym.type));
283 try writer.writeAll(std.mem.span(sym.name));312 try writer.writeAll(std.mem.span(sym.name));