authorgravatar for jacoblevgw@gmail.comJacob G-W <jacoblevgw@gmail.com> 2021-06-13 00:07:27-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-07-08 14:10:50-07:00
log166dffb08811cb4ad7ea8ca65ef99b49d2986b94
tree95176f8b5c88b7584b5c58a1bce86392b9d64894
parent72bb6bb1430f0b3b32f0cb5e52054293a59abca6

plan9 linker: correct runtime vs file offset converting code


2 files changed, 74 insertions(+), 47 deletions(-)

src/link/Plan9.zig+65-38
......@@ -19,37 +19,73 @@ const assert = std.debug.assert;
1919base: link.File,
2020ptr_width: PtrWidth,
2121error_flags: File.ErrorFlags = File.ErrorFlags{},
22bases: Bases,
2223
2324decl_table: std.AutoArrayHashMapUnmanaged(*Module.Decl, void) = .{},
2425/// is just casted down when 32 bit
25syms: std.ArrayListUnmanaged(aout.Sym64) = .{},
26syms: std.ArrayListUnmanaged(aout.Sym) = .{},
2627call_relocs: std.ArrayListUnmanaged(CallReloc) = .{},
2728text_buf: std.ArrayListUnmanaged(u8) = .{},
2829data_buf: std.ArrayListUnmanaged(u8) = .{},
2930
3031cur_decl: *Module.Decl = undefined,
3132hdr: aout.ExecHdr = undefined,
33const Bases = struct { text: u32, data: u32 };
34
35fn getAddr(self: Plan9, addr: u32, t: aout.SymType) u32 {
36 return addr + switch (t) {
37 .T, .t => self.bases.text,
38 .D, .d, .B, .b => self.bases.data,
39 else => @panic("get address for more symbol types"),
40 };
41}
42/// opposite of getAddr
43fn takeAddr(self: Plan9, addr: u32, t: aout.SymType) u32 {
44 return addr - switch (t) {
45 .T, .t => self.bases.text,
46 .D, .d, .B, .b => self.bases.data, // TODO is .b correct here?
47 else => @panic("take address for more symbol types"),
48 };
49}
50
51fn getSymAddr(self: Plan9, s: aout.Sym) u32 {
52 return self.getAddr(@intCast(u32, s.value), s.type);
53}
3254
3355fn headerSize(self: Plan9) u32 {
3456 // fat header (currently unused)
3557 const fat: u8 = if (self.ptr_width == .p64) 8 else 0;
3658 return @sizeOf(aout.ExecHdr) + fat;
3759}
60
3861pub const DeclBlock = struct {
39 type: enum { text, data },
62 type: aout.SymType,
4063 // offset in the text or data sects
4164 offset: u32,
4265 // offset into syms
4366 sym_index: ?usize,
4467 pub const empty = DeclBlock{
45 .type = .text,
68 .type = .t,
4669 .offset = 0,
4770 .sym_index = null,
4871 };
4972};
5073
51// TODO change base addr based on target (and section?) (right now it just works on amd64)
52const default_base_addr = 0x00200028;
74pub fn defaultBaseAddrs(arch: std.Target.Cpu.Arch) Bases {
75 return switch (arch) {
76 .x86_64 => .{
77 // 0x28 => 40 == header size
78 .text = 0x200028,
79 .data = 0x400000,
80 },
81 .i386 => .{
82 // 0x20 => 32 == header size
83 .text = 0x200020,
84 .data = 0x400000,
85 },
86 else => std.debug.panic("find default base address for {}", .{arch}),
87 };
88}
5389
5490pub const CallReloc = struct {
5591 caller: *Module.Decl,
......@@ -76,6 +112,7 @@ pub fn createEmpty(gpa: *Allocator, options: link.Options) !*Plan9 {
76112 .file = null,
77113 },
78114 .ptr_width = ptr_width,
115 .bases = undefined,
79116 };
80117 return self;
81118}
......@@ -115,31 +152,25 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void {
115152 self.cur_decl = decl;
116153 const is_fn = (decl.ty.zigTypeTag() == .Fn);
117154 decl.link.plan9 = if (is_fn) .{
118 .offset = @intCast(u32, self.text_buf.items.len),
119 .type = .text,
155 .offset = self.getAddr(@intCast(u32, self.text_buf.items.len), .t),
156 .type = .t,
120157 .sym_index = decl.link.plan9.sym_index,
121158 } else .{
122 .offset = @intCast(u32, self.data_buf.items.len),
123 .type = .data,
159 .offset = self.getAddr(@intCast(u32, self.data_buf.items.len), .d),
160 .type = .t,
124161 .sym_index = decl.link.plan9.sym_index,
125162 };
126163 if (decl.link.plan9.sym_index == null) {
127164 try self.syms.append(self.base.allocator, .{
128165 .value = decl.link.plan9.offset,
129 .type = switch (decl.link.plan9.type) {
130 .text => .t,
131 .data => .d,
132 },
166 .type = decl.link.plan9.type,
133167 .name = mem.span(decl.name),
134168 });
135169 decl.link.plan9.sym_index = self.syms.items.len - 1;
136170 } else {
137171 self.syms.items[decl.link.plan9.sym_index.?] = .{
138172 .value = decl.link.plan9.offset,
139 .type = switch (decl.link.plan9.type) {
140 .text => .t,
141 .data => .d,
142 },
173 .type = decl.link.plan9.type,
143174 .name = mem.span(decl.name),
144175 };
145176 }
......@@ -174,21 +205,21 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void {
174205 assert(l.sym_index != null); // we didn't process it already
175206 const endian = self.base.options.target.cpu.arch.endian();
176207 if (self.ptr_width == .p32) {
177 const callee_offset = @truncate(u32, reloc.callee.link.plan9.offset + default_base_addr); // TODO this is different if its data
178 const off = reloc.offset_in_caller + l.offset;
208 const callee_offset = @intCast(u32, reloc.callee.link.plan9.offset);
209 const off = self.takeAddr(@intCast(u32, reloc.offset_in_caller) + l.offset, reloc.caller.link.plan9.type);
179210 std.mem.writeInt(u32, self.text_buf.items[off - 4 ..][0..4], callee_offset, endian);
180211 } else {
181 const callee_offset = reloc.callee.link.plan9.offset + default_base_addr; // TODO this is different if its data
182 const off = reloc.offset_in_caller + l.offset;
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);
183214 std.mem.writeInt(u64, self.text_buf.items[off - 8 ..][0..8], callee_offset, endian);
184215 }
185216 }
186217 }
187218
188219 // edata, end, etext
189 self.syms.items[0].value = 0x200000; // TODO make this number other place, and what is it?
190 self.syms.items[1].value = 0x200000; // TODO make this number other place, and what is it?
191 self.syms.items[2].value = self.text_buf.items.len;
220 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 number
222 self.syms.items[2].value = self.getAddr(@intCast(u32, self.text_buf.items.len), .t);
192223
193224 var sym_buf = std.ArrayList(u8).init(self.base.allocator);
194225 defer sym_buf.deinit();
......@@ -248,25 +279,19 @@ pub fn updateDeclExports(
248279 }
249280 }
250281 if (std.mem.eql(u8, exp.options.name, "_start")) {
251 std.debug.assert(decl.link.plan9.type == .text); // we tried to link a non-function as _start
252 self.hdr.entry = Plan9.default_base_addr + self.headerSize() + decl.link.plan9.offset;
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;
253284 }
254285 if (exp.link.plan9) |i| {
255286 self.syms.items[i] = .{
256 .value = decl.link.plan9.offset,
257 .type = switch (decl.link.plan9.type) {
258 .text => .T,
259 .data => .D,
260 },
287 .value = self.getAddr(decl.link.plan9.offset, decl.link.plan9.type),
288 .type = decl.link.plan9.type.toGlobal(),
261289 .name = exp.options.name,
262290 };
263291 } else {
264292 try self.syms.append(self.base.allocator, .{
265 .value = decl.link.plan9.offset,
266 .type = switch (decl.link.plan9.type) {
267 .text => .T,
268 .data => .D,
269 },
293 .value = self.getAddr(decl.link.plan9.offset, decl.link.plan9.type),
294 .type = decl.link.plan9.type.toGlobal(),
270295 .name = exp.options.name,
271296 });
272297 exp.link.plan9 = self.syms.items.len - 1;
......@@ -300,6 +325,8 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
300325 if (std.builtin.mode == .Debug or std.builtin.mode == .ReleaseSafe)
301326 self.hdr.entry = 0x0;
302327
328 self.bases = defaultBaseAddrs(options.target.cpu.arch);
329
303330 // first 3 symbols in our table are edata, end, etext
304331 try self.syms.appendSlice(self.base.allocator, &.{
305332 .{
......@@ -333,9 +360,9 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void {
333360 const writer = buf.writer();
334361 for (self.syms.items) |sym| {
335362 if (self.ptr_width == .p32) {
336 try writer.writeIntBig(u32, @intCast(u32, sym.value) + default_base_addr);
363 try writer.writeIntBig(u32, @intCast(u32, sym.value));
337364 } else {
338 try writer.writeIntBig(u64, sym.value + default_base_addr);
365 try writer.writeIntBig(u64, sym.value);
339366 }
340367 try writer.writeByte(@enumToInt(sym.type));
341368 try writer.writeAll(std.mem.span(sym.name));
src/link/plan9/a.out.zig+9-9
......@@ -46,18 +46,10 @@ pub const ExecHdr = extern struct {
4646 }
4747};
4848
49// uchar value[4];
50// char type;
51// char name[n]; /* NUL-terminated */
52pub const Sym32 = struct {
53 value: u32, // big endian in the file
54 type: SymType,
55 name: []const u8,
56};
5749// uchar value[8];
5850// char type;
5951// char name[n]; /* NUL-terminated */
60pub const Sym64 = struct {
52pub const Sym = struct {
6153 value: u64, // big endian in the file
6254 type: SymType,
6355 name: []const u8,
......@@ -93,6 +85,14 @@ pub const SymType = enum(u8) {
9385 z = 0x80 | 'z',
9486 Z = 0x80 | 'Z',
9587 m = 0x80 | 'm',
88 pub fn toGlobal(self: SymType) SymType {
89 return switch (self) {
90 .t => .T,
91 .b => .B,
92 .d => .D,
93 else => unreachable,
94 };
95 }
9696};
9797
9898pub const HDR_MAGIC = 0x00008000;