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;...@@ -19,37 +19,73 @@ const assert = std.debug.assert;
19base: link.File,19base: link.File,
20ptr_width: PtrWidth,20ptr_width: PtrWidth,
21error_flags: File.ErrorFlags = File.ErrorFlags{},21error_flags: File.ErrorFlags = File.ErrorFlags{},
22bases: Bases,
2223
23decl_table: std.AutoArrayHashMapUnmanaged(*Module.Decl, void) = .{},24decl_table: std.AutoArrayHashMapUnmanaged(*Module.Decl, void) = .{},
24/// is just casted down when 32 bit25/// is just casted down when 32 bit
25syms: std.ArrayListUnmanaged(aout.Sym64) = .{},26syms: std.ArrayListUnmanaged(aout.Sym) = .{},
26call_relocs: std.ArrayListUnmanaged(CallReloc) = .{},27call_relocs: std.ArrayListUnmanaged(CallReloc) = .{},
27text_buf: std.ArrayListUnmanaged(u8) = .{},28text_buf: std.ArrayListUnmanaged(u8) = .{},
28data_buf: std.ArrayListUnmanaged(u8) = .{},29data_buf: std.ArrayListUnmanaged(u8) = .{},
2930
30cur_decl: *Module.Decl = undefined,31cur_decl: *Module.Decl = undefined,
31hdr: aout.ExecHdr = undefined,32hdr: 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
33fn headerSize(self: Plan9) u32 {55fn headerSize(self: Plan9) u32 {
34 // fat header (currently unused)56 // fat header (currently unused)
35 const fat: u8 = if (self.ptr_width == .p64) 8 else 0;57 const fat: u8 = if (self.ptr_width == .p64) 8 else 0;
36 return @sizeOf(aout.ExecHdr) + fat;58 return @sizeOf(aout.ExecHdr) + fat;
37}59}
60
38pub const DeclBlock = struct {61pub const DeclBlock = struct {
39 type: enum { text, data },62 type: aout.SymType,
40 // offset in the text or data sects63 // offset in the text or data sects
41 offset: u32,64 offset: u32,
42 // offset into syms65 // offset into syms
43 sym_index: ?usize,66 sym_index: ?usize,
44 pub const empty = DeclBlock{67 pub const empty = DeclBlock{
45 .type = .text,68 .type = .t,
46 .offset = 0,69 .offset = 0,
47 .sym_index = null,70 .sym_index = null,
48 };71 };
49};72};
5073
51// TODO change base addr based on target (and section?) (right now it just works on amd64)74pub fn defaultBaseAddrs(arch: std.Target.Cpu.Arch) Bases {
52const default_base_addr = 0x00200028;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
54pub const CallReloc = struct {90pub const CallReloc = struct {
55 caller: *Module.Decl,91 caller: *Module.Decl,
...@@ -76,6 +112,7 @@ pub fn createEmpty(gpa: *Allocator, options: link.Options) !*Plan9 {...@@ -76,6 +112,7 @@ pub fn createEmpty(gpa: *Allocator, options: link.Options) !*Plan9 {
76 .file = null,112 .file = null,
77 },113 },
78 .ptr_width = ptr_width,114 .ptr_width = ptr_width,
115 .bases = undefined,
79 };116 };
80 return self;117 return self;
81}118}
...@@ -115,31 +152,25 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void {...@@ -115,31 +152,25 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void {
115 self.cur_decl = decl;152 self.cur_decl = decl;
116 const is_fn = (decl.ty.zigTypeTag() == .Fn);153 const is_fn = (decl.ty.zigTypeTag() == .Fn);
117 decl.link.plan9 = if (is_fn) .{154 decl.link.plan9 = if (is_fn) .{
118 .offset = @intCast(u32, self.text_buf.items.len),155 .offset = self.getAddr(@intCast(u32, self.text_buf.items.len), .t),
119 .type = .text,156 .type = .t,
120 .sym_index = decl.link.plan9.sym_index,157 .sym_index = decl.link.plan9.sym_index,
121 } else .{158 } else .{
122 .offset = @intCast(u32, self.data_buf.items.len),159 .offset = self.getAddr(@intCast(u32, self.data_buf.items.len), .d),
123 .type = .data,160 .type = .t,
124 .sym_index = decl.link.plan9.sym_index,161 .sym_index = decl.link.plan9.sym_index,
125 };162 };
126 if (decl.link.plan9.sym_index == null) {163 if (decl.link.plan9.sym_index == null) {
127 try self.syms.append(self.base.allocator, .{164 try self.syms.append(self.base.allocator, .{
128 .value = decl.link.plan9.offset,165 .value = decl.link.plan9.offset,
129 .type = switch (decl.link.plan9.type) {166 .type = decl.link.plan9.type,
130 .text => .t,
131 .data => .d,
132 },
133 .name = mem.span(decl.name),167 .name = mem.span(decl.name),
134 });168 });
135 decl.link.plan9.sym_index = self.syms.items.len - 1;169 decl.link.plan9.sym_index = self.syms.items.len - 1;
136 } else {170 } else {
137 self.syms.items[decl.link.plan9.sym_index.?] = .{171 self.syms.items[decl.link.plan9.sym_index.?] = .{
138 .value = decl.link.plan9.offset,172 .value = decl.link.plan9.offset,
139 .type = switch (decl.link.plan9.type) {173 .type = decl.link.plan9.type,
140 .text => .t,
141 .data => .d,
142 },
143 .name = mem.span(decl.name),174 .name = mem.span(decl.name),
144 };175 };
145 }176 }
...@@ -174,21 +205,21 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void {...@@ -174,21 +205,21 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void {
174 assert(l.sym_index != null); // we didn't process it already205 assert(l.sym_index != null); // we didn't process it already
175 const endian = self.base.options.target.cpu.arch.endian();206 const endian = self.base.options.target.cpu.arch.endian();
176 if (self.ptr_width == .p32) {207 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 data208 const callee_offset = @intCast(u32, reloc.callee.link.plan9.offset);
178 const off = reloc.offset_in_caller + l.offset;209 const off = self.takeAddr(@intCast(u32, reloc.offset_in_caller) + l.offset, reloc.caller.link.plan9.type);
179 std.mem.writeInt(u32, self.text_buf.items[off - 4 ..][0..4], callee_offset, endian);210 std.mem.writeInt(u32, self.text_buf.items[off - 4 ..][0..4], callee_offset, endian);
180 } else {211 } else {
181 const callee_offset = reloc.callee.link.plan9.offset + default_base_addr; // TODO this is different if its data212 const callee_offset = reloc.callee.link.plan9.offset;
182 const off = reloc.offset_in_caller + l.offset;213 const off = self.takeAddr(@intCast(u32, reloc.offset_in_caller) + l.offset, reloc.caller.link.plan9.type);
183 std.mem.writeInt(u64, self.text_buf.items[off - 8 ..][0..8], callee_offset, endian);214 std.mem.writeInt(u64, self.text_buf.items[off - 8 ..][0..8], callee_offset, endian);
184 }215 }
185 }216 }
186 }217 }
187218
188 // edata, end, etext219 // edata, end, etext
189 self.syms.items[0].value = 0x200000; // TODO make this number other place, and what is it?220 self.syms.items[0].value = self.getAddr(0x0, .b); // what is this number
190 self.syms.items[1].value = 0x200000; // TODO make this number other place, and what is it?221 self.syms.items[1].value = self.getAddr(0x0, .b); // what is this number
191 self.syms.items[2].value = self.text_buf.items.len;222 self.syms.items[2].value = self.getAddr(@intCast(u32, self.text_buf.items.len), .t);
192223
193 var sym_buf = std.ArrayList(u8).init(self.base.allocator);224 var sym_buf = std.ArrayList(u8).init(self.base.allocator);
194 defer sym_buf.deinit();225 defer sym_buf.deinit();
...@@ -248,25 +279,19 @@ pub fn updateDeclExports(...@@ -248,25 +279,19 @@ pub fn updateDeclExports(
248 }279 }
249 }280 }
250 if (std.mem.eql(u8, exp.options.name, "_start")) {281 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 _start282 std.debug.assert(decl.link.plan9.type == .t); // we tried to link a non-function as _start
252 self.hdr.entry = Plan9.default_base_addr + self.headerSize() + decl.link.plan9.offset;283 self.hdr.entry = self.bases.text + decl.link.plan9.offset;
253 }284 }
254 if (exp.link.plan9) |i| {285 if (exp.link.plan9) |i| {
255 self.syms.items[i] = .{286 self.syms.items[i] = .{
256 .value = decl.link.plan9.offset,287 .value = self.getAddr(decl.link.plan9.offset, decl.link.plan9.type),
257 .type = switch (decl.link.plan9.type) {288 .type = decl.link.plan9.type.toGlobal(),
258 .text => .T,
259 .data => .D,
260 },
261 .name = exp.options.name,289 .name = exp.options.name,
262 };290 };
263 } else {291 } else {
264 try self.syms.append(self.base.allocator, .{292 try self.syms.append(self.base.allocator, .{
265 .value = decl.link.plan9.offset,293 .value = self.getAddr(decl.link.plan9.offset, decl.link.plan9.type),
266 .type = switch (decl.link.plan9.type) {294 .type = decl.link.plan9.type.toGlobal(),
267 .text => .T,
268 .data => .D,
269 },
270 .name = exp.options.name,295 .name = exp.options.name,
271 });296 });
272 exp.link.plan9 = self.syms.items.len - 1;297 exp.link.plan9 = self.syms.items.len - 1;
...@@ -300,6 +325,8 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio...@@ -300,6 +325,8 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
300 if (std.builtin.mode == .Debug or std.builtin.mode == .ReleaseSafe)325 if (std.builtin.mode == .Debug or std.builtin.mode == .ReleaseSafe)
301 self.hdr.entry = 0x0;326 self.hdr.entry = 0x0;
302327
328 self.bases = defaultBaseAddrs(options.target.cpu.arch);
329
303 // first 3 symbols in our table are edata, end, etext330 // first 3 symbols in our table are edata, end, etext
304 try self.syms.appendSlice(self.base.allocator, &.{331 try self.syms.appendSlice(self.base.allocator, &.{
305 .{332 .{
...@@ -333,9 +360,9 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void {...@@ -333,9 +360,9 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void {
333 const writer = buf.writer();360 const writer = buf.writer();
334 for (self.syms.items) |sym| {361 for (self.syms.items) |sym| {
335 if (self.ptr_width == .p32) {362 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));
337 } else {364 } else {
338 try writer.writeIntBig(u64, sym.value + default_base_addr);365 try writer.writeIntBig(u64, sym.value);
339 }366 }
340 try writer.writeByte(@enumToInt(sym.type));367 try writer.writeByte(@enumToInt(sym.type));
341 try writer.writeAll(std.mem.span(sym.name));368 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 {...@@ -46,18 +46,10 @@ pub const ExecHdr = extern struct {
46 }46 }
47};47};
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};
57// uchar value[8];49// uchar value[8];
58// char type;50// char type;
59// char name[n]; /* NUL-terminated */51// char name[n]; /* NUL-terminated */
60pub const Sym64 = struct {52pub const Sym = struct {
61 value: u64, // big endian in the file53 value: u64, // big endian in the file
62 type: SymType,54 type: SymType,
63 name: []const u8,55 name: []const u8,
...@@ -93,6 +85,14 @@ pub const SymType = enum(u8) {...@@ -93,6 +85,14 @@ pub const SymType = enum(u8) {
93 z = 0x80 | 'z',85 z = 0x80 | 'z',
94 Z = 0x80 | 'Z',86 Z = 0x80 | 'Z',
95 m = 0x80 | 'm',87 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 }
96};96};
9797
98pub const HDR_MAGIC = 0x00008000;98pub const HDR_MAGIC = 0x00008000;