| ... | @@ -19,37 +19,73 @@ const assert = std.debug.assert; | ... | @@ -19,37 +19,73 @@ const assert = std.debug.assert; |
| 19 | base: link.File, | 19 | base: link.File, |
| 20 | ptr_width: PtrWidth, | 20 | ptr_width: PtrWidth, |
| 21 | error_flags: File.ErrorFlags = File.ErrorFlags{}, | 21 | error_flags: File.ErrorFlags = File.ErrorFlags{}, |
| | 22 | bases: Bases, |
| 22 | | 23 | |
| 23 | decl_table: std.AutoArrayHashMapUnmanaged(*Module.Decl, void) = .{}, | 24 | decl_table: std.AutoArrayHashMapUnmanaged(*Module.Decl, void) = .{}, |
| 24 | /// is just casted down when 32 bit | 25 | /// is just casted down when 32 bit |
| 25 | syms: std.ArrayListUnmanaged(aout.Sym64) = .{}, | 26 | syms: std.ArrayListUnmanaged(aout.Sym) = .{}, |
| 26 | call_relocs: std.ArrayListUnmanaged(CallReloc) = .{}, | 27 | call_relocs: std.ArrayListUnmanaged(CallReloc) = .{}, |
| 27 | text_buf: std.ArrayListUnmanaged(u8) = .{}, | 28 | text_buf: std.ArrayListUnmanaged(u8) = .{}, |
| 28 | data_buf: std.ArrayListUnmanaged(u8) = .{}, | 29 | data_buf: std.ArrayListUnmanaged(u8) = .{}, |
| 29 | | 30 | |
| 30 | cur_decl: *Module.Decl = undefined, | 31 | cur_decl: *Module.Decl = undefined, |
| 31 | hdr: aout.ExecHdr = undefined, | 32 | hdr: aout.ExecHdr = undefined, |
| | 33 | const Bases = struct { text: u32, data: u32 }; |
| | 34 | |
| | 35 | fn 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 |
| | 43 | fn 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 | |
| | 51 | fn getSymAddr(self: Plan9, s: aout.Sym) u32 { |
| | 52 | return self.getAddr(@intCast(u32, s.value), s.type); |
| | 53 | } |
| 32 | | 54 | |
| 33 | fn headerSize(self: Plan9) u32 { | 55 | fn 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 | |
| 38 | pub const DeclBlock = struct { | 61 | pub const DeclBlock = struct { |
| 39 | type: enum { text, data }, | 62 | type: aout.SymType, |
| 40 | // offset in the text or data sects | 63 | // offset in the text or data sects |
| 41 | offset: u32, | 64 | offset: u32, |
| 42 | // offset into syms | 65 | // 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 | }; |
| 50 | | 73 | |
| 51 | // TODO change base addr based on target (and section?) (right now it just works on amd64) | 74 | pub fn defaultBaseAddrs(arch: std.Target.Cpu.Arch) Bases { |
| 52 | const 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 | } |
| 53 | | 89 | |
| 54 | pub const CallReloc = struct { | 90 | pub 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 already | 205 | 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 data | 208 | 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 data | 212 | 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 | } |
| 187 | | 218 | |
| 188 | // edata, end, etext | 219 | // 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); |
| 192 | | 223 | |
| 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 _start | 282 | 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; |
| 302 | | 327 | |
| | 328 | self.bases = defaultBaseAddrs(options.target.cpu.arch); |
| | 329 | |
| 303 | // first 3 symbols in our table are edata, end, etext | 330 | // 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)); |