authorgravatar for jacoblevgw@gmail.comJacob G-W <jacoblevgw@gmail.com> 2021-06-13 21:29:32-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-07-08 14:12:07-07:00
logdb2d5b49c693b8a38743232b83a6ee1eab8e6468
tree5d52790c19c1bd35bb7a85699f9777c267aeea46
parent166dffb08811cb4ad7ea8ca65ef99b49d2986b94

plan9 linker: use a global offset table

this simplifies stuff and makes us not have to use relocations

3 files changed, 104 insertions(+), 87 deletions(-)

src/codegen.zig+13-8
...@@ -2593,14 +2593,15 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -2593,14 +2593,15 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
2593 }2593 }
2594 if (inst.func.value()) |func_value| {2594 if (inst.func.value()) |func_value| {
2595 if (func_value.castTag(.function)) |func_payload| {2595 if (func_value.castTag(.function)) |func_payload| {
2596 try self.genSetReg(inst.base.src, Type.initTag(.u64), .rax, .{ .immediate = 0xdeadbeefdeadbeef });2596 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
2597 try p9.addCallReloc(self.code, .{2597 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
2598 .caller = p9.cur_decl,2598 const got_addr = p9.bases.data;
2599 .callee = func_payload.data.owner_decl,2599 const got_index = func_payload.data.owner_decl.link.plan9.got_index.?;
2600 .offset_in_caller = self.code.items.len,2600 // ff 14 25 xx xx xx xx call [addr]
2601 });2601 try self.code.ensureCapacity(self.code.items.len + 7);
2602 // call rax2602 self.code.appendSliceAssumeCapacity(&[3]u8{ 0xff, 0x14, 0x25 });
2603 try self.code.appendSlice(&.{ 0xff, 0xd0 });2603 const fn_got_addr = got_addr + got_index * ptr_bytes;
2604 mem.writeIntLittle(u32, self.code.addManyAsArrayAssumeCapacity(4), @intCast(u32, fn_got_addr));
2604 } else return self.fail(inst.base.src, "TODO implement calling extern fn on plan9", .{});2605 } else return self.fail(inst.base.src, "TODO implement calling extern fn on plan9", .{});
2605 } else {2606 } else {
2606 return self.fail(inst.base.src, "TODO implement calling runtime known function pointer", .{});2607 return self.fail(inst.base.src, "TODO implement calling runtime known function pointer", .{});
...@@ -4273,6 +4274,10 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -4273,6 +4274,10 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
4273 const decl = payload.data;4274 const decl = payload.data;
4274 const got_addr = coff_file.offset_table_virtual_address + decl.link.coff.offset_table_index * ptr_bytes;4275 const got_addr = coff_file.offset_table_virtual_address + decl.link.coff.offset_table_index * ptr_bytes;
4275 return MCValue{ .memory = got_addr };4276 return MCValue{ .memory = got_addr };
4277 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
4278 const decl = payload.data;
4279 const got_addr = p9.bases.data + decl.link.plan9.got_index.? * ptr_bytes;
4280 return MCValue{ .memory = got_addr };
4276 } else {4281 } else {
4277 return self.fail(src, "TODO codegen non-ELF const Decl pointer", .{});4282 return self.fail(src, "TODO codegen non-ELF const Decl pointer", .{});
4278 }4283 }
src/link.zig+1-1
...@@ -348,7 +348,7 @@ pub const File = struct {...@@ -348,7 +348,7 @@ pub const File = struct {
348 .macho => return @fieldParentPtr(MachO, "base", base).allocateDeclIndexes(decl),348 .macho => return @fieldParentPtr(MachO, "base", base).allocateDeclIndexes(decl),
349 .c => return @fieldParentPtr(C, "base", base).allocateDeclIndexes(decl),349 .c => return @fieldParentPtr(C, "base", base).allocateDeclIndexes(decl),
350 .wasm => return @fieldParentPtr(Wasm, "base", base).allocateDeclIndexes(decl),350 .wasm => return @fieldParentPtr(Wasm, "base", base).allocateDeclIndexes(decl),
351 .plan9 => {},351 .plan9 => return @fieldParentPtr(Plan9, "base", base).allocateDeclIndexes(decl),
352 .spirv => {},352 .spirv => {},
353 }353 }
354 }354 }
src/link/Plan9.zig+90-78
...@@ -24,13 +24,19 @@ bases: Bases,...@@ -24,13 +24,19 @@ bases: Bases,
24decl_table: std.AutoArrayHashMapUnmanaged(*Module.Decl, void) = .{},24decl_table: std.AutoArrayHashMapUnmanaged(*Module.Decl, void) = .{},
25/// is just casted down when 32 bit25/// is just casted down when 32 bit
26syms: std.ArrayListUnmanaged(aout.Sym) = .{},26syms: std.ArrayListUnmanaged(aout.Sym) = .{},
27call_relocs: std.ArrayListUnmanaged(CallReloc) = .{},
28text_buf: std.ArrayListUnmanaged(u8) = .{},27text_buf: std.ArrayListUnmanaged(u8) = .{},
29data_buf: std.ArrayListUnmanaged(u8) = .{},28data_buf: std.ArrayListUnmanaged(u8) = .{},
3029
31cur_decl: *Module.Decl = undefined,
32hdr: aout.ExecHdr = undefined,30hdr: aout.ExecHdr = undefined,
33const Bases = struct { text: u32, data: u32 };31
32entry_decl: ?*Module.Decl = null,
33
34got: std.ArrayListUnmanaged(u64) = .{},
35const Bases = struct {
36 text: u32,
37 /// the addr of the got
38 data: u32,
39};
3440
35fn getAddr(self: Plan9, addr: u32, t: aout.SymType) u32 {41fn getAddr(self: Plan9, addr: u32, t: aout.SymType) u32 {
36 return addr + switch (t) {42 return addr + switch (t) {
...@@ -60,14 +66,17 @@ fn headerSize(self: Plan9) u32 {...@@ -60,14 +66,17 @@ fn headerSize(self: Plan9) u32 {
6066
61pub const DeclBlock = struct {67pub const DeclBlock = struct {
62 type: aout.SymType,68 type: aout.SymType,
63 // offset in the text or data sects69 /// offset in the text or data sects
64 offset: u32,70 offset: ?u32,
65 // offset into syms71 /// offset into syms
66 sym_index: ?usize,72 sym_index: ?usize,
73 /// offset into got
74 got_index: ?usize,
67 pub const empty = DeclBlock{75 pub const empty = DeclBlock{
68 .type = .t,76 .type = .t,
69 .offset = 0,77 .offset = null,
70 .sym_index = null,78 .sym_index = null,
79 .got_index = null,
71 };80 };
72};81};
7382
...@@ -87,12 +96,6 @@ pub fn defaultBaseAddrs(arch: std.Target.Cpu.Arch) Bases {...@@ -87,12 +96,6 @@ pub fn defaultBaseAddrs(arch: std.Target.Cpu.Arch) Bases {
87 };96 };
88}97}
8998
90pub const CallReloc = struct {
91 caller: *Module.Decl,
92 callee: *Module.Decl,
93 offset_in_caller: usize,
94};
95
96pub const PtrWidth = enum { p32, p64 };99pub const PtrWidth = enum { p32, p64 };
97100
98pub fn createEmpty(gpa: *Allocator, options: link.Options) !*Plan9 {101pub fn createEmpty(gpa: *Allocator, options: link.Options) !*Plan9 {
...@@ -132,48 +135,89 @@ pub fn flush(self: *Plan9, comp: *Compilation) !void {...@@ -132,48 +135,89 @@ pub fn flush(self: *Plan9, comp: *Compilation) !void {
132 }135 }
133 return self.flushModule(comp);136 return self.flushModule(comp);
134}137}
138
135pub fn flushModule(self: *Plan9, comp: *Compilation) !void {139pub fn flushModule(self: *Plan9, comp: *Compilation) !void {
136 const tracy = trace(@src());140 const tracy = trace(@src());
137 defer tracy.end();141 defer tracy.end();
138142
143 log.debug("flushModule", .{});
144
139 defer assert(self.hdr.entry != 0x0);145 defer assert(self.hdr.entry != 0x0);
140146
141 const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented;147 const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented;
142148
143 self.text_buf.items.len = 0;149 self.text_buf.items.len = 0;
144 self.data_buf.items.len = 0;150 self.data_buf.items.len = 0;
145 self.call_relocs.items.len = 0;151 // ensure space to write the got later
152 assert(self.got.items.len == self.decl_table.count());
153 try self.data_buf.appendNTimes(self.base.allocator, 0x69, self.got.items.len * if (self.ptr_width == .p32) @as(u32, 4) else 8);
146 // temporary buffer154 // temporary buffer
147 var code_buffer = std.ArrayList(u8).init(self.base.allocator);155 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
148 defer code_buffer.deinit();156 defer code_buffer.deinit();
149 {157 {
150 for (self.decl_table.keys()) |decl| {158 for (self.decl_table.keys()) |decl| {
151 if (!decl.has_tv) continue;159 if (!decl.has_tv) continue;
152 self.cur_decl = decl;
153 const is_fn = (decl.ty.zigTypeTag() == .Fn);160 const is_fn = (decl.ty.zigTypeTag() == .Fn);
161
162 log.debug("update the symbol table and got for decl {*} ({s})", .{ decl, decl.name });
154 decl.link.plan9 = if (is_fn) .{163 decl.link.plan9 = if (is_fn) .{
155 .offset = self.getAddr(@intCast(u32, self.text_buf.items.len), .t),164 .offset = self.getAddr(@intCast(u32, self.text_buf.items.len), .t),
156 .type = .t,165 .type = .t,
157 .sym_index = decl.link.plan9.sym_index,166 .sym_index = decl.link.plan9.sym_index,
167 .got_index = decl.link.plan9.got_index,
158 } else .{168 } else .{
159 .offset = self.getAddr(@intCast(u32, self.data_buf.items.len), .d),169 .offset = self.getAddr(@intCast(u32, self.data_buf.items.len), .d),
160 .type = .t,170 .type = .d,
161 .sym_index = decl.link.plan9.sym_index,171 .sym_index = decl.link.plan9.sym_index,
172 .got_index = decl.link.plan9.got_index,
162 };173 };
163 if (decl.link.plan9.sym_index == null) {174 self.got.items[decl.link.plan9.got_index.?] = decl.link.plan9.offset.?;
164 try self.syms.append(self.base.allocator, .{175 if (decl.link.plan9.sym_index) |s| {
165 .value = decl.link.plan9.offset,176 self.syms.items[s] = .{
177 .value = decl.link.plan9.offset.?,
166 .type = decl.link.plan9.type,178 .type = decl.link.plan9.type,
167 .name = mem.span(decl.name),179 .name = mem.span(decl.name),
168 });180 };
169 decl.link.plan9.sym_index = self.syms.items.len - 1;
170 } else {181 } else {
171 self.syms.items[decl.link.plan9.sym_index.?] = .{182 try self.syms.append(self.base.allocator, .{
172 .value = decl.link.plan9.offset,183 .value = decl.link.plan9.offset.?,
173 .type = decl.link.plan9.type,184 .type = decl.link.plan9.type,
174 .name = mem.span(decl.name),185 .name = mem.span(decl.name),
175 };186 });
187 decl.link.plan9.sym_index = self.syms.items.len - 1;
188 }
189
190 if (module.decl_exports.get(decl)) |exports| {
191 for (exports) |exp| {
192 // plan9 does not support custom sections
193 if (exp.options.section) |section_name| {
194 if (!mem.eql(u8, section_name, ".text") or !mem.eql(u8, section_name, ".data")) {
195 try module.failed_exports.put(module.gpa, exp, try Module.ErrorMsg.create(self.base.allocator, decl.srcLoc(), "plan9 does not support extra sections", .{}));
196 break;
197 }
198 }
199 if (std.mem.eql(u8, exp.options.name, "_start")) {
200 std.debug.assert(decl.link.plan9.type == .t); // we tried to link a non-function as the entry
201 self.entry_decl = decl;
202 }
203 if (exp.link.plan9) |i| {
204 self.syms.items[i] = .{
205 .value = decl.link.plan9.offset.?,
206 .type = decl.link.plan9.type.toGlobal(),
207 .name = exp.options.name,
208 };
209 } else {
210 try self.syms.append(self.base.allocator, .{
211 .value = decl.link.plan9.offset.?,
212 .type = decl.link.plan9.type.toGlobal(),
213 .name = exp.options.name,
214 });
215 exp.link.plan9 = self.syms.items.len - 1;
216 }
217 }
176 }218 }
219
220 log.debug("codegen decl {*} ({s})", .{ decl, decl.name });
177 const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), .{221 const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), .{
178 .ty = decl.ty,222 .ty = decl.ty,
179 .val = decl.val,223 .val = decl.val,
...@@ -190,32 +234,30 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void {...@@ -190,32 +234,30 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void {
190 };234 };
191 if (is_fn) {235 if (is_fn) {
192 try self.text_buf.appendSlice(self.base.allocator, code);236 try self.text_buf.appendSlice(self.base.allocator, code);
193 try code_buffer.resize(0);237 code_buffer.items.len = 0;
194 } else {238 } else {
195 try self.data_buf.appendSlice(self.base.allocator, code);239 try self.data_buf.appendSlice(self.base.allocator, code);
196 try code_buffer.resize(0);240 code_buffer.items.len = 0;
197 }241 }
198 }242 }
199 }243 }
200244
201 // Do relocations.245 // write the got
202 {246 if (self.ptr_width == .p32) {
203 for (self.call_relocs.items) |reloc| {247 for (self.got.items) |p, i| {
204 const l: DeclBlock = reloc.caller.link.plan9;248 mem.writeInt(u32, self.data_buf.items[i * 4 ..][0..4], @intCast(u32, p), self.base.options.target.cpu.arch.endian());
205 assert(l.sym_index != null); // we didn't process it already249 }
206 const endian = self.base.options.target.cpu.arch.endian();250 } else {
207 if (self.ptr_width == .p32) {251 for (self.got.items) |p, i| {
208 const callee_offset = @intCast(u32, reloc.callee.link.plan9.offset);252 mem.writeInt(u64, self.data_buf.items[i * 8 ..][0..8], p, self.base.options.target.cpu.arch.endian());
209 const off = self.takeAddr(@intCast(u32, reloc.offset_in_caller) + l.offset, reloc.caller.link.plan9.type);
210 std.mem.writeInt(u32, self.text_buf.items[off - 4 ..][0..4], callee_offset, endian);
211 } else {
212 const callee_offset = reloc.callee.link.plan9.offset;
213 const off = self.takeAddr(@intCast(u32, reloc.offset_in_caller) + l.offset, reloc.caller.link.plan9.type);
214 std.mem.writeInt(u64, self.text_buf.items[off - 8 ..][0..8], callee_offset, endian);
215 }
216 }253 }
217 }254 }
218255
256 if (self.entry_decl == null) {
257 @panic("TODO we didn't have _start");
258 }
259 self.hdr.entry = self.entry_decl.?.link.plan9.offset.?;
260
219 // edata, end, etext261 // edata, end, etext
220 self.syms.items[0].value = self.getAddr(0x0, .b); // what is this number262 self.syms.items[0].value = self.getAddr(0x0, .b); // what is this number
221 self.syms.items[1].value = self.getAddr(0x0, .b); // what is this number263 self.syms.items[1].value = self.getAddr(0x0, .b); // what is this number
...@@ -267,43 +309,14 @@ pub fn updateDeclExports(...@@ -267,43 +309,14 @@ pub fn updateDeclExports(
267 decl: *Module.Decl,309 decl: *Module.Decl,
268 exports: []const *Module.Export,310 exports: []const *Module.Export,
269) !void {311) !void {
270 for (exports) |exp| {312 // we do all the things in flush
271 if (exp.options.section) |section_name| {
272 if (!mem.eql(u8, section_name, ".text")) {
273 try module.failed_exports.ensureCapacity(module.gpa, module.failed_exports.count() + 1);
274 module.failed_exports.putAssumeCapacityNoClobber(
275 exp,
276 try Module.ErrorMsg.create(self.base.allocator, decl.srcLoc(), "plan9 does not support extra sections", .{}),
277 );
278 continue;
279 }
280 }
281 if (std.mem.eql(u8, exp.options.name, "_start")) {
282 std.debug.assert(decl.link.plan9.type == .t); // we tried to link a non-function as _start
283 self.hdr.entry = self.bases.text + decl.link.plan9.offset;
284 }
285 if (exp.link.plan9) |i| {
286 self.syms.items[i] = .{
287 .value = self.getAddr(decl.link.plan9.offset, decl.link.plan9.type),
288 .type = decl.link.plan9.type.toGlobal(),
289 .name = exp.options.name,
290 };
291 } else {
292 try self.syms.append(self.base.allocator, .{
293 .value = self.getAddr(decl.link.plan9.offset, decl.link.plan9.type),
294 .type = decl.link.plan9.type.toGlobal(),
295 .name = exp.options.name,
296 });
297 exp.link.plan9 = self.syms.items.len - 1;
298 }
299 }
300}313}
301pub fn deinit(self: *Plan9) void {314pub fn deinit(self: *Plan9) void {
302 self.decl_table.deinit(self.base.allocator);315 self.decl_table.deinit(self.base.allocator);
303 self.call_relocs.deinit(self.base.allocator);
304 self.syms.deinit(self.base.allocator);316 self.syms.deinit(self.base.allocator);
305 self.text_buf.deinit(self.base.allocator);317 self.text_buf.deinit(self.base.allocator);
306 self.data_buf.deinit(self.base.allocator);318 self.data_buf.deinit(self.base.allocator);
319 self.got.deinit(self.base.allocator);
307}320}
308321
309pub const Export = ?usize;322pub const Export = ?usize;
...@@ -350,12 +363,6 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio...@@ -350,12 +363,6 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
350 return self;363 return self;
351}364}
352365
353// tells its future self to write the addr of the callee decl into offset_in_caller.
354// writes it to the {4, 8} bytes before offset_in_caller
355pub fn addCallReloc(self: *Plan9, code: *std.ArrayList(u8), reloc: CallReloc) !void {
356 try self.call_relocs.append(self.base.allocator, reloc);
357}
358
359pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void {366pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void {
360 const writer = buf.writer();367 const writer = buf.writer();
361 for (self.syms.items) |sym| {368 for (self.syms.items) |sym| {
...@@ -369,3 +376,8 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void {...@@ -369,3 +376,8 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void {
369 try writer.writeByte(0);376 try writer.writeByte(0);
370 }377 }
371}378}
379
380pub fn allocateDeclIndexes(self: *Plan9, decl: *Module.Decl) !void {
381 try self.got.append(self.base.allocator, 0xdeadbeef);
382 decl.link.plan9.got_index = self.got.items.len - 1;
383}