| ... | ... | @@ -19,37 +19,73 @@ const assert = std.debug.assert; |
| 19 | 19 | base: link.File, |
| 20 | 20 | ptr_width: PtrWidth, |
| 21 | 21 | error_flags: File.ErrorFlags = File.ErrorFlags{}, |
| 22 | bases: Bases, |
| 22 | 23 | |
| 23 | 24 | decl_table: std.AutoArrayHashMapUnmanaged(*Module.Decl, void) = .{}, |
| 24 | 25 | /// is just casted down when 32 bit |
| 25 | | syms: std.ArrayListUnmanaged(aout.Sym64) = .{}, |
| 26 | syms: std.ArrayListUnmanaged(aout.Sym) = .{}, |
| 26 | 27 | call_relocs: std.ArrayListUnmanaged(CallReloc) = .{}, |
| 27 | 28 | text_buf: std.ArrayListUnmanaged(u8) = .{}, |
| 28 | 29 | data_buf: std.ArrayListUnmanaged(u8) = .{}, |
| 29 | 30 | |
| 30 | 31 | cur_decl: *Module.Decl = undefined, |
| 31 | 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 | 55 | fn headerSize(self: Plan9) u32 { |
| 34 | 56 | // fat header (currently unused) |
| 35 | 57 | const fat: u8 = if (self.ptr_width == .p64) 8 else 0; |
| 36 | 58 | return @sizeOf(aout.ExecHdr) + fat; |
| 37 | 59 | } |
| 60 | |
| 38 | 61 | pub const DeclBlock = struct { |
| 39 | | type: enum { text, data }, |
| 62 | type: aout.SymType, |
| 40 | 63 | // offset in the text or data sects |
| 41 | 64 | offset: u32, |
| 42 | 65 | // offset into syms |
| 43 | 66 | sym_index: ?usize, |
| 44 | 67 | pub const empty = DeclBlock{ |
| 45 | | .type = .text, |
| 68 | .type = .t, |
| 46 | 69 | .offset = 0, |
| 47 | 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) |
| 52 | | const default_base_addr = 0x00200028; |
| 74 | pub 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 | } |
| 53 | 89 | |
| 54 | 90 | pub const CallReloc = struct { |
| 55 | 91 | caller: *Module.Decl, |
| ... | ... | @@ -76,6 +112,7 @@ pub fn createEmpty(gpa: *Allocator, options: link.Options) !*Plan9 { |
| 76 | 112 | .file = null, |
| 77 | 113 | }, |
| 78 | 114 | .ptr_width = ptr_width, |
| 115 | .bases = undefined, |
| 79 | 116 | }; |
| 80 | 117 | return self; |
| 81 | 118 | } |
| ... | ... | @@ -115,31 +152,25 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void { |
| 115 | 152 | self.cur_decl = decl; |
| 116 | 153 | const is_fn = (decl.ty.zigTypeTag() == .Fn); |
| 117 | 154 | 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, |
| 120 | 157 | .sym_index = decl.link.plan9.sym_index, |
| 121 | 158 | } 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, |
| 124 | 161 | .sym_index = decl.link.plan9.sym_index, |
| 125 | 162 | }; |
| 126 | 163 | if (decl.link.plan9.sym_index == null) { |
| 127 | 164 | try self.syms.append(self.base.allocator, .{ |
| 128 | 165 | .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, |
| 133 | 167 | .name = mem.span(decl.name), |
| 134 | 168 | }); |
| 135 | 169 | decl.link.plan9.sym_index = self.syms.items.len - 1; |
| 136 | 170 | } else { |
| 137 | 171 | self.syms.items[decl.link.plan9.sym_index.?] = .{ |
| 138 | 172 | .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, |
| 143 | 174 | .name = mem.span(decl.name), |
| 144 | 175 | }; |
| 145 | 176 | } |
| ... | ... | @@ -174,21 +205,21 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void { |
| 174 | 205 | assert(l.sym_index != null); // we didn't process it already |
| 175 | 206 | const endian = self.base.options.target.cpu.arch.endian(); |
| 176 | 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 |
| 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); |
| 179 | 210 | std.mem.writeInt(u32, self.text_buf.items[off - 4 ..][0..4], callee_offset, endian); |
| 180 | 211 | } 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); |
| 183 | 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 | 219 | // 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); |
| 192 | 223 | |
| 193 | 224 | var sym_buf = std.ArrayList(u8).init(self.base.allocator); |
| 194 | 225 | defer sym_buf.deinit(); |
| ... | ... | @@ -248,25 +279,19 @@ pub fn updateDeclExports( |
| 248 | 279 | } |
| 249 | 280 | } |
| 250 | 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 |
| 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; |
| 253 | 284 | } |
| 254 | 285 | if (exp.link.plan9) |i| { |
| 255 | 286 | 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(), |
| 261 | 289 | .name = exp.options.name, |
| 262 | 290 | }; |
| 263 | 291 | } else { |
| 264 | 292 | 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(), |
| 270 | 295 | .name = exp.options.name, |
| 271 | 296 | }); |
| 272 | 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 | 325 | if (std.builtin.mode == .Debug or std.builtin.mode == .ReleaseSafe) |
| 301 | 326 | self.hdr.entry = 0x0; |
| 302 | 327 | |
| 328 | self.bases = defaultBaseAddrs(options.target.cpu.arch); |
| 329 | |
| 303 | 330 | // first 3 symbols in our table are edata, end, etext |
| 304 | 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 | 360 | const writer = buf.writer(); |
| 334 | 361 | for (self.syms.items) |sym| { |
| 335 | 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 | 364 | } else { |
| 338 | | try writer.writeIntBig(u64, sym.value + default_base_addr); |
| 365 | try writer.writeIntBig(u64, sym.value); |
| 339 | 366 | } |
| 340 | 367 | try writer.writeByte(@enumToInt(sym.type)); |
| 341 | 368 | try writer.writeAll(std.mem.span(sym.name)); |