| ... | ... | @@ -24,13 +24,19 @@ bases: Bases, |
| 24 | 24 | decl_table: std.AutoArrayHashMapUnmanaged(*Module.Decl, void) = .{}, |
| 25 | 25 | /// is just casted down when 32 bit |
| 26 | 26 | syms: std.ArrayListUnmanaged(aout.Sym) = .{}, |
| 27 | | call_relocs: std.ArrayListUnmanaged(CallReloc) = .{}, |
| 28 | 27 | text_buf: std.ArrayListUnmanaged(u8) = .{}, |
| 29 | 28 | data_buf: std.ArrayListUnmanaged(u8) = .{}, |
| 30 | 29 | |
| 31 | | cur_decl: *Module.Decl = undefined, |
| 32 | 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 | 41 | fn getAddr(self: Plan9, addr: u32, t: aout.SymType) u32 { |
| 36 | 42 | return addr + switch (t) { |
| ... | ... | @@ -60,14 +66,17 @@ fn headerSize(self: Plan9) u32 { |
| 60 | 66 | |
| 61 | 67 | pub const DeclBlock = struct { |
| 62 | 68 | type: aout.SymType, |
| 63 | | // offset in the text or data sects |
| 64 | | offset: u32, |
| 65 | | // offset into syms |
| 69 | /// offset in the text or data sects |
| 70 | offset: ?u32, |
| 71 | /// offset into syms |
| 66 | 72 | sym_index: ?usize, |
| 73 | /// offset into got |
| 74 | got_index: ?usize, |
| 67 | 75 | pub const empty = DeclBlock{ |
| 68 | 76 | .type = .t, |
| 69 | | .offset = 0, |
| 77 | .offset = null, |
| 70 | 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 | 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 | 99 | pub const PtrWidth = enum { p32, p64 }; |
| 97 | 100 | |
| 98 | 101 | pub fn createEmpty(gpa: *Allocator, options: link.Options) !*Plan9 { |
| ... | ... | @@ -132,48 +135,89 @@ pub fn flush(self: *Plan9, comp: *Compilation) !void { |
| 132 | 135 | } |
| 133 | 136 | return self.flushModule(comp); |
| 134 | 137 | } |
| 138 | |
| 135 | 139 | pub fn flushModule(self: *Plan9, comp: *Compilation) !void { |
| 136 | 140 | const tracy = trace(@src()); |
| 137 | 141 | defer tracy.end(); |
| 138 | 142 | |
| 143 | log.debug("flushModule", .{}); |
| 144 | |
| 139 | 145 | defer assert(self.hdr.entry != 0x0); |
| 140 | 146 | |
| 141 | 147 | const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented; |
| 142 | 148 | |
| 143 | 149 | self.text_buf.items.len = 0; |
| 144 | 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 | 154 | // temporary buffer |
| 147 | 155 | var code_buffer = std.ArrayList(u8).init(self.base.allocator); |
| 148 | 156 | defer code_buffer.deinit(); |
| 149 | 157 | { |
| 150 | 158 | for (self.decl_table.keys()) |decl| { |
| 151 | 159 | if (!decl.has_tv) continue; |
| 152 | | self.cur_decl = decl; |
| 153 | 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 | 163 | decl.link.plan9 = if (is_fn) .{ |
| 155 | 164 | .offset = self.getAddr(@intCast(u32, self.text_buf.items.len), .t), |
| 156 | 165 | .type = .t, |
| 157 | 166 | .sym_index = decl.link.plan9.sym_index, |
| 167 | .got_index = decl.link.plan9.got_index, |
| 158 | 168 | } else .{ |
| 159 | 169 | .offset = self.getAddr(@intCast(u32, self.data_buf.items.len), .d), |
| 160 | | .type = .t, |
| 170 | .type = .d, |
| 161 | 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) { |
| 164 | | try self.syms.append(self.base.allocator, .{ |
| 165 | | .value = decl.link.plan9.offset, |
| 174 | self.got.items[decl.link.plan9.got_index.?] = decl.link.plan9.offset.?; |
| 175 | if (decl.link.plan9.sym_index) |s| { |
| 176 | self.syms.items[s] = .{ |
| 177 | .value = decl.link.plan9.offset.?, |
| 166 | 178 | .type = decl.link.plan9.type, |
| 167 | 179 | .name = mem.span(decl.name), |
| 168 | | }); |
| 169 | | decl.link.plan9.sym_index = self.syms.items.len - 1; |
| 180 | }; |
| 170 | 181 | } else { |
| 171 | | self.syms.items[decl.link.plan9.sym_index.?] = .{ |
| 172 | | .value = decl.link.plan9.offset, |
| 182 | try self.syms.append(self.base.allocator, .{ |
| 183 | .value = decl.link.plan9.offset.?, |
| 173 | 184 | .type = decl.link.plan9.type, |
| 174 | 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 | 221 | const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), .{ |
| 178 | 222 | .ty = decl.ty, |
| 179 | 223 | .val = decl.val, |
| ... | ... | @@ -190,32 +234,30 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void { |
| 190 | 234 | }; |
| 191 | 235 | if (is_fn) { |
| 192 | 236 | try self.text_buf.appendSlice(self.base.allocator, code); |
| 193 | | try code_buffer.resize(0); |
| 237 | code_buffer.items.len = 0; |
| 194 | 238 | } else { |
| 195 | 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. |
| 202 | | { |
| 203 | | for (self.call_relocs.items) |reloc| { |
| 204 | | const l: DeclBlock = reloc.caller.link.plan9; |
| 205 | | assert(l.sym_index != null); // we didn't process it already |
| 206 | | const endian = self.base.options.target.cpu.arch.endian(); |
| 207 | | if (self.ptr_width == .p32) { |
| 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); |
| 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 | | } |
| 245 | // write the got |
| 246 | if (self.ptr_width == .p32) { |
| 247 | for (self.got.items) |p, i| { |
| 248 | mem.writeInt(u32, self.data_buf.items[i * 4 ..][0..4], @intCast(u32, p), self.base.options.target.cpu.arch.endian()); |
| 249 | } |
| 250 | } else { |
| 251 | for (self.got.items) |p, i| { |
| 252 | mem.writeInt(u64, self.data_buf.items[i * 8 ..][0..8], p, self.base.options.target.cpu.arch.endian()); |
| 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 | 261 | // edata, end, etext |
| 220 | 262 | self.syms.items[0].value = self.getAddr(0x0, .b); // what is this number |
| 221 | 263 | self.syms.items[1].value = self.getAddr(0x0, .b); // what is this number |
| ... | ... | @@ -267,43 +309,14 @@ pub fn updateDeclExports( |
| 267 | 309 | decl: *Module.Decl, |
| 268 | 310 | exports: []const *Module.Export, |
| 269 | 311 | ) !void { |
| 270 | | for (exports) |exp| { |
| 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 | | } |
| 312 | // we do all the things in flush |
| 300 | 313 | } |
| 301 | 314 | pub fn deinit(self: *Plan9) void { |
| 302 | 315 | self.decl_table.deinit(self.base.allocator); |
| 303 | | self.call_relocs.deinit(self.base.allocator); |
| 304 | 316 | self.syms.deinit(self.base.allocator); |
| 305 | 317 | self.text_buf.deinit(self.base.allocator); |
| 306 | 318 | self.data_buf.deinit(self.base.allocator); |
| 319 | self.got.deinit(self.base.allocator); |
| 307 | 320 | } |
| 308 | 321 | |
| 309 | 322 | pub const Export = ?usize; |
| ... | ... | @@ -350,12 +363,6 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio |
| 350 | 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 | 366 | pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void { |
| 360 | 367 | const writer = buf.writer(); |
| 361 | 368 | for (self.syms.items) |sym| { |
| ... | ... | @@ -369,3 +376,8 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void { |
| 369 | 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 | } |