| ... | @@ -24,13 +24,19 @@ bases: Bases, | ... | @@ -24,13 +24,19 @@ bases: Bases, |
| 24 | decl_table: std.AutoArrayHashMapUnmanaged(*Module.Decl, void) = .{}, | 24 | decl_table: std.AutoArrayHashMapUnmanaged(*Module.Decl, void) = .{}, |
| 25 | /// is just casted down when 32 bit | 25 | /// is just casted down when 32 bit |
| 26 | syms: std.ArrayListUnmanaged(aout.Sym) = .{}, | 26 | syms: std.ArrayListUnmanaged(aout.Sym) = .{}, |
| 27 | call_relocs: std.ArrayListUnmanaged(CallReloc) = .{}, | | |
| 28 | text_buf: std.ArrayListUnmanaged(u8) = .{}, | 27 | text_buf: std.ArrayListUnmanaged(u8) = .{}, |
| 29 | data_buf: std.ArrayListUnmanaged(u8) = .{}, | 28 | data_buf: std.ArrayListUnmanaged(u8) = .{}, |
| 30 | | 29 | |
| 31 | cur_decl: *Module.Decl = undefined, | | |
| 32 | hdr: aout.ExecHdr = undefined, | 30 | hdr: aout.ExecHdr = undefined, |
| 33 | const Bases = struct { text: u32, data: u32 }; | 31 | |
| | 32 | entry_decl: ?*Module.Decl = null, |
| | 33 | |
| | 34 | got: std.ArrayListUnmanaged(u64) = .{}, |
| | 35 | const Bases = struct { |
| | 36 | text: u32, |
| | 37 | /// the addr of the got |
| | 38 | data: u32, |
| | 39 | }; |
| 34 | | 40 | |
| 35 | fn getAddr(self: Plan9, addr: u32, t: aout.SymType) u32 { | 41 | fn 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 { |
| 60 | | 66 | |
| 61 | pub const DeclBlock = struct { | 67 | pub const DeclBlock = struct { |
| 62 | type: aout.SymType, | 68 | type: aout.SymType, |
| 63 | // offset in the text or data sects | 69 | /// offset in the text or data sects |
| 64 | offset: u32, | 70 | offset: ?u32, |
| 65 | // offset into syms | 71 | /// 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 | }; |
| 73 | | 82 | |
| ... | @@ -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 | } |
| 89 | | 98 | |
| 90 | pub const CallReloc = struct { | | |
| 91 | caller: *Module.Decl, | | |
| 92 | callee: *Module.Decl, | | |
| 93 | offset_in_caller: usize, | | |
| 94 | }; | | |
| 95 | | | |
| 96 | pub const PtrWidth = enum { p32, p64 }; | 99 | pub const PtrWidth = enum { p32, p64 }; |
| 97 | | 100 | |
| 98 | pub fn createEmpty(gpa: *Allocator, options: link.Options) !*Plan9 { | 101 | pub 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 | |
| 135 | pub fn flushModule(self: *Plan9, comp: *Compilation) !void { | 139 | pub 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(); |
| 138 | | 142 | |
| | 143 | log.debug("flushModule", .{}); |
| | 144 | |
| 139 | defer assert(self.hdr.entry != 0x0); | 145 | defer assert(self.hdr.entry != 0x0); |
| 140 | | 146 | |
| 141 | const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented; | 147 | const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented; |
| 142 | | 148 | |
| 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 buffer | 154 | // 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 | } |
| 200 | | 244 | |
| 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 already | 249 | } |
| 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 | } |
| 218 | | 255 | |
| | 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, etext | 261 | // edata, end, etext |
| 220 | self.syms.items[0].value = self.getAddr(0x0, .b); // what is this number | 262 | 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 | 263 | 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 | } |
| 301 | pub fn deinit(self: *Plan9) void { | 314 | pub 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 | } |
| 308 | | 321 | |
| 309 | pub const Export = ?usize; | 322 | pub 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 | } |
| 352 | | 365 | |
| 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 | | |
| 355 | pub fn addCallReloc(self: *Plan9, code: *std.ArrayList(u8), reloc: CallReloc) !void { | | |
| 356 | try self.call_relocs.append(self.base.allocator, reloc); | | |
| 357 | } | | |
| 358 | | | |
| 359 | pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void { | 366 | pub 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 | |
| | 380 | pub 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 | } |