| author | |
| committer | |
| log | 5944e89016219138f6d5d9c818c7ce323eb64c1d |
| tree | 611427b002732130e0b2112bf5bf4c3fbd1f8432 |
| parent | 21135387fb7c2dbaf70a72f2c97341e9c1307045 |
* link: add a virtual function `lowerUnnamedConsts`, similar to
`updateFunc` or `updateDecl` which needs to be implemented by the
linker backend in order to be used with the `CodeGen` code
* elf: implement `lowerUnnamedConsts` specialization where we
lower unnamed constants to `.rodata` section. We keep track of the
atoms encompassing the lowered unnamed consts in a global table
indexed by parent `Decl`. When the `Decl` is updated or destroyed,
we clear the unnamed consts referenced within the `Decl`.
* macho: implement `lowerUnnamedConsts` specialization where we
lower unnamed constants to `__TEXT,__const` section. We keep track of the
atoms encompassing the lowered unnamed consts in a global table
indexed by parent `Decl`. When the `Decl` is updated or destroyed,
we clear the unnamed consts referenced within the `Decl`.
* x64: change `MCValue.linker_sym_index` into two `MCValue`s: `.got_load` and
`.direct_load`. The former signifies to the emitter that it should
emit a GOT load relocation, while the latter that it should emit
a direct load (`SIGNED`) relocation.
* x64: lower `struct` instantiations14 files changed, 772 insertions(+), 248 deletions(-)
src/arch/x86_64/CodeGen.zig+67-24| ... | @@ -118,10 +118,14 @@ pub const MCValue = union(enum) { | ... | @@ -118,10 +118,14 @@ pub const MCValue = union(enum) { |
| 118 | /// The value is in memory at a hard-coded address. | 118 | /// The value is in memory at a hard-coded address. |
| 119 | /// If the type is a pointer, it means the pointer address is at this memory location. | 119 | /// If the type is a pointer, it means the pointer address is at this memory location. |
| 120 | memory: u64, | 120 | memory: u64, |
| 121 | /// The value is in memory but not allocated an address yet by the linker, so we store | 121 | /// The value is in memory referenced indirectly via a GOT entry index. |
| 122 | /// the symbol index instead. | 122 | /// If the type is a pointer, it means the pointer is referenced indirectly via GOT. |
| 123 | /// If the type is a pointer, it means the pointer is the symbol. | 123 | /// When lowered, linker will emit a relocation of type X86_64_RELOC_GOT. |
| 124 | linker_sym_index: u32, | 124 | got_load: u32, |
| 125 | /// The value is in memory referenced directly via symbol index. | ||
| 126 | /// If the type is a pointer, it means the pointer is referenced directly via symbol index. | ||
| 127 | /// When lowered, linker will emit a relocation of type X86_64_RELOC_SIGNED. | ||
| 128 | direct_load: u32, | ||
| 125 | /// The value is one of the stack variables. | 129 | /// The value is one of the stack variables. |
| 126 | /// If the type is a pointer, it means the pointer address is in the stack at this offset. | 130 | /// If the type is a pointer, it means the pointer address is in the stack at this offset. |
| 127 | stack_offset: i32, | 131 | stack_offset: i32, |
| ... | @@ -1691,7 +1695,8 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo | ... | @@ -1691,7 +1695,8 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 1691 | } | 1695 | } |
| 1692 | }, | 1696 | }, |
| 1693 | .memory, | 1697 | .memory, |
| 1694 | .linker_sym_index, | 1698 | .got_load, |
| 1699 | .direct_load, | ||
| 1695 | => { | 1700 | => { |
| 1696 | const reg = try self.copyToTmpRegister(ptr_ty, ptr); | 1701 | const reg = try self.copyToTmpRegister(ptr_ty, ptr); |
| 1697 | try self.load(dst_mcv, .{ .register = reg }, ptr_ty); | 1702 | try self.load(dst_mcv, .{ .register = reg }, ptr_ty); |
| ... | @@ -1823,7 +1828,8 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type | ... | @@ -1823,7 +1828,8 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 1823 | }, | 1828 | }, |
| 1824 | } | 1829 | } |
| 1825 | }, | 1830 | }, |
| 1826 | .linker_sym_index, | 1831 | .got_load, |
| 1832 | .direct_load, | ||
| 1827 | .memory, | 1833 | .memory, |
| 1828 | => { | 1834 | => { |
| 1829 | value.freezeIfRegister(&self.register_manager); | 1835 | value.freezeIfRegister(&self.register_manager); |
| ... | @@ -1831,15 +1837,22 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type | ... | @@ -1831,15 +1837,22 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 1831 | 1837 | ||
| 1832 | const addr_reg: Register = blk: { | 1838 | const addr_reg: Register = blk: { |
| 1833 | switch (ptr) { | 1839 | switch (ptr) { |
| 1834 | .linker_sym_index => |sym_index| { | 1840 | .got_load, |
| 1841 | .direct_load, | ||
| 1842 | => |sym_index| { | ||
| 1843 | const flags: u2 = switch (ptr) { | ||
| 1844 | .got_load => 0b00, | ||
| 1845 | .direct_load => 0b01, | ||
| 1846 | else => unreachable, | ||
| 1847 | }; | ||
| 1835 | const addr_reg = try self.register_manager.allocReg(null); | 1848 | const addr_reg = try self.register_manager.allocReg(null); |
| 1836 | _ = try self.addInst(.{ | 1849 | _ = try self.addInst(.{ |
| 1837 | .tag = .lea, | 1850 | .tag = .lea_pie, |
| 1838 | .ops = (Mir.Ops{ | 1851 | .ops = (Mir.Ops{ |
| 1839 | .reg1 = addr_reg.to64(), | 1852 | .reg1 = addr_reg.to64(), |
| 1840 | .flags = 0b10, | 1853 | .flags = flags, |
| 1841 | }).encode(), | 1854 | }).encode(), |
| 1842 | .data = .{ .got_entry = sym_index }, | 1855 | .data = .{ .linker_sym_index = sym_index }, |
| 1843 | }); | 1856 | }); |
| 1844 | break :blk addr_reg; | 1857 | break :blk addr_reg; |
| 1845 | }, | 1858 | }, |
| ... | @@ -2160,7 +2173,7 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC | ... | @@ -2160,7 +2173,7 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC |
| 2160 | .embedded_in_code, .memory => { | 2173 | .embedded_in_code, .memory => { |
| 2161 | return self.fail("TODO implement x86 ADD/SUB/CMP source memory", .{}); | 2174 | return self.fail("TODO implement x86 ADD/SUB/CMP source memory", .{}); |
| 2162 | }, | 2175 | }, |
| 2163 | .linker_sym_index => { | 2176 | .got_load, .direct_load => { |
| 2164 | return self.fail("TODO implement x86 ADD/SUB/CMP source symbol at index in linker", .{}); | 2177 | return self.fail("TODO implement x86 ADD/SUB/CMP source symbol at index in linker", .{}); |
| 2165 | }, | 2178 | }, |
| 2166 | .stack_offset => |off| { | 2179 | .stack_offset => |off| { |
| ... | @@ -2247,7 +2260,7 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC | ... | @@ -2247,7 +2260,7 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC |
| 2247 | .embedded_in_code, .memory, .stack_offset => { | 2260 | .embedded_in_code, .memory, .stack_offset => { |
| 2248 | return self.fail("TODO implement x86 ADD/SUB/CMP source memory", .{}); | 2261 | return self.fail("TODO implement x86 ADD/SUB/CMP source memory", .{}); |
| 2249 | }, | 2262 | }, |
| 2250 | .linker_sym_index => { | 2263 | .got_load, .direct_load => { |
| 2251 | return self.fail("TODO implement x86 ADD/SUB/CMP source symbol at index in linker", .{}); | 2264 | return self.fail("TODO implement x86 ADD/SUB/CMP source symbol at index in linker", .{}); |
| 2252 | }, | 2265 | }, |
| 2253 | .compare_flags_unsigned => { | 2266 | .compare_flags_unsigned => { |
| ... | @@ -2261,7 +2274,7 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC | ... | @@ -2261,7 +2274,7 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC |
| 2261 | .embedded_in_code, .memory => { | 2274 | .embedded_in_code, .memory => { |
| 2262 | return self.fail("TODO implement x86 ADD/SUB/CMP destination memory", .{}); | 2275 | return self.fail("TODO implement x86 ADD/SUB/CMP destination memory", .{}); |
| 2263 | }, | 2276 | }, |
| 2264 | .linker_sym_index => { | 2277 | .got_load, .direct_load => { |
| 2265 | return self.fail("TODO implement x86 ADD/SUB/CMP destination symbol at index", .{}); | 2278 | return self.fail("TODO implement x86 ADD/SUB/CMP destination symbol at index", .{}); |
| 2266 | }, | 2279 | }, |
| 2267 | } | 2280 | } |
| ... | @@ -2317,7 +2330,7 @@ fn genIMulOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) ! | ... | @@ -2317,7 +2330,7 @@ fn genIMulOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) ! |
| 2317 | .embedded_in_code, .memory, .stack_offset => { | 2330 | .embedded_in_code, .memory, .stack_offset => { |
| 2318 | return self.fail("TODO implement x86 multiply source memory", .{}); | 2331 | return self.fail("TODO implement x86 multiply source memory", .{}); |
| 2319 | }, | 2332 | }, |
| 2320 | .linker_sym_index => { | 2333 | .got_load, .direct_load => { |
| 2321 | return self.fail("TODO implement x86 multiply source symbol at index in linker", .{}); | 2334 | return self.fail("TODO implement x86 multiply source symbol at index in linker", .{}); |
| 2322 | }, | 2335 | }, |
| 2323 | .compare_flags_unsigned => { | 2336 | .compare_flags_unsigned => { |
| ... | @@ -2358,7 +2371,7 @@ fn genIMulOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) ! | ... | @@ -2358,7 +2371,7 @@ fn genIMulOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) ! |
| 2358 | .embedded_in_code, .memory, .stack_offset => { | 2371 | .embedded_in_code, .memory, .stack_offset => { |
| 2359 | return self.fail("TODO implement x86 multiply source memory", .{}); | 2372 | return self.fail("TODO implement x86 multiply source memory", .{}); |
| 2360 | }, | 2373 | }, |
| 2361 | .linker_sym_index => { | 2374 | .got_load, .direct_load => { |
| 2362 | return self.fail("TODO implement x86 multiply source symbol at index in linker", .{}); | 2375 | return self.fail("TODO implement x86 multiply source symbol at index in linker", .{}); |
| 2363 | }, | 2376 | }, |
| 2364 | .compare_flags_unsigned => { | 2377 | .compare_flags_unsigned => { |
| ... | @@ -2372,7 +2385,7 @@ fn genIMulOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) ! | ... | @@ -2372,7 +2385,7 @@ fn genIMulOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) ! |
| 2372 | .embedded_in_code, .memory => { | 2385 | .embedded_in_code, .memory => { |
| 2373 | return self.fail("TODO implement x86 multiply destination memory", .{}); | 2386 | return self.fail("TODO implement x86 multiply destination memory", .{}); |
| 2374 | }, | 2387 | }, |
| 2375 | .linker_sym_index => { | 2388 | .got_load, .direct_load => { |
| 2376 | return self.fail("TODO implement x86 multiply destination symbol at index in linker", .{}); | 2389 | return self.fail("TODO implement x86 multiply destination symbol at index in linker", .{}); |
| 2377 | }, | 2390 | }, |
| 2378 | } | 2391 | } |
| ... | @@ -2478,7 +2491,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2478,7 +2491,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void { |
| 2478 | .dead => unreachable, | 2491 | .dead => unreachable, |
| 2479 | .embedded_in_code => unreachable, | 2492 | .embedded_in_code => unreachable, |
| 2480 | .memory => unreachable, | 2493 | .memory => unreachable, |
| 2481 | .linker_sym_index => unreachable, | 2494 | .got_load => unreachable, |
| 2495 | .direct_load => unreachable, | ||
| 2482 | .compare_flags_signed => unreachable, | 2496 | .compare_flags_signed => unreachable, |
| 2483 | .compare_flags_unsigned => unreachable, | 2497 | .compare_flags_unsigned => unreachable, |
| 2484 | } | 2498 | } |
| ... | @@ -2540,7 +2554,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2540,7 +2554,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void { |
| 2540 | if (func_value.castTag(.function)) |func_payload| { | 2554 | if (func_value.castTag(.function)) |func_payload| { |
| 2541 | const func = func_payload.data; | 2555 | const func = func_payload.data; |
| 2542 | try self.genSetReg(Type.initTag(.usize), .rax, .{ | 2556 | try self.genSetReg(Type.initTag(.usize), .rax, .{ |
| 2543 | .linker_sym_index = func.owner_decl.link.macho.local_sym_index, | 2557 | .got_load = func.owner_decl.link.macho.local_sym_index, |
| 2544 | }); | 2558 | }); |
| 2545 | // callq *%rax | 2559 | // callq *%rax |
| 2546 | _ = try self.addInst(.{ | 2560 | _ = try self.addInst(.{ |
| ... | @@ -3576,7 +3590,8 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro | ... | @@ -3576,7 +3590,8 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro |
| 3576 | }, | 3590 | }, |
| 3577 | .memory, | 3591 | .memory, |
| 3578 | .embedded_in_code, | 3592 | .embedded_in_code, |
| 3579 | .linker_sym_index, | 3593 | .got_load, |
| 3594 | .direct_load, | ||
| 3580 | => { | 3595 | => { |
| 3581 | if (ty.abiSize(self.target.*) <= 8) { | 3596 | if (ty.abiSize(self.target.*) <= 8) { |
| 3582 | const reg = try self.copyToTmpRegister(ty, mcv); | 3597 | const reg = try self.copyToTmpRegister(ty, mcv); |
| ... | @@ -3982,14 +3997,21 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void | ... | @@ -3982,14 +3997,21 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 3982 | .data = undefined, | 3997 | .data = undefined, |
| 3983 | }); | 3998 | }); |
| 3984 | }, | 3999 | }, |
| 3985 | .linker_sym_index => |sym_index| { | 4000 | .got_load, |
| 4001 | .direct_load, | ||
| 4002 | => |sym_index| { | ||
| 4003 | const flags: u2 = switch (mcv) { | ||
| 4004 | .got_load => 0b00, | ||
| 4005 | .direct_load => 0b01, | ||
| 4006 | else => unreachable, | ||
| 4007 | }; | ||
| 3986 | _ = try self.addInst(.{ | 4008 | _ = try self.addInst(.{ |
| 3987 | .tag = .lea, | 4009 | .tag = .lea_pie, |
| 3988 | .ops = (Mir.Ops{ | 4010 | .ops = (Mir.Ops{ |
| 3989 | .reg1 = reg, | 4011 | .reg1 = reg, |
| 3990 | .flags = 0b10, | 4012 | .flags = flags, |
| 3991 | }).encode(), | 4013 | }).encode(), |
| 3992 | .data = .{ .got_entry = sym_index }, | 4014 | .data = .{ .linker_sym_index = sym_index }, |
| 3993 | }); | 4015 | }); |
| 3994 | // MOV reg, [reg] | 4016 | // MOV reg, [reg] |
| 3995 | _ = try self.addInst(.{ | 4017 | _ = try self.addInst(.{ |
| ... | @@ -4316,7 +4338,7 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl: *Module.Decl) InnerError!MCVa | ... | @@ -4316,7 +4338,7 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl: *Module.Decl) InnerError!MCVa |
| 4316 | } else if (self.bin_file.cast(link.File.MachO)) |_| { | 4338 | } else if (self.bin_file.cast(link.File.MachO)) |_| { |
| 4317 | // Because MachO is PIE-always-on, we defer memory address resolution until | 4339 | // Because MachO is PIE-always-on, we defer memory address resolution until |
| 4318 | // the linker has enough info to perform relocations. | 4340 | // the linker has enough info to perform relocations. |
| 4319 | return MCValue{ .linker_sym_index = decl.link.macho.local_sym_index }; | 4341 | return MCValue{ .got_load = decl.link.macho.local_sym_index }; |
| 4320 | } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { | 4342 | } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { |
| 4321 | const got_addr = coff_file.offset_table_virtual_address + decl.link.coff.offset_table_index * ptr_bytes; | 4343 | const got_addr = coff_file.offset_table_virtual_address + decl.link.coff.offset_table_index * ptr_bytes; |
| 4322 | return MCValue{ .memory = got_addr }; | 4344 | return MCValue{ .memory = got_addr }; |
| ... | @@ -4331,6 +4353,24 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl: *Module.Decl) InnerError!MCVa | ... | @@ -4331,6 +4353,24 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl: *Module.Decl) InnerError!MCVa |
| 4331 | _ = tv; | 4353 | _ = tv; |
| 4332 | } | 4354 | } |
| 4333 | 4355 | ||
| 4356 | fn lowerUnnamedConst(self: *Self, tv: TypedValue) InnerError!MCValue { | ||
| 4357 | const local_sym_index = self.bin_file.lowerUnnamedConst(tv, self.mod_fn.owner_decl) catch |err| { | ||
| 4358 | return self.fail("lowering unnamed constant failed: {s}", .{@errorName(err)}); | ||
| 4359 | }; | ||
| 4360 | if (self.bin_file.cast(link.File.Elf)) |elf_file| { | ||
| 4361 | const vaddr = elf_file.local_symbols.items[local_sym_index].st_value; | ||
| 4362 | return MCValue{ .memory = vaddr }; | ||
| 4363 | } else if (self.bin_file.cast(link.File.MachO)) |_| { | ||
| 4364 | return MCValue{ .direct_load = local_sym_index }; | ||
| 4365 | } else if (self.bin_file.cast(link.File.Coff)) |_| { | ||
| 4366 | return self.fail("TODO lower unnamed const in COFF", .{}); | ||
| 4367 | } else if (self.bin_file.cast(link.File.Plan9)) |_| { | ||
| 4368 | return self.fail("TODO lower unnamed const in Plan9", .{}); | ||
| 4369 | } else { | ||
| 4370 | return self.fail("TODO lower unnamed const", .{}); | ||
| 4371 | } | ||
| 4372 | } | ||
| 4373 | |||
| 4334 | fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { | 4374 | fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { |
| 4335 | if (typed_value.val.isUndef()) | 4375 | if (typed_value.val.isUndef()) |
| 4336 | return MCValue{ .undef = {} }; | 4376 | return MCValue{ .undef = {} }; |
| ... | @@ -4446,6 +4486,9 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { | ... | @@ -4446,6 +4486,9 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { |
| 4446 | 4486 | ||
| 4447 | return self.fail("TODO implement error union const of type '{}' (error)", .{typed_value.ty}); | 4487 | return self.fail("TODO implement error union const of type '{}' (error)", .{typed_value.ty}); |
| 4448 | }, | 4488 | }, |
| 4489 | .Struct => { | ||
| 4490 | return self.lowerUnnamedConst(typed_value); | ||
| 4491 | }, | ||
| 4449 | else => return self.fail("TODO implement const of type '{}'", .{typed_value.ty}), | 4492 | else => return self.fail("TODO implement const of type '{}'", .{typed_value.ty}), |
| 4450 | } | 4493 | } |
| 4451 | } | 4494 | } |
src/arch/x86_64/Emit.zig+41-30| ... | @@ -131,6 +131,7 @@ pub fn lowerMir(emit: *Emit) InnerError!void { | ... | @@ -131,6 +131,7 @@ pub fn lowerMir(emit: *Emit) InnerError!void { |
| 131 | .movabs => try emit.mirMovabs(inst), | 131 | .movabs => try emit.mirMovabs(inst), |
| 132 | 132 | ||
| 133 | .lea => try emit.mirLea(inst), | 133 | .lea => try emit.mirLea(inst), |
| 134 | .lea_pie => try emit.mirLeaPie(inst), | ||
| 134 | 135 | ||
| 135 | .imul_complex => try emit.mirIMulComplex(inst), | 136 | .imul_complex => try emit.mirIMulComplex(inst), |
| 136 | 137 | ||
| ... | @@ -706,36 +707,6 @@ fn mirLea(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { | ... | @@ -706,36 +707,6 @@ fn mirLea(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { |
| 706 | mem.writeIntLittle(i32, emit.code.items[end_offset - 4 ..][0..4], disp); | 707 | mem.writeIntLittle(i32, emit.code.items[end_offset - 4 ..][0..4], disp); |
| 707 | }, | 708 | }, |
| 708 | 0b10 => { | 709 | 0b10 => { |
| 709 | // lea reg1, [rip + reloc] | ||
| 710 | // RM | ||
| 711 | try lowerToRmEnc( | ||
| 712 | .lea, | ||
| 713 | ops.reg1, | ||
| 714 | RegisterOrMemory.rip(Memory.PtrSize.fromBits(ops.reg1.size()), 0), | ||
| 715 | emit.code, | ||
| 716 | ); | ||
| 717 | const end_offset = emit.code.items.len; | ||
| 718 | const got_entry = emit.mir.instructions.items(.data)[inst].got_entry; | ||
| 719 | if (emit.bin_file.cast(link.File.MachO)) |macho_file| { | ||
| 720 | // TODO I think the reloc might be in the wrong place. | ||
| 721 | const decl = macho_file.active_decl.?; | ||
| 722 | try decl.link.macho.relocs.append(emit.bin_file.allocator, .{ | ||
| 723 | .offset = @intCast(u32, end_offset - 4), | ||
| 724 | .target = .{ .local = got_entry }, | ||
| 725 | .addend = 0, | ||
| 726 | .subtractor = null, | ||
| 727 | .pcrel = true, | ||
| 728 | .length = 2, | ||
| 729 | .@"type" = @enumToInt(std.macho.reloc_type_x86_64.X86_64_RELOC_GOT), | ||
| 730 | }); | ||
| 731 | } else { | ||
| 732 | return emit.fail( | ||
| 733 | "TODO implement lea reg, [rip + reloc] for linking backends different than MachO", | ||
| 734 | .{}, | ||
| 735 | ); | ||
| 736 | } | ||
| 737 | }, | ||
| 738 | 0b11 => { | ||
| 739 | // lea reg, [rbp + rcx + imm32] | 710 | // lea reg, [rbp + rcx + imm32] |
| 740 | const imm = emit.mir.instructions.items(.data)[inst].imm; | 711 | const imm = emit.mir.instructions.items(.data)[inst].imm; |
| 741 | const src_reg: ?Register = if (ops.reg2 == .none) null else ops.reg2; | 712 | const src_reg: ?Register = if (ops.reg2 == .none) null else ops.reg2; |
| ... | @@ -754,6 +725,46 @@ fn mirLea(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { | ... | @@ -754,6 +725,46 @@ fn mirLea(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { |
| 754 | emit.code, | 725 | emit.code, |
| 755 | ); | 726 | ); |
| 756 | }, | 727 | }, |
| 728 | 0b11 => return emit.fail("TODO unused LEA variant 0b11", .{}), | ||
| 729 | } | ||
| 730 | } | ||
| 731 | |||
| 732 | fn mirLeaPie(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { | ||
| 733 | const tag = emit.mir.instructions.items(.tag)[inst]; | ||
| 734 | assert(tag == .lea_pie); | ||
| 735 | const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]); | ||
| 736 | |||
| 737 | // lea reg1, [rip + reloc] | ||
| 738 | // RM | ||
| 739 | try lowerToRmEnc( | ||
| 740 | .lea, | ||
| 741 | ops.reg1, | ||
| 742 | RegisterOrMemory.rip(Memory.PtrSize.fromBits(ops.reg1.size()), 0), | ||
| 743 | emit.code, | ||
| 744 | ); | ||
| 745 | const end_offset = emit.code.items.len; | ||
| 746 | const reloc_type = switch (ops.flags) { | ||
| 747 | 0b00 => @enumToInt(std.macho.reloc_type_x86_64.X86_64_RELOC_GOT), | ||
| 748 | 0b01 => @enumToInt(std.macho.reloc_type_x86_64.X86_64_RELOC_SIGNED), | ||
| 749 | else => return emit.fail("TODO unused LEA PIE variants 0b10 and 0b11", .{}), | ||
| 750 | }; | ||
| 751 | const sym_index = emit.mir.instructions.items(.data)[inst].linker_sym_index; | ||
| 752 | if (emit.bin_file.cast(link.File.MachO)) |macho_file| { | ||
| 753 | const decl = macho_file.active_decl.?; | ||
| 754 | try decl.link.macho.relocs.append(emit.bin_file.allocator, .{ | ||
| 755 | .offset = @intCast(u32, end_offset - 4), | ||
| 756 | .target = .{ .local = sym_index }, | ||
| 757 | .addend = 0, | ||
| 758 | .subtractor = null, | ||
| 759 | .pcrel = true, | ||
| 760 | .length = 2, | ||
| 761 | .@"type" = reloc_type, | ||
| 762 | }); | ||
| 763 | } else { | ||
| 764 | return emit.fail( | ||
| 765 | "TODO implement lea reg, [rip + reloc] for linking backends different than MachO", | ||
| 766 | .{}, | ||
| 767 | ); | ||
| 757 | } | 768 | } |
| 758 | } | 769 | } |
| 759 | 770 |
src/arch/x86_64/Mir.zig+10-7| ... | @@ -202,13 +202,16 @@ pub const Inst = struct { | ... | @@ -202,13 +202,16 @@ pub const Inst = struct { |
| 202 | /// 0b00 reg1, [reg2 + imm32] | 202 | /// 0b00 reg1, [reg2 + imm32] |
| 203 | /// 0b00 reg1, [ds:imm32] | 203 | /// 0b00 reg1, [ds:imm32] |
| 204 | /// 0b01 reg1, [rip + imm32] | 204 | /// 0b01 reg1, [rip + imm32] |
| 205 | /// 0b10 reg1, [rip + reloc] | 205 | /// 0b10 reg1, [reg2 + rcx + imm32] |
| 206 | /// 0b11 reg1, [reg2 + rcx + imm32] | ||
| 207 | /// Notes: | ||
| 208 | /// * if flags are 0b10, `Data` contains `got_entry` for the linker to generate | ||
| 209 | /// a valid relocation for. | ||
| 210 | lea, | 206 | lea, |
| 211 | 207 | ||
| 208 | /// ops flags: form: | ||
| 209 | /// 0b00 reg1, [rip + reloc] // via GOT emits X86_64_RELOC_GOT relocation | ||
| 210 | /// 0b01 reg1, [rip + reloc] // direct load emits X86_64_RELOC_SIGNED relocation | ||
| 211 | /// Notes: | ||
| 212 | /// * `Data` contains `linker_sym_index` | ||
| 213 | lea_pie, | ||
| 214 | |||
| 212 | /// ops flags: form: | 215 | /// ops flags: form: |
| 213 | /// 0bX0 reg1 | 216 | /// 0bX0 reg1 |
| 214 | /// 0bX1 [reg1 + imm32] | 217 | /// 0bX1 [reg1 + imm32] |
| ... | @@ -342,8 +345,8 @@ pub const Inst = struct { | ... | @@ -342,8 +345,8 @@ pub const Inst = struct { |
| 342 | /// An extern function. | 345 | /// An extern function. |
| 343 | /// Index into the linker's string table. | 346 | /// Index into the linker's string table. |
| 344 | extern_fn: u32, | 347 | extern_fn: u32, |
| 345 | /// Entry in the GOT table by index. | 348 | /// Entry in the linker's symbol table. |
| 346 | got_entry: u32, | 349 | linker_sym_index: u32, |
| 347 | /// Index into `extra`. Meaning of what can be found there is context-dependent. | 350 | /// Index into `extra`. Meaning of what can be found there is context-dependent. |
| 348 | payload: u32, | 351 | payload: u32, |
| 349 | }; | 352 | }; |
src/arch/x86_64/PrintMir.zig+27-11| ... | @@ -119,6 +119,7 @@ pub fn printMir(print: *const Print, w: anytype, mir_to_air_map: std.AutoHashMap | ... | @@ -119,6 +119,7 @@ pub fn printMir(print: *const Print, w: anytype, mir_to_air_map: std.AutoHashMap |
| 119 | .movabs => try print.mirMovabs(inst, w), | 119 | .movabs => try print.mirMovabs(inst, w), |
| 120 | 120 | ||
| 121 | .lea => try print.mirLea(inst, w), | 121 | .lea => try print.mirLea(inst, w), |
| 122 | .lea_pie => try print.mirLeaPie(inst, w), | ||
| 122 | 123 | ||
| 123 | .imul_complex => try print.mirIMulComplex(inst, w), | 124 | .imul_complex => try print.mirIMulComplex(inst, w), |
| 124 | 125 | ||
| ... | @@ -412,7 +413,7 @@ fn mirLea(print: *const Print, inst: Mir.Inst.Index, w: anytype) !void { | ... | @@ -412,7 +413,7 @@ fn mirLea(print: *const Print, inst: Mir.Inst.Index, w: anytype) !void { |
| 412 | } else { | 413 | } else { |
| 413 | try w.print("ds:", .{}); | 414 | try w.print("ds:", .{}); |
| 414 | } | 415 | } |
| 415 | try w.print("{d}]\n", .{imm}); | 416 | try w.print("{d}]", .{imm}); |
| 416 | }, | 417 | }, |
| 417 | 0b01 => { | 418 | 0b01 => { |
| 418 | try w.print("{s}, ", .{@tagName(ops.reg1)}); | 419 | try w.print("{s}, ", .{@tagName(ops.reg1)}); |
| ... | @@ -429,6 +430,7 @@ fn mirLea(print: *const Print, inst: Mir.Inst.Index, w: anytype) !void { | ... | @@ -429,6 +430,7 @@ fn mirLea(print: *const Print, inst: Mir.Inst.Index, w: anytype) !void { |
| 429 | try w.print("target@{x}", .{imm}); | 430 | try w.print("target@{x}", .{imm}); |
| 430 | }, | 431 | }, |
| 431 | 0b10 => { | 432 | 0b10 => { |
| 433 | const imm = print.mir.instructions.items(.data)[inst].imm; | ||
| 432 | try w.print("{s}, ", .{@tagName(ops.reg1)}); | 434 | try w.print("{s}, ", .{@tagName(ops.reg1)}); |
| 433 | switch (ops.reg1.size()) { | 435 | switch (ops.reg1.size()) { |
| 434 | 8 => try w.print("byte ptr ", .{}), | 436 | 8 => try w.print("byte ptr ", .{}), |
| ... | @@ -437,23 +439,37 @@ fn mirLea(print: *const Print, inst: Mir.Inst.Index, w: anytype) !void { | ... | @@ -437,23 +439,37 @@ fn mirLea(print: *const Print, inst: Mir.Inst.Index, w: anytype) !void { |
| 437 | 64 => try w.print("qword ptr ", .{}), | 439 | 64 => try w.print("qword ptr ", .{}), |
| 438 | else => unreachable, | 440 | else => unreachable, |
| 439 | } | 441 | } |
| 440 | try w.print("[rip + 0x0] ", .{}); | 442 | try w.print("[rbp + rcx + {d}]", .{imm}); |
| 441 | const got_entry = print.mir.instructions.items(.data)[inst].got_entry; | ||
| 442 | if (print.bin_file.cast(link.File.MachO)) |macho_file| { | ||
| 443 | const target = macho_file.locals.items[got_entry]; | ||
| 444 | const target_name = macho_file.getString(target.n_strx); | ||
| 445 | try w.print("target@{s}", .{target_name}); | ||
| 446 | } else { | ||
| 447 | try w.writeAll("TODO lea reg, [rip + reloc] for linking backends different than MachO"); | ||
| 448 | } | ||
| 449 | }, | 443 | }, |
| 450 | 0b11 => { | 444 | 0b11 => { |
| 451 | try w.writeAll("unused variant\n"); | 445 | try w.writeAll("unused variant"); |
| 452 | }, | 446 | }, |
| 453 | } | 447 | } |
| 454 | try w.writeAll("\n"); | 448 | try w.writeAll("\n"); |
| 455 | } | 449 | } |
| 456 | 450 | ||
| 451 | fn mirLeaPie(print: *const Print, inst: Mir.Inst.Index, w: anytype) !void { | ||
| 452 | const ops = Mir.Ops.decode(print.mir.instructions.items(.ops)[inst]); | ||
| 453 | try w.print("lea {s}, ", .{@tagName(ops.reg1)}); | ||
| 454 | switch (ops.reg1.size()) { | ||
| 455 | 8 => try w.print("byte ptr ", .{}), | ||
| 456 | 16 => try w.print("word ptr ", .{}), | ||
| 457 | 32 => try w.print("dword ptr ", .{}), | ||
| 458 | 64 => try w.print("qword ptr ", .{}), | ||
| 459 | else => unreachable, | ||
| 460 | } | ||
| 461 | try w.print("[rip + 0x0] ", .{}); | ||
| 462 | const sym_index = print.mir.instructions.items(.data)[inst].linker_sym_index; | ||
| 463 | if (print.bin_file.cast(link.File.MachO)) |macho_file| { | ||
| 464 | const target = macho_file.locals.items[sym_index]; | ||
| 465 | const target_name = macho_file.getString(target.n_strx); | ||
| 466 | try w.print("target@{s}", .{target_name}); | ||
| 467 | } else { | ||
| 468 | try w.print("TODO lea PIE for other backends", .{}); | ||
| 469 | } | ||
| 470 | return w.writeByte('\n'); | ||
| 471 | } | ||
| 472 | |||
| 457 | fn mirCallExtern(print: *const Print, inst: Mir.Inst.Index, w: anytype) !void { | 473 | fn mirCallExtern(print: *const Print, inst: Mir.Inst.Index, w: anytype) !void { |
| 458 | _ = print; | 474 | _ = print; |
| 459 | _ = inst; | 475 | _ = inst; |
src/link.zig+20| ... | @@ -17,6 +17,7 @@ const LibCInstallation = @import("libc_installation.zig").LibCInstallation; | ... | @@ -17,6 +17,7 @@ const LibCInstallation = @import("libc_installation.zig").LibCInstallation; |
| 17 | const wasi_libc = @import("wasi_libc.zig"); | 17 | const wasi_libc = @import("wasi_libc.zig"); |
| 18 | const Air = @import("Air.zig"); | 18 | const Air = @import("Air.zig"); |
| 19 | const Liveness = @import("Liveness.zig"); | 19 | const Liveness = @import("Liveness.zig"); |
| 20 | const TypedValue = @import("TypedValue.zig"); | ||
| 20 | 21 | ||
| 21 | pub const SystemLib = struct { | 22 | pub const SystemLib = struct { |
| 22 | needed: bool = false, | 23 | needed: bool = false, |
| ... | @@ -429,6 +430,25 @@ pub const File = struct { | ... | @@ -429,6 +430,25 @@ pub const File = struct { |
| 429 | CurrentWorkingDirectoryUnlinked, | 430 | CurrentWorkingDirectoryUnlinked, |
| 430 | }; | 431 | }; |
| 431 | 432 | ||
| 433 | /// Called from within the CodeGen to lower a local variable instantion as an unnamed | ||
| 434 | /// constant. Returns the symbol index of the lowered constant in the read-only section | ||
| 435 | /// of the final binary. | ||
| 436 | pub fn lowerUnnamedConst(base: *File, tv: TypedValue, decl: *Module.Decl) UpdateDeclError!u32 { | ||
| 437 | log.debug("lowerUnnamedConst {*} ({s})", .{ decl, decl.name }); | ||
| 438 | switch (base.tag) { | ||
| 439 | // zig fmt: off | ||
| 440 | .coff => return @fieldParentPtr(Coff, "base", base).lowerUnnamedConst(tv, decl), | ||
| 441 | .elf => return @fieldParentPtr(Elf, "base", base).lowerUnnamedConst(tv, decl), | ||
| 442 | .macho => return @fieldParentPtr(MachO, "base", base).lowerUnnamedConst(tv, decl), | ||
| 443 | .plan9 => return @fieldParentPtr(Plan9, "base", base).lowerUnnamedConst(tv, decl), | ||
| 444 | .spirv => unreachable, | ||
| 445 | .c => unreachable, | ||
| 446 | .wasm => unreachable, | ||
| 447 | .nvptx => unreachable, | ||
| 448 | // zig fmt: on | ||
| 449 | } | ||
| 450 | } | ||
| 451 | |||
| 432 | /// May be called before or after updateDeclExports but must be called | 452 | /// May be called before or after updateDeclExports but must be called |
| 433 | /// after allocateDeclIndexes for any given Decl. | 453 | /// after allocateDeclIndexes for any given Decl. |
| 434 | pub fn updateDecl(base: *File, module: *Module, decl: *Module.Decl) UpdateDeclError!void { | 454 | pub fn updateDecl(base: *File, module: *Module, decl: *Module.Decl) UpdateDeclError!void { |
src/link/Coff.zig+9| ... | @@ -21,6 +21,7 @@ const mingw = @import("../mingw.zig"); | ... | @@ -21,6 +21,7 @@ const mingw = @import("../mingw.zig"); |
| 21 | const Air = @import("../Air.zig"); | 21 | const Air = @import("../Air.zig"); |
| 22 | const Liveness = @import("../Liveness.zig"); | 22 | const Liveness = @import("../Liveness.zig"); |
| 23 | const LlvmObject = @import("../codegen/llvm.zig").Object; | 23 | const LlvmObject = @import("../codegen/llvm.zig").Object; |
| 24 | const TypedValue = @import("../TypedValue.zig"); | ||
| 24 | 25 | ||
| 25 | const allocation_padding = 4 / 3; | 26 | const allocation_padding = 4 / 3; |
| 26 | const minimum_text_block_size = 64 * allocation_padding; | 27 | const minimum_text_block_size = 64 * allocation_padding; |
| ... | @@ -697,6 +698,14 @@ pub fn updateFunc(self: *Coff, module: *Module, func: *Module.Fn, air: Air, live | ... | @@ -697,6 +698,14 @@ pub fn updateFunc(self: *Coff, module: *Module, func: *Module.Fn, air: Air, live |
| 697 | return self.finishUpdateDecl(module, func.owner_decl, code); | 698 | return self.finishUpdateDecl(module, func.owner_decl, code); |
| 698 | } | 699 | } |
| 699 | 700 | ||
| 701 | pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl: *Module.Decl) !u32 { | ||
| 702 | _ = self; | ||
| 703 | _ = tv; | ||
| 704 | _ = decl; | ||
| 705 | log.debug("TODO lowerUnnamedConst for Coff", .{}); | ||
| 706 | return error.AnalysisFail; | ||
| 707 | } | ||
| 708 | |||
| 700 | pub fn updateDecl(self: *Coff, module: *Module, decl: *Module.Decl) !void { | 709 | pub fn updateDecl(self: *Coff, module: *Module, decl: *Module.Decl) !void { |
| 701 | if (build_options.skip_non_native and builtin.object_format != .coff) { | 710 | if (build_options.skip_non_native and builtin.object_format != .coff) { |
| 702 | @panic("Attempted to compile for object format that was disabled by build configuration"); | 711 | @panic("Attempted to compile for object format that was disabled by build configuration"); |
src/link/Elf.zig+169-20| ... | @@ -19,6 +19,7 @@ const trace = @import("../tracy.zig").trace; | ... | @@ -19,6 +19,7 @@ const trace = @import("../tracy.zig").trace; |
| 19 | const Package = @import("../Package.zig"); | 19 | const Package = @import("../Package.zig"); |
| 20 | const Value = @import("../value.zig").Value; | 20 | const Value = @import("../value.zig").Value; |
| 21 | const Type = @import("../type.zig").Type; | 21 | const Type = @import("../type.zig").Type; |
| 22 | const TypedValue = @import("../TypedValue.zig"); | ||
| 22 | const link = @import("../link.zig"); | 23 | const link = @import("../link.zig"); |
| 23 | const File = link.File; | 24 | const File = link.File; |
| 24 | const build_options = @import("build_options"); | 25 | const build_options = @import("build_options"); |
| ... | @@ -110,6 +111,9 @@ debug_line_header_dirty: bool = false, | ... | @@ -110,6 +111,9 @@ debug_line_header_dirty: bool = false, |
| 110 | 111 | ||
| 111 | error_flags: File.ErrorFlags = File.ErrorFlags{}, | 112 | error_flags: File.ErrorFlags = File.ErrorFlags{}, |
| 112 | 113 | ||
| 114 | /// Pointer to the last allocated atom | ||
| 115 | atoms: std.AutoHashMapUnmanaged(u16, *TextBlock) = .{}, | ||
| 116 | |||
| 113 | /// A list of text blocks that have surplus capacity. This list can have false | 117 | /// A list of text blocks that have surplus capacity. This list can have false |
| 114 | /// positives, as functions grow and shrink over time, only sometimes being added | 118 | /// positives, as functions grow and shrink over time, only sometimes being added |
| 115 | /// or removed from the freelist. | 119 | /// or removed from the freelist. |
| ... | @@ -125,10 +129,42 @@ error_flags: File.ErrorFlags = File.ErrorFlags{}, | ... | @@ -125,10 +129,42 @@ error_flags: File.ErrorFlags = File.ErrorFlags{}, |
| 125 | /// overcapacity can be negative. A simple way to have negative overcapacity is to | 129 | /// overcapacity can be negative. A simple way to have negative overcapacity is to |
| 126 | /// allocate a fresh text block, which will have ideal capacity, and then grow it | 130 | /// allocate a fresh text block, which will have ideal capacity, and then grow it |
| 127 | /// by 1 byte. It will then have -1 overcapacity. | 131 | /// by 1 byte. It will then have -1 overcapacity. |
| 128 | atoms: std.AutoHashMapUnmanaged(u16, *TextBlock) = .{}, | ||
| 129 | atom_free_lists: std.AutoHashMapUnmanaged(u16, std.ArrayListUnmanaged(*TextBlock)) = .{}, | 132 | atom_free_lists: std.AutoHashMapUnmanaged(u16, std.ArrayListUnmanaged(*TextBlock)) = .{}, |
| 133 | |||
| 134 | /// Table of Decls that are currently alive. | ||
| 135 | /// We store them here so that we can properly dispose of any allocated | ||
| 136 | /// memory within the atom in the incremental linker. | ||
| 137 | /// TODO consolidate this. | ||
| 130 | decls: std.AutoHashMapUnmanaged(*Module.Decl, ?u16) = .{}, | 138 | decls: std.AutoHashMapUnmanaged(*Module.Decl, ?u16) = .{}, |
| 131 | 139 | ||
| 140 | /// List of atoms that are owned directly by the linker. | ||
| 141 | /// Currently these are only atoms that are the result of linking | ||
| 142 | /// object files. Atoms which take part in incremental linking are | ||
| 143 | /// at present owned by Module.Decl. | ||
| 144 | /// TODO consolidate this. | ||
| 145 | managed_atoms: std.ArrayListUnmanaged(*TextBlock) = .{}, | ||
| 146 | |||
| 147 | /// Table of unnamed constants associated with a parent `Decl`. | ||
| 148 | /// We store them here so that we can free the constants whenever the `Decl` | ||
| 149 | /// needs updating or is freed. | ||
| 150 | /// | ||
| 151 | /// For example, | ||
| 152 | /// | ||
| 153 | /// ```zig | ||
| 154 | /// const Foo = struct{ | ||
| 155 | /// a: u8, | ||
| 156 | /// }; | ||
| 157 | /// | ||
| 158 | /// pub fn main() void { | ||
| 159 | /// var foo = Foo{ .a = 1 }; | ||
| 160 | /// _ = foo; | ||
| 161 | /// } | ||
| 162 | /// ``` | ||
| 163 | /// | ||
| 164 | /// value assigned to label `foo` is an unnamed constant belonging/associated | ||
| 165 | /// with `Decl` `main`, and lives as long as that `Decl`. | ||
| 166 | unnamed_const_atoms: UnnamedConstTable = .{}, | ||
| 167 | |||
| 132 | /// A list of `SrcFn` whose Line Number Programs have surplus capacity. | 168 | /// A list of `SrcFn` whose Line Number Programs have surplus capacity. |
| 133 | /// This is the same concept as `text_block_free_list`; see those doc comments. | 169 | /// This is the same concept as `text_block_free_list`; see those doc comments. |
| 134 | dbg_line_fn_free_list: std.AutoHashMapUnmanaged(*SrcFn, void) = .{}, | 170 | dbg_line_fn_free_list: std.AutoHashMapUnmanaged(*SrcFn, void) = .{}, |
| ... | @@ -141,6 +177,8 @@ dbg_info_decl_free_list: std.AutoHashMapUnmanaged(*TextBlock, void) = .{}, | ... | @@ -141,6 +177,8 @@ dbg_info_decl_free_list: std.AutoHashMapUnmanaged(*TextBlock, void) = .{}, |
| 141 | dbg_info_decl_first: ?*TextBlock = null, | 177 | dbg_info_decl_first: ?*TextBlock = null, |
| 142 | dbg_info_decl_last: ?*TextBlock = null, | 178 | dbg_info_decl_last: ?*TextBlock = null, |
| 143 | 179 | ||
| 180 | const UnnamedConstTable = std.AutoHashMapUnmanaged(*Module.Decl, std.ArrayListUnmanaged(*TextBlock)); | ||
| 181 | |||
| 144 | /// When allocating, the ideal_capacity is calculated by | 182 | /// When allocating, the ideal_capacity is calculated by |
| 145 | /// actual_capacity + (actual_capacity / ideal_factor) | 183 | /// actual_capacity + (actual_capacity / ideal_factor) |
| 146 | const ideal_factor = 3; | 184 | const ideal_factor = 3; |
| ... | @@ -342,6 +380,19 @@ pub fn deinit(self: *Elf) void { | ... | @@ -342,6 +380,19 @@ pub fn deinit(self: *Elf) void { |
| 342 | } | 380 | } |
| 343 | self.atom_free_lists.deinit(self.base.allocator); | 381 | self.atom_free_lists.deinit(self.base.allocator); |
| 344 | } | 382 | } |
| 383 | |||
| 384 | for (self.managed_atoms.items) |atom| { | ||
| 385 | self.base.allocator.destroy(atom); | ||
| 386 | } | ||
| 387 | self.managed_atoms.deinit(self.base.allocator); | ||
| 388 | |||
| 389 | { | ||
| 390 | var it = self.unnamed_const_atoms.valueIterator(); | ||
| 391 | while (it.next()) |atoms| { | ||
| 392 | atoms.deinit(self.base.allocator); | ||
| 393 | } | ||
| 394 | self.unnamed_const_atoms.deinit(self.base.allocator); | ||
| 395 | } | ||
| 345 | } | 396 | } |
| 346 | 397 | ||
| 347 | pub fn getDeclVAddr(self: *Elf, decl: *const Module.Decl) u64 { | 398 | pub fn getDeclVAddr(self: *Elf, decl: *const Module.Decl) u64 { |
| ... | @@ -2166,6 +2217,11 @@ fn writeElfHeader(self: *Elf) !void { | ... | @@ -2166,6 +2217,11 @@ fn writeElfHeader(self: *Elf) !void { |
| 2166 | } | 2217 | } |
| 2167 | 2218 | ||
| 2168 | fn freeTextBlock(self: *Elf, text_block: *TextBlock, phdr_index: u16) void { | 2219 | fn freeTextBlock(self: *Elf, text_block: *TextBlock, phdr_index: u16) void { |
| 2220 | const local_sym = self.local_symbols.items[text_block.local_sym_index]; | ||
| 2221 | const name_str_index = local_sym.st_name; | ||
| 2222 | const name = self.getString(name_str_index); | ||
| 2223 | log.debug("freeTextBlock {*} ({s})", .{ text_block, name }); | ||
| 2224 | |||
| 2169 | const free_list = self.atom_free_lists.getPtr(phdr_index).?; | 2225 | const free_list = self.atom_free_lists.getPtr(phdr_index).?; |
| 2170 | var already_have_free_list_node = false; | 2226 | var already_have_free_list_node = false; |
| 2171 | { | 2227 | { |
| ... | @@ -2376,23 +2432,43 @@ fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, al | ... | @@ -2376,23 +2432,43 @@ fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, al |
| 2376 | return vaddr; | 2432 | return vaddr; |
| 2377 | } | 2433 | } |
| 2378 | 2434 | ||
| 2435 | fn allocateLocalSymbol(self: *Elf) !u32 { | ||
| 2436 | try self.local_symbols.ensureUnusedCapacity(self.base.allocator, 1); | ||
| 2437 | |||
| 2438 | const index = blk: { | ||
| 2439 | if (self.local_symbol_free_list.popOrNull()) |index| { | ||
| 2440 | log.debug(" (reusing symbol index {d})", .{index}); | ||
| 2441 | break :blk index; | ||
| 2442 | } else { | ||
| 2443 | log.debug(" (allocating symbol index {d})", .{self.local_symbols.items.len}); | ||
| 2444 | const index = @intCast(u32, self.local_symbols.items.len); | ||
| 2445 | _ = self.local_symbols.addOneAssumeCapacity(); | ||
| 2446 | break :blk index; | ||
| 2447 | } | ||
| 2448 | }; | ||
| 2449 | |||
| 2450 | self.local_symbols.items[index] = .{ | ||
| 2451 | .st_name = 0, | ||
| 2452 | .st_info = 0, | ||
| 2453 | .st_other = 0, | ||
| 2454 | .st_shndx = 0, | ||
| 2455 | .st_value = 0, | ||
| 2456 | .st_size = 0, | ||
| 2457 | }; | ||
| 2458 | |||
| 2459 | return index; | ||
| 2460 | } | ||
| 2461 | |||
| 2379 | pub fn allocateDeclIndexes(self: *Elf, decl: *Module.Decl) !void { | 2462 | pub fn allocateDeclIndexes(self: *Elf, decl: *Module.Decl) !void { |
| 2380 | if (self.llvm_object) |_| return; | 2463 | if (self.llvm_object) |_| return; |
| 2381 | 2464 | ||
| 2382 | if (decl.link.elf.local_sym_index != 0) return; | 2465 | if (decl.link.elf.local_sym_index != 0) return; |
| 2383 | 2466 | ||
| 2384 | try self.local_symbols.ensureUnusedCapacity(self.base.allocator, 1); | ||
| 2385 | try self.offset_table.ensureUnusedCapacity(self.base.allocator, 1); | 2467 | try self.offset_table.ensureUnusedCapacity(self.base.allocator, 1); |
| 2386 | try self.decls.putNoClobber(self.base.allocator, decl, null); | 2468 | try self.decls.putNoClobber(self.base.allocator, decl, null); |
| 2387 | 2469 | ||
| 2388 | if (self.local_symbol_free_list.popOrNull()) |i| { | 2470 | log.debug("allocating symbol indexes for {s}", .{decl.name}); |
| 2389 | log.debug("reusing symbol index {d} for {s}", .{ i, decl.name }); | 2471 | decl.link.elf.local_sym_index = try self.allocateLocalSymbol(); |
| 2390 | decl.link.elf.local_sym_index = i; | ||
| 2391 | } else { | ||
| 2392 | log.debug("allocating symbol index {d} for {s}", .{ self.local_symbols.items.len, decl.name }); | ||
| 2393 | decl.link.elf.local_sym_index = @intCast(u32, self.local_symbols.items.len); | ||
| 2394 | _ = self.local_symbols.addOneAssumeCapacity(); | ||
| 2395 | } | ||
| 2396 | 2472 | ||
| 2397 | if (self.offset_table_free_list.popOrNull()) |i| { | 2473 | if (self.offset_table_free_list.popOrNull()) |i| { |
| 2398 | decl.link.elf.offset_table_index = i; | 2474 | decl.link.elf.offset_table_index = i; |
| ... | @@ -2401,18 +2477,19 @@ pub fn allocateDeclIndexes(self: *Elf, decl: *Module.Decl) !void { | ... | @@ -2401,18 +2477,19 @@ pub fn allocateDeclIndexes(self: *Elf, decl: *Module.Decl) !void { |
| 2401 | _ = self.offset_table.addOneAssumeCapacity(); | 2477 | _ = self.offset_table.addOneAssumeCapacity(); |
| 2402 | self.offset_table_count_dirty = true; | 2478 | self.offset_table_count_dirty = true; |
| 2403 | } | 2479 | } |
| 2404 | |||
| 2405 | self.local_symbols.items[decl.link.elf.local_sym_index] = .{ | ||
| 2406 | .st_name = 0, | ||
| 2407 | .st_info = 0, | ||
| 2408 | .st_other = 0, | ||
| 2409 | .st_shndx = 0, | ||
| 2410 | .st_value = 0, | ||
| 2411 | .st_size = 0, | ||
| 2412 | }; | ||
| 2413 | self.offset_table.items[decl.link.elf.offset_table_index] = 0; | 2480 | self.offset_table.items[decl.link.elf.offset_table_index] = 0; |
| 2414 | } | 2481 | } |
| 2415 | 2482 | ||
| 2483 | fn freeUnnamedConsts(self: *Elf, decl: *Module.Decl) void { | ||
| 2484 | const unnamed_consts = self.unnamed_const_atoms.getPtr(decl) orelse return; | ||
| 2485 | for (unnamed_consts.items) |atom| { | ||
| 2486 | self.freeTextBlock(atom, self.phdr_load_ro_index.?); | ||
| 2487 | self.local_symbol_free_list.append(self.base.allocator, atom.local_sym_index) catch {}; | ||
| 2488 | self.local_symbols.items[atom.local_sym_index].st_info = 0; | ||
| 2489 | } | ||
| 2490 | unnamed_consts.clearAndFree(self.base.allocator); | ||
| 2491 | } | ||
| 2492 | |||
| 2416 | pub fn freeDecl(self: *Elf, decl: *Module.Decl) void { | 2493 | pub fn freeDecl(self: *Elf, decl: *Module.Decl) void { |
| 2417 | if (build_options.have_llvm) { | 2494 | if (build_options.have_llvm) { |
| 2418 | if (self.llvm_object) |llvm_object| return llvm_object.freeDecl(decl); | 2495 | if (self.llvm_object) |llvm_object| return llvm_object.freeDecl(decl); |
| ... | @@ -2421,6 +2498,7 @@ pub fn freeDecl(self: *Elf, decl: *Module.Decl) void { | ... | @@ -2421,6 +2498,7 @@ pub fn freeDecl(self: *Elf, decl: *Module.Decl) void { |
| 2421 | const kv = self.decls.fetchRemove(decl); | 2498 | const kv = self.decls.fetchRemove(decl); |
| 2422 | if (kv.?.value) |index| { | 2499 | if (kv.?.value) |index| { |
| 2423 | self.freeTextBlock(&decl.link.elf, index); | 2500 | self.freeTextBlock(&decl.link.elf, index); |
| 2501 | self.freeUnnamedConsts(decl); | ||
| 2424 | } | 2502 | } |
| 2425 | 2503 | ||
| 2426 | // Appending to free lists is allowed to fail because the free lists are heuristics based anyway. | 2504 | // Appending to free lists is allowed to fail because the free lists are heuristics based anyway. |
| ... | @@ -2528,7 +2606,6 @@ fn updateDeclCode(self: *Elf, decl: *Module.Decl, code: []const u8, stt_bits: u8 | ... | @@ -2528,7 +2606,6 @@ fn updateDeclCode(self: *Elf, decl: *Module.Decl, code: []const u8, stt_bits: u8 |
| 2528 | const vaddr = try self.allocateTextBlock(&decl.link.elf, code.len, required_alignment, phdr_index); | 2606 | const vaddr = try self.allocateTextBlock(&decl.link.elf, code.len, required_alignment, phdr_index); |
| 2529 | errdefer self.freeTextBlock(&decl.link.elf, phdr_index); | 2607 | errdefer self.freeTextBlock(&decl.link.elf, phdr_index); |
| 2530 | log.debug("allocated text block for {s} at 0x{x}", .{ decl_name, vaddr }); | 2608 | log.debug("allocated text block for {s} at 0x{x}", .{ decl_name, vaddr }); |
| 2531 | errdefer self.freeTextBlock(&decl.link.elf, phdr_index); | ||
| 2532 | 2609 | ||
| 2533 | local_sym.* = .{ | 2610 | local_sym.* = .{ |
| 2534 | .st_name = name_str_index, | 2611 | .st_name = name_str_index, |
| ... | @@ -2632,6 +2709,8 @@ pub fn updateFunc(self: *Elf, module: *Module, func: *Module.Fn, air: Air, liven | ... | @@ -2632,6 +2709,8 @@ pub fn updateFunc(self: *Elf, module: *Module, func: *Module.Fn, air: Air, liven |
| 2632 | defer deinitRelocs(self.base.allocator, &dbg_info_type_relocs); | 2709 | defer deinitRelocs(self.base.allocator, &dbg_info_type_relocs); |
| 2633 | 2710 | ||
| 2634 | const decl = func.owner_decl; | 2711 | const decl = func.owner_decl; |
| 2712 | self.freeUnnamedConsts(decl); | ||
| 2713 | |||
| 2635 | log.debug("updateFunc {s}{*}", .{ decl.name, func.owner_decl }); | 2714 | log.debug("updateFunc {s}{*}", .{ decl.name, func.owner_decl }); |
| 2636 | log.debug(" (decl.src_line={d}, func.lbrace_line={d}, func.rbrace_line={d})", .{ | 2715 | log.debug(" (decl.src_line={d}, func.lbrace_line={d}, func.rbrace_line={d})", .{ |
| 2637 | decl.src_line, | 2716 | decl.src_line, |
| ... | @@ -2859,6 +2938,8 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void { | ... | @@ -2859,6 +2938,8 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void { |
| 2859 | } | 2938 | } |
| 2860 | } | 2939 | } |
| 2861 | 2940 | ||
| 2941 | assert(!self.unnamed_const_atoms.contains(decl)); | ||
| 2942 | |||
| 2862 | var code_buffer = std.ArrayList(u8).init(self.base.allocator); | 2943 | var code_buffer = std.ArrayList(u8).init(self.base.allocator); |
| 2863 | defer code_buffer.deinit(); | 2944 | defer code_buffer.deinit(); |
| 2864 | 2945 | ||
| ... | @@ -2897,6 +2978,74 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void { | ... | @@ -2897,6 +2978,74 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void { |
| 2897 | return self.finishUpdateDecl(module, decl, &dbg_info_type_relocs, &dbg_info_buffer); | 2978 | return self.finishUpdateDecl(module, decl, &dbg_info_type_relocs, &dbg_info_buffer); |
| 2898 | } | 2979 | } |
| 2899 | 2980 | ||
| 2981 | pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl: *Module.Decl) !u32 { | ||
| 2982 | var code_buffer = std.ArrayList(u8).init(self.base.allocator); | ||
| 2983 | defer code_buffer.deinit(); | ||
| 2984 | |||
| 2985 | const module = self.base.options.module.?; | ||
| 2986 | const gop = try self.unnamed_const_atoms.getOrPut(self.base.allocator, decl); | ||
| 2987 | if (!gop.found_existing) { | ||
| 2988 | gop.value_ptr.* = .{}; | ||
| 2989 | } | ||
| 2990 | const unnamed_consts = gop.value_ptr; | ||
| 2991 | |||
| 2992 | const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), typed_value, &code_buffer, .{ | ||
| 2993 | .none = .{}, | ||
| 2994 | }); | ||
| 2995 | const code = switch (res) { | ||
| 2996 | .externally_managed => |x| x, | ||
| 2997 | .appended => code_buffer.items, | ||
| 2998 | .fail => |em| { | ||
| 2999 | decl.analysis = .codegen_failure; | ||
| 3000 | try module.failed_decls.put(module.gpa, decl, em); | ||
| 3001 | return error.AnalysisFail; | ||
| 3002 | }, | ||
| 3003 | }; | ||
| 3004 | |||
| 3005 | const atom = try self.base.allocator.create(TextBlock); | ||
| 3006 | errdefer self.base.allocator.destroy(atom); | ||
| 3007 | atom.* = TextBlock.empty; | ||
| 3008 | try self.managed_atoms.append(self.base.allocator, atom); | ||
| 3009 | |||
| 3010 | const name_str_index = blk: { | ||
| 3011 | const index = unnamed_consts.items.len; | ||
| 3012 | const name = try std.fmt.allocPrint(self.base.allocator, "__unnamed_{s}_{d}", .{ decl.name, index }); | ||
| 3013 | defer self.base.allocator.free(name); | ||
| 3014 | break :blk try self.makeString(name); | ||
| 3015 | }; | ||
| 3016 | const name = self.getString(name_str_index); | ||
| 3017 | |||
| 3018 | log.debug("allocating symbol indexes for {s}", .{name}); | ||
| 3019 | atom.local_sym_index = try self.allocateLocalSymbol(); | ||
| 3020 | |||
| 3021 | const required_alignment = typed_value.ty.abiAlignment(self.base.options.target); | ||
| 3022 | const phdr_index = self.phdr_load_ro_index.?; | ||
| 3023 | const shdr_index = self.phdr_shdr_table.get(phdr_index).?; | ||
| 3024 | const vaddr = try self.allocateTextBlock(atom, code.len, required_alignment, phdr_index); | ||
| 3025 | errdefer self.freeTextBlock(atom, phdr_index); | ||
| 3026 | |||
| 3027 | log.debug("allocated text block for {s} at 0x{x}", .{ name, vaddr }); | ||
| 3028 | |||
| 3029 | const local_sym = &self.local_symbols.items[atom.local_sym_index]; | ||
| 3030 | local_sym.* = .{ | ||
| 3031 | .st_name = name_str_index, | ||
| 3032 | .st_info = (elf.STB_LOCAL << 4) | elf.STT_OBJECT, | ||
| 3033 | .st_other = 0, | ||
| 3034 | .st_shndx = shdr_index, | ||
| 3035 | .st_value = vaddr, | ||
| 3036 | .st_size = code.len, | ||
| 3037 | }; | ||
| 3038 | |||
| 3039 | try self.writeSymbol(atom.local_sym_index); | ||
| 3040 | try unnamed_consts.append(self.base.allocator, atom); | ||
| 3041 | |||
| 3042 | const section_offset = local_sym.st_value - self.program_headers.items[phdr_index].p_vaddr; | ||
| 3043 | const file_offset = self.sections.items[shdr_index].sh_offset + section_offset; | ||
| 3044 | try self.base.file.?.pwriteAll(code, file_offset); | ||
| 3045 | |||
| 3046 | return atom.local_sym_index; | ||
| 3047 | } | ||
| 3048 | |||
| 2900 | /// Asserts the type has codegen bits. | 3049 | /// Asserts the type has codegen bits. |
| 2901 | fn addDbgInfoType( | 3050 | fn addDbgInfoType( |
| 2902 | self: *Elf, | 3051 | self: *Elf, |
src/link/MachO.zig+275-76| ... | @@ -39,6 +39,7 @@ const StringIndexAdapter = std.hash_map.StringIndexAdapter; | ... | @@ -39,6 +39,7 @@ const StringIndexAdapter = std.hash_map.StringIndexAdapter; |
| 39 | const StringIndexContext = std.hash_map.StringIndexContext; | 39 | const StringIndexContext = std.hash_map.StringIndexContext; |
| 40 | const Trie = @import("MachO/Trie.zig"); | 40 | const Trie = @import("MachO/Trie.zig"); |
| 41 | const Type = @import("../type.zig").Type; | 41 | const Type = @import("../type.zig").Type; |
| 42 | const TypedValue = @import("../TypedValue.zig"); | ||
| 42 | 43 | ||
| 43 | pub const TextBlock = Atom; | 44 | pub const TextBlock = Atom; |
| 44 | 45 | ||
| ... | @@ -166,14 +167,17 @@ stub_helper_preamble_atom: ?*Atom = null, | ... | @@ -166,14 +167,17 @@ stub_helper_preamble_atom: ?*Atom = null, |
| 166 | strtab: std.ArrayListUnmanaged(u8) = .{}, | 167 | strtab: std.ArrayListUnmanaged(u8) = .{}, |
| 167 | strtab_dir: std.HashMapUnmanaged(u32, void, StringIndexContext, std.hash_map.default_max_load_percentage) = .{}, | 168 | strtab_dir: std.HashMapUnmanaged(u32, void, StringIndexContext, std.hash_map.default_max_load_percentage) = .{}, |
| 168 | 169 | ||
| 169 | tlv_ptr_entries_map: std.AutoArrayHashMapUnmanaged(Atom.Relocation.Target, *Atom) = .{}, | 170 | tlv_ptr_entries: std.ArrayListUnmanaged(Entry) = .{}, |
| 170 | tlv_ptr_entries_map_free_list: std.ArrayListUnmanaged(u32) = .{}, | 171 | tlv_ptr_entries_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| 172 | tlv_ptr_entries_table: std.AutoArrayHashMapUnmanaged(Atom.Relocation.Target, u32) = .{}, | ||
| 171 | 173 | ||
| 172 | got_entries_map: std.AutoArrayHashMapUnmanaged(Atom.Relocation.Target, *Atom) = .{}, | 174 | got_entries: std.ArrayListUnmanaged(Entry) = .{}, |
| 173 | got_entries_map_free_list: std.ArrayListUnmanaged(u32) = .{}, | 175 | got_entries_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| 176 | got_entries_table: std.AutoArrayHashMapUnmanaged(Atom.Relocation.Target, u32) = .{}, | ||
| 174 | 177 | ||
| 175 | stubs_map: std.AutoArrayHashMapUnmanaged(u32, *Atom) = .{}, | 178 | stubs: std.ArrayListUnmanaged(*Atom) = .{}, |
| 176 | stubs_map_free_list: std.ArrayListUnmanaged(u32) = .{}, | 179 | stubs_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| 180 | stubs_table: std.AutoArrayHashMapUnmanaged(u32, u32) = .{}, | ||
| 177 | 181 | ||
| 178 | error_flags: File.ErrorFlags = File.ErrorFlags{}, | 182 | error_flags: File.ErrorFlags = File.ErrorFlags{}, |
| 179 | 183 | ||
| ... | @@ -217,6 +221,27 @@ atoms: std.AutoHashMapUnmanaged(MatchingSection, *Atom) = .{}, | ... | @@ -217,6 +221,27 @@ atoms: std.AutoHashMapUnmanaged(MatchingSection, *Atom) = .{}, |
| 217 | /// TODO consolidate this. | 221 | /// TODO consolidate this. |
| 218 | managed_atoms: std.ArrayListUnmanaged(*Atom) = .{}, | 222 | managed_atoms: std.ArrayListUnmanaged(*Atom) = .{}, |
| 219 | 223 | ||
| 224 | /// Table of unnamed constants associated with a parent `Decl`. | ||
| 225 | /// We store them here so that we can free the constants whenever the `Decl` | ||
| 226 | /// needs updating or is freed. | ||
| 227 | /// | ||
| 228 | /// For example, | ||
| 229 | /// | ||
| 230 | /// ```zig | ||
| 231 | /// const Foo = struct{ | ||
| 232 | /// a: u8, | ||
| 233 | /// }; | ||
| 234 | /// | ||
| 235 | /// pub fn main() void { | ||
| 236 | /// var foo = Foo{ .a = 1 }; | ||
| 237 | /// _ = foo; | ||
| 238 | /// } | ||
| 239 | /// ``` | ||
| 240 | /// | ||
| 241 | /// value assigned to label `foo` is an unnamed constant belonging/associated | ||
| 242 | /// with `Decl` `main`, and lives as long as that `Decl`. | ||
| 243 | unnamed_const_atoms: UnnamedConstTable = .{}, | ||
| 244 | |||
| 220 | /// Table of Decls that are currently alive. | 245 | /// Table of Decls that are currently alive. |
| 221 | /// We store them here so that we can properly dispose of any allocated | 246 | /// We store them here so that we can properly dispose of any allocated |
| 222 | /// memory within the atom in the incremental linker. | 247 | /// memory within the atom in the incremental linker. |
| ... | @@ -229,6 +254,13 @@ decls: std.AutoArrayHashMapUnmanaged(*Module.Decl, ?MatchingSection) = .{}, | ... | @@ -229,6 +254,13 @@ decls: std.AutoArrayHashMapUnmanaged(*Module.Decl, ?MatchingSection) = .{}, |
| 229 | /// somewhere else in the codegen. | 254 | /// somewhere else in the codegen. |
| 230 | active_decl: ?*Module.Decl = null, | 255 | active_decl: ?*Module.Decl = null, |
| 231 | 256 | ||
| 257 | const Entry = struct { | ||
| 258 | target: Atom.Relocation.Target, | ||
| 259 | atom: *Atom, | ||
| 260 | }; | ||
| 261 | |||
| 262 | const UnnamedConstTable = std.AutoHashMapUnmanaged(*Module.Decl, std.ArrayListUnmanaged(*Atom)); | ||
| 263 | |||
| 232 | const PendingUpdate = union(enum) { | 264 | const PendingUpdate = union(enum) { |
| 233 | resolve_undef: u32, | 265 | resolve_undef: u32, |
| 234 | add_stub_entry: u32, | 266 | add_stub_entry: u32, |
| ... | @@ -661,16 +693,15 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { | ... | @@ -661,16 +693,15 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { |
| 661 | sym.n_desc = 0; | 693 | sym.n_desc = 0; |
| 662 | }, | 694 | }, |
| 663 | } | 695 | } |
| 664 | if (self.got_entries_map.getIndex(.{ .global = entry.key })) |i| { | 696 | if (self.got_entries_table.get(.{ .global = entry.key })) |i| { |
| 665 | self.got_entries_map_free_list.append( | 697 | self.got_entries_free_list.append(self.base.allocator, @intCast(u32, i)) catch {}; |
| 666 | self.base.allocator, | 698 | self.got_entries.items[i] = .{ .target = .{ .local = 0 }, .atom = undefined }; |
| 667 | @intCast(u32, i), | 699 | _ = self.got_entries_table.swapRemove(.{ .global = entry.key }); |
| 668 | ) catch {}; | ||
| 669 | self.got_entries_map.keys()[i] = .{ .local = 0 }; | ||
| 670 | } | 700 | } |
| 671 | if (self.stubs_map.getIndex(entry.key)) |i| { | 701 | if (self.stubs_table.get(entry.key)) |i| { |
| 672 | self.stubs_map_free_list.append(self.base.allocator, @intCast(u32, i)) catch {}; | 702 | self.stubs_free_list.append(self.base.allocator, @intCast(u32, i)) catch {}; |
| 673 | self.stubs_map.keys()[i] = 0; | 703 | self.stubs.items[i] = undefined; |
| 704 | _ = self.stubs_table.swapRemove(entry.key); | ||
| 674 | } | 705 | } |
| 675 | } | 706 | } |
| 676 | } | 707 | } |
| ... | @@ -2948,7 +2979,7 @@ fn resolveSymbolsInDylibs(self: *MachO) !void { | ... | @@ -2948,7 +2979,7 @@ fn resolveSymbolsInDylibs(self: *MachO) !void { |
| 2948 | .none => {}, | 2979 | .none => {}, |
| 2949 | .got => return error.TODOGotHint, | 2980 | .got => return error.TODOGotHint, |
| 2950 | .stub => { | 2981 | .stub => { |
| 2951 | if (self.stubs_map.contains(sym.n_strx)) break :outer_blk; | 2982 | if (self.stubs_table.contains(sym.n_strx)) break :outer_blk; |
| 2952 | const stub_helper_atom = blk: { | 2983 | const stub_helper_atom = blk: { |
| 2953 | const match = MatchingSection{ | 2984 | const match = MatchingSection{ |
| 2954 | .seg = self.text_segment_cmd_index.?, | 2985 | .seg = self.text_segment_cmd_index.?, |
| ... | @@ -2991,7 +3022,9 @@ fn resolveSymbolsInDylibs(self: *MachO) !void { | ... | @@ -2991,7 +3022,9 @@ fn resolveSymbolsInDylibs(self: *MachO) !void { |
| 2991 | atom_sym.n_sect = @intCast(u8, self.section_ordinals.getIndex(match).? + 1); | 3022 | atom_sym.n_sect = @intCast(u8, self.section_ordinals.getIndex(match).? + 1); |
| 2992 | break :blk atom; | 3023 | break :blk atom; |
| 2993 | }; | 3024 | }; |
| 2994 | try self.stubs_map.putNoClobber(self.base.allocator, sym.n_strx, stub_atom); | 3025 | const stub_index = @intCast(u32, self.stubs.items.len); |
| 3026 | try self.stubs.append(self.base.allocator, stub_atom); | ||
| 3027 | try self.stubs_table.putNoClobber(self.base.allocator, sym.n_strx, stub_index); | ||
| 2995 | }, | 3028 | }, |
| 2996 | } | 3029 | } |
| 2997 | } | 3030 | } |
| ... | @@ -3086,7 +3119,9 @@ fn resolveDyldStubBinder(self: *MachO) !void { | ... | @@ -3086,7 +3119,9 @@ fn resolveDyldStubBinder(self: *MachO) !void { |
| 3086 | // Add dyld_stub_binder as the final GOT entry. | 3119 | // Add dyld_stub_binder as the final GOT entry. |
| 3087 | const target = Atom.Relocation.Target{ .global = n_strx }; | 3120 | const target = Atom.Relocation.Target{ .global = n_strx }; |
| 3088 | const atom = try self.createGotAtom(target); | 3121 | const atom = try self.createGotAtom(target); |
| 3089 | try self.got_entries_map.putNoClobber(self.base.allocator, target, atom); | 3122 | const got_index = @intCast(u32, self.got_entries.items.len); |
| 3123 | try self.got_entries.append(self.base.allocator, .{ .target = target, .atom = atom }); | ||
| 3124 | try self.got_entries_table.putNoClobber(self.base.allocator, target, got_index); | ||
| 3090 | const match = MatchingSection{ | 3125 | const match = MatchingSection{ |
| 3091 | .seg = self.data_const_segment_cmd_index.?, | 3126 | .seg = self.data_const_segment_cmd_index.?, |
| 3092 | .sect = self.got_section_index.?, | 3127 | .sect = self.got_section_index.?, |
| ... | @@ -3339,12 +3374,15 @@ pub fn deinit(self: *MachO) void { | ... | @@ -3339,12 +3374,15 @@ pub fn deinit(self: *MachO) void { |
| 3339 | } | 3374 | } |
| 3340 | 3375 | ||
| 3341 | self.section_ordinals.deinit(self.base.allocator); | 3376 | self.section_ordinals.deinit(self.base.allocator); |
| 3342 | self.tlv_ptr_entries_map.deinit(self.base.allocator); | 3377 | self.tlv_ptr_entries.deinit(self.base.allocator); |
| 3343 | self.tlv_ptr_entries_map_free_list.deinit(self.base.allocator); | 3378 | self.tlv_ptr_entries_free_list.deinit(self.base.allocator); |
| 3344 | self.got_entries_map.deinit(self.base.allocator); | 3379 | self.tlv_ptr_entries_table.deinit(self.base.allocator); |
| 3345 | self.got_entries_map_free_list.deinit(self.base.allocator); | 3380 | self.got_entries.deinit(self.base.allocator); |
| 3346 | self.stubs_map.deinit(self.base.allocator); | 3381 | self.got_entries_free_list.deinit(self.base.allocator); |
| 3347 | self.stubs_map_free_list.deinit(self.base.allocator); | 3382 | self.got_entries_table.deinit(self.base.allocator); |
| 3383 | self.stubs.deinit(self.base.allocator); | ||
| 3384 | self.stubs_free_list.deinit(self.base.allocator); | ||
| 3385 | self.stubs_table.deinit(self.base.allocator); | ||
| 3348 | self.strtab_dir.deinit(self.base.allocator); | 3386 | self.strtab_dir.deinit(self.base.allocator); |
| 3349 | self.strtab.deinit(self.base.allocator); | 3387 | self.strtab.deinit(self.base.allocator); |
| 3350 | self.undefs.deinit(self.base.allocator); | 3388 | self.undefs.deinit(self.base.allocator); |
| ... | @@ -3395,6 +3433,14 @@ pub fn deinit(self: *MachO) void { | ... | @@ -3395,6 +3433,14 @@ pub fn deinit(self: *MachO) void { |
| 3395 | decl.link.macho.deinit(self.base.allocator); | 3433 | decl.link.macho.deinit(self.base.allocator); |
| 3396 | } | 3434 | } |
| 3397 | self.decls.deinit(self.base.allocator); | 3435 | self.decls.deinit(self.base.allocator); |
| 3436 | |||
| 3437 | { | ||
| 3438 | var it = self.unnamed_const_atoms.valueIterator(); | ||
| 3439 | while (it.next()) |atoms| { | ||
| 3440 | atoms.deinit(self.base.allocator); | ||
| 3441 | } | ||
| 3442 | self.unnamed_const_atoms.deinit(self.base.allocator); | ||
| 3443 | } | ||
| 3398 | } | 3444 | } |
| 3399 | 3445 | ||
| 3400 | pub fn closeFiles(self: MachO) void { | 3446 | pub fn closeFiles(self: MachO) void { |
| ... | @@ -3409,9 +3455,11 @@ pub fn closeFiles(self: MachO) void { | ... | @@ -3409,9 +3455,11 @@ pub fn closeFiles(self: MachO) void { |
| 3409 | } | 3455 | } |
| 3410 | } | 3456 | } |
| 3411 | 3457 | ||
| 3412 | fn freeAtom(self: *MachO, atom: *Atom, match: MatchingSection) void { | 3458 | fn freeAtom(self: *MachO, atom: *Atom, match: MatchingSection, owns_atom: bool) void { |
| 3413 | log.debug("freeAtom {*}", .{atom}); | 3459 | log.debug("freeAtom {*}", .{atom}); |
| 3414 | atom.deinit(self.base.allocator); | 3460 | if (!owns_atom) { |
| 3461 | atom.deinit(self.base.allocator); | ||
| 3462 | } | ||
| 3415 | 3463 | ||
| 3416 | const free_list = self.atom_free_lists.getPtr(match).?; | 3464 | const free_list = self.atom_free_lists.getPtr(match).?; |
| 3417 | var already_have_free_list_node = false; | 3465 | var already_have_free_list_node = false; |
| ... | @@ -3502,23 +3550,22 @@ fn growAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64, match | ... | @@ -3502,23 +3550,22 @@ fn growAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64, match |
| 3502 | return self.allocateAtom(atom, new_atom_size, alignment, match); | 3550 | return self.allocateAtom(atom, new_atom_size, alignment, match); |
| 3503 | } | 3551 | } |
| 3504 | 3552 | ||
| 3505 | pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void { | 3553 | fn allocateLocalSymbol(self: *MachO) !u32 { |
| 3506 | if (self.llvm_object) |_| return; | ||
| 3507 | if (decl.link.macho.local_sym_index != 0) return; | ||
| 3508 | |||
| 3509 | try self.locals.ensureUnusedCapacity(self.base.allocator, 1); | 3554 | try self.locals.ensureUnusedCapacity(self.base.allocator, 1); |
| 3510 | try self.decls.putNoClobber(self.base.allocator, decl, null); | ||
| 3511 | 3555 | ||
| 3512 | if (self.locals_free_list.popOrNull()) |i| { | 3556 | const index = blk: { |
| 3513 | log.debug("reusing symbol index {d} for {s}", .{ i, decl.name }); | 3557 | if (self.locals_free_list.popOrNull()) |index| { |
| 3514 | decl.link.macho.local_sym_index = i; | 3558 | log.debug(" (reusing symbol index {d})", .{index}); |
| 3515 | } else { | 3559 | break :blk index; |
| 3516 | log.debug("allocating symbol index {d} for {s}", .{ self.locals.items.len, decl.name }); | 3560 | } else { |
| 3517 | decl.link.macho.local_sym_index = @intCast(u32, self.locals.items.len); | 3561 | log.debug(" (allocating symbol index {d})", .{self.locals.items.len}); |
| 3518 | _ = self.locals.addOneAssumeCapacity(); | 3562 | const index = @intCast(u32, self.locals.items.len); |
| 3519 | } | 3563 | _ = self.locals.addOneAssumeCapacity(); |
| 3564 | break :blk index; | ||
| 3565 | } | ||
| 3566 | }; | ||
| 3520 | 3567 | ||
| 3521 | self.locals.items[decl.link.macho.local_sym_index] = .{ | 3568 | self.locals.items[index] = .{ |
| 3522 | .n_strx = 0, | 3569 | .n_strx = 0, |
| 3523 | .n_type = 0, | 3570 | .n_type = 0, |
| 3524 | .n_sect = 0, | 3571 | .n_sect = 0, |
| ... | @@ -3526,24 +3573,86 @@ pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void { | ... | @@ -3526,24 +3573,86 @@ pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void { |
| 3526 | .n_value = 0, | 3573 | .n_value = 0, |
| 3527 | }; | 3574 | }; |
| 3528 | 3575 | ||
| 3529 | // TODO try popping from free list first before allocating a new GOT atom. | 3576 | return index; |
| 3530 | const target = Atom.Relocation.Target{ .local = decl.link.macho.local_sym_index }; | 3577 | } |
| 3531 | const value_ptr = blk: { | 3578 | |
| 3532 | if (self.got_entries_map_free_list.popOrNull()) |i| { | 3579 | pub fn allocateGotEntry(self: *MachO, target: Atom.Relocation.Target) !u32 { |
| 3533 | log.debug("reusing GOT entry index {d} for {s}", .{ i, decl.name }); | 3580 | try self.got_entries.ensureUnusedCapacity(self.base.allocator, 1); |
| 3534 | self.got_entries_map.keys()[i] = target; | 3581 | |
| 3535 | const value_ptr = self.got_entries_map.getPtr(target).?; | 3582 | const index = blk: { |
| 3536 | break :blk value_ptr; | 3583 | if (self.got_entries_free_list.popOrNull()) |index| { |
| 3584 | log.debug(" (reusing GOT entry index {d})", .{index}); | ||
| 3585 | break :blk index; | ||
| 3537 | } else { | 3586 | } else { |
| 3538 | const res = try self.got_entries_map.getOrPut(self.base.allocator, target); | 3587 | log.debug(" (allocating GOT entry at index {d})", .{self.got_entries.items.len}); |
| 3539 | log.debug("creating new GOT entry at index {d} for {s}", .{ | 3588 | const index = @intCast(u32, self.got_entries.items.len); |
| 3540 | self.got_entries_map.getIndex(target).?, | 3589 | _ = self.got_entries.addOneAssumeCapacity(); |
| 3541 | decl.name, | 3590 | break :blk index; |
| 3542 | }); | 3591 | } |
| 3543 | break :blk res.value_ptr; | 3592 | }; |
| 3593 | |||
| 3594 | self.got_entries.items[index] = .{ | ||
| 3595 | .target = target, | ||
| 3596 | .atom = undefined, | ||
| 3597 | }; | ||
| 3598 | try self.got_entries_table.putNoClobber(self.base.allocator, target, index); | ||
| 3599 | |||
| 3600 | return index; | ||
| 3601 | } | ||
| 3602 | |||
| 3603 | pub fn allocateStubEntry(self: *MachO, n_strx: u32) !u32 { | ||
| 3604 | try self.stubs.ensureUnusedCapacity(self.base.allocator, 1); | ||
| 3605 | |||
| 3606 | const index = blk: { | ||
| 3607 | if (self.stubs_free_list.popOrNull()) |index| { | ||
| 3608 | log.debug(" (reusing stub entry index {d})", .{index}); | ||
| 3609 | break :blk index; | ||
| 3610 | } else { | ||
| 3611 | log.debug(" (allocating stub entry at index {d})", .{self.stubs.items.len}); | ||
| 3612 | const index = @intCast(u32, self.stubs.items.len); | ||
| 3613 | _ = self.stubs.addOneAssumeCapacity(); | ||
| 3614 | break :blk index; | ||
| 3615 | } | ||
| 3616 | }; | ||
| 3617 | |||
| 3618 | self.stubs.items[index] = undefined; | ||
| 3619 | try self.stubs_table.putNoClobber(self.base.allocator, n_strx, index); | ||
| 3620 | |||
| 3621 | return index; | ||
| 3622 | } | ||
| 3623 | |||
| 3624 | pub fn allocateTlvPtrEntry(self: *MachO, target: Atom.Relocation.Target) !u32 { | ||
| 3625 | try self.tlv_ptr_entries.ensureUnusedCapacity(self.base.allocator, 1); | ||
| 3626 | |||
| 3627 | const index = blk: { | ||
| 3628 | if (self.tlv_ptr_entries_free_list.popOrNull()) |index| { | ||
| 3629 | log.debug(" (reusing TLV ptr entry index {d})", .{index}); | ||
| 3630 | break :blk index; | ||
| 3631 | } else { | ||
| 3632 | log.debug(" (allocating TLV ptr entry at index {d})", .{self.tlv_ptr_entries.items.len}); | ||
| 3633 | const index = @intCast(u32, self.tlv_ptr_entries.items.len); | ||
| 3634 | _ = self.tlv_ptr_entries.addOneAssumeCapacity(); | ||
| 3635 | break :blk index; | ||
| 3544 | } | 3636 | } |
| 3545 | }; | 3637 | }; |
| 3546 | value_ptr.* = try self.createGotAtom(target); | 3638 | |
| 3639 | self.tlv_ptr_entries.items[index] = .{ .target = target, .atom = undefined }; | ||
| 3640 | try self.tlv_ptr_entries_table.putNoClobber(self.base.allocator, target, index); | ||
| 3641 | |||
| 3642 | return index; | ||
| 3643 | } | ||
| 3644 | |||
| 3645 | pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void { | ||
| 3646 | if (self.llvm_object) |_| return; | ||
| 3647 | if (decl.link.macho.local_sym_index != 0) return; | ||
| 3648 | |||
| 3649 | decl.link.macho.local_sym_index = try self.allocateLocalSymbol(); | ||
| 3650 | try self.decls.putNoClobber(self.base.allocator, decl, null); | ||
| 3651 | |||
| 3652 | const got_target = .{ .local = decl.link.macho.local_sym_index }; | ||
| 3653 | const got_index = try self.allocateGotEntry(got_target); | ||
| 3654 | const got_atom = try self.createGotAtom(got_target); | ||
| 3655 | self.got_entries.items[got_index].atom = got_atom; | ||
| 3547 | } | 3656 | } |
| 3548 | 3657 | ||
| 3549 | pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void { | 3658 | pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void { |
| ... | @@ -3557,6 +3666,7 @@ pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liv | ... | @@ -3557,6 +3666,7 @@ pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liv |
| 3557 | defer tracy.end(); | 3666 | defer tracy.end(); |
| 3558 | 3667 | ||
| 3559 | const decl = func.owner_decl; | 3668 | const decl = func.owner_decl; |
| 3669 | self.freeUnnamedConsts(decl); | ||
| 3560 | // TODO clearing the code and relocs buffer should probably be orchestrated | 3670 | // TODO clearing the code and relocs buffer should probably be orchestrated |
| 3561 | // in a different, smarter, more automatic way somewhere else, in a more centralised | 3671 | // in a different, smarter, more automatic way somewhere else, in a more centralised |
| 3562 | // way than this. | 3672 | // way than this. |
| ... | @@ -3624,6 +3734,70 @@ pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liv | ... | @@ -3624,6 +3734,70 @@ pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liv |
| 3624 | try self.updateDeclExports(module, decl, decl_exports); | 3734 | try self.updateDeclExports(module, decl, decl_exports); |
| 3625 | } | 3735 | } |
| 3626 | 3736 | ||
| 3737 | pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl: *Module.Decl) !u32 { | ||
| 3738 | var code_buffer = std.ArrayList(u8).init(self.base.allocator); | ||
| 3739 | defer code_buffer.deinit(); | ||
| 3740 | |||
| 3741 | const module = self.base.options.module.?; | ||
| 3742 | const gop = try self.unnamed_const_atoms.getOrPut(self.base.allocator, decl); | ||
| 3743 | if (!gop.found_existing) { | ||
| 3744 | gop.value_ptr.* = .{}; | ||
| 3745 | } | ||
| 3746 | const unnamed_consts = gop.value_ptr; | ||
| 3747 | |||
| 3748 | const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), typed_value, &code_buffer, .{ | ||
| 3749 | .none = .{}, | ||
| 3750 | }); | ||
| 3751 | const code = switch (res) { | ||
| 3752 | .externally_managed => |x| x, | ||
| 3753 | .appended => code_buffer.items, | ||
| 3754 | .fail => |em| { | ||
| 3755 | decl.analysis = .codegen_failure; | ||
| 3756 | try module.failed_decls.put(module.gpa, decl, em); | ||
| 3757 | return error.AnalysisFail; | ||
| 3758 | }, | ||
| 3759 | }; | ||
| 3760 | |||
| 3761 | const name_str_index = blk: { | ||
| 3762 | const index = unnamed_consts.items.len; | ||
| 3763 | const name = try std.fmt.allocPrint(self.base.allocator, "__unnamed_{s}_{d}", .{ decl.name, index }); | ||
| 3764 | defer self.base.allocator.free(name); | ||
| 3765 | break :blk try self.makeString(name); | ||
| 3766 | }; | ||
| 3767 | const name = self.getString(name_str_index); | ||
| 3768 | |||
| 3769 | log.debug("allocating symbol indexes for {s}", .{name}); | ||
| 3770 | |||
| 3771 | const required_alignment = typed_value.ty.abiAlignment(self.base.options.target); | ||
| 3772 | const match = (try self.getMatchingSection(.{ | ||
| 3773 | .segname = makeStaticString("__TEXT"), | ||
| 3774 | .sectname = makeStaticString("__const"), | ||
| 3775 | .size = code.len, | ||
| 3776 | .@"align" = math.log2(required_alignment), | ||
| 3777 | })).?; | ||
| 3778 | const local_sym_index = try self.allocateLocalSymbol(); | ||
| 3779 | const atom = try self.createEmptyAtom(local_sym_index, code.len, math.log2(required_alignment)); | ||
| 3780 | mem.copy(u8, atom.code.items, code); | ||
| 3781 | const addr = try self.allocateAtom(atom, code.len, required_alignment, match); | ||
| 3782 | |||
| 3783 | log.debug("allocated atom for {s} at 0x{x}", .{ name, addr }); | ||
| 3784 | |||
| 3785 | errdefer self.freeAtom(atom, match, true); | ||
| 3786 | |||
| 3787 | const symbol = &self.locals.items[atom.local_sym_index]; | ||
| 3788 | symbol.* = .{ | ||
| 3789 | .n_strx = name_str_index, | ||
| 3790 | .n_type = macho.N_SECT, | ||
| 3791 | .n_sect = @intCast(u8, self.section_ordinals.getIndex(match).?) + 1, | ||
| 3792 | .n_desc = 0, | ||
| 3793 | .n_value = addr, | ||
| 3794 | }; | ||
| 3795 | |||
| 3796 | try unnamed_consts.append(self.base.allocator, atom); | ||
| 3797 | |||
| 3798 | return atom.local_sym_index; | ||
| 3799 | } | ||
| 3800 | |||
| 3627 | pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { | 3801 | pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { |
| 3628 | if (build_options.skip_non_native and builtin.object_format != .macho) { | 3802 | if (build_options.skip_non_native and builtin.object_format != .macho) { |
| 3629 | @panic("Attempted to compile for object format that was disabled by build configuration"); | 3803 | @panic("Attempted to compile for object format that was disabled by build configuration"); |
| ... | @@ -3879,7 +4053,8 @@ fn placeDecl(self: *MachO, decl: *Module.Decl, code_len: usize) !*macho.nlist_64 | ... | @@ -3879,7 +4053,8 @@ fn placeDecl(self: *MachO, decl: *Module.Decl, code_len: usize) !*macho.nlist_64 |
| 3879 | 4053 | ||
| 3880 | if (vaddr != symbol.n_value) { | 4054 | if (vaddr != symbol.n_value) { |
| 3881 | log.debug(" (writing new GOT entry)", .{}); | 4055 | log.debug(" (writing new GOT entry)", .{}); |
| 3882 | const got_atom = self.got_entries_map.get(.{ .local = decl.link.macho.local_sym_index }).?; | 4056 | const got_index = self.got_entries_table.get(.{ .local = decl.link.macho.local_sym_index }).?; |
| 4057 | const got_atom = self.got_entries.items[got_index].atom; | ||
| 3883 | const got_sym = &self.locals.items[got_atom.local_sym_index]; | 4058 | const got_sym = &self.locals.items[got_atom.local_sym_index]; |
| 3884 | const got_vaddr = try self.allocateAtom(got_atom, @sizeOf(u64), 8, .{ | 4059 | const got_vaddr = try self.allocateAtom(got_atom, @sizeOf(u64), 8, .{ |
| 3885 | .seg = self.data_const_segment_cmd_index.?, | 4060 | .seg = self.data_const_segment_cmd_index.?, |
| ... | @@ -3920,7 +4095,7 @@ fn placeDecl(self: *MachO, decl: *Module.Decl, code_len: usize) !*macho.nlist_64 | ... | @@ -3920,7 +4095,7 @@ fn placeDecl(self: *MachO, decl: *Module.Decl, code_len: usize) !*macho.nlist_64 |
| 3920 | 4095 | ||
| 3921 | log.debug("allocated atom for {s} at 0x{x}", .{ decl_name, addr }); | 4096 | log.debug("allocated atom for {s} at 0x{x}", .{ decl_name, addr }); |
| 3922 | 4097 | ||
| 3923 | errdefer self.freeAtom(&decl.link.macho, match); | 4098 | errdefer self.freeAtom(&decl.link.macho, match, false); |
| 3924 | 4099 | ||
| 3925 | symbol.* = .{ | 4100 | symbol.* = .{ |
| 3926 | .n_strx = name_str_index, | 4101 | .n_strx = name_str_index, |
| ... | @@ -3929,7 +4104,8 @@ fn placeDecl(self: *MachO, decl: *Module.Decl, code_len: usize) !*macho.nlist_64 | ... | @@ -3929,7 +4104,8 @@ fn placeDecl(self: *MachO, decl: *Module.Decl, code_len: usize) !*macho.nlist_64 |
| 3929 | .n_desc = 0, | 4104 | .n_desc = 0, |
| 3930 | .n_value = addr, | 4105 | .n_value = addr, |
| 3931 | }; | 4106 | }; |
| 3932 | const got_atom = self.got_entries_map.get(.{ .local = decl.link.macho.local_sym_index }).?; | 4107 | const got_index = self.got_entries_table.get(.{ .local = decl.link.macho.local_sym_index }).?; |
| 4108 | const got_atom = self.got_entries.items[got_index].atom; | ||
| 3933 | const got_sym = &self.locals.items[got_atom.local_sym_index]; | 4109 | const got_sym = &self.locals.items[got_atom.local_sym_index]; |
| 3934 | const vaddr = try self.allocateAtom(got_atom, @sizeOf(u64), 8, .{ | 4110 | const vaddr = try self.allocateAtom(got_atom, @sizeOf(u64), 8, .{ |
| 3935 | .seg = self.data_const_segment_cmd_index.?, | 4111 | .seg = self.data_const_segment_cmd_index.?, |
| ... | @@ -4103,6 +4279,19 @@ pub fn deleteExport(self: *MachO, exp: Export) void { | ... | @@ -4103,6 +4279,19 @@ pub fn deleteExport(self: *MachO, exp: Export) void { |
| 4103 | global.n_value = 0; | 4279 | global.n_value = 0; |
| 4104 | } | 4280 | } |
| 4105 | 4281 | ||
| 4282 | fn freeUnnamedConsts(self: *MachO, decl: *Module.Decl) void { | ||
| 4283 | const unnamed_consts = self.unnamed_const_atoms.getPtr(decl) orelse return; | ||
| 4284 | for (unnamed_consts.items) |atom| { | ||
| 4285 | self.freeAtom(atom, .{ | ||
| 4286 | .seg = self.text_segment_cmd_index.?, | ||
| 4287 | .sect = self.text_const_section_index.?, | ||
| 4288 | }, true); | ||
| 4289 | self.locals_free_list.append(self.base.allocator, atom.local_sym_index) catch {}; | ||
| 4290 | self.locals.items[atom.local_sym_index].n_type = 0; | ||
| 4291 | } | ||
| 4292 | unnamed_consts.clearAndFree(self.base.allocator); | ||
| 4293 | } | ||
| 4294 | |||
| 4106 | pub fn freeDecl(self: *MachO, decl: *Module.Decl) void { | 4295 | pub fn freeDecl(self: *MachO, decl: *Module.Decl) void { |
| 4107 | if (build_options.have_llvm) { | 4296 | if (build_options.have_llvm) { |
| 4108 | if (self.llvm_object) |llvm_object| return llvm_object.freeDecl(decl); | 4297 | if (self.llvm_object) |llvm_object| return llvm_object.freeDecl(decl); |
| ... | @@ -4110,15 +4299,19 @@ pub fn freeDecl(self: *MachO, decl: *Module.Decl) void { | ... | @@ -4110,15 +4299,19 @@ pub fn freeDecl(self: *MachO, decl: *Module.Decl) void { |
| 4110 | log.debug("freeDecl {*}", .{decl}); | 4299 | log.debug("freeDecl {*}", .{decl}); |
| 4111 | const kv = self.decls.fetchSwapRemove(decl); | 4300 | const kv = self.decls.fetchSwapRemove(decl); |
| 4112 | if (kv.?.value) |match| { | 4301 | if (kv.?.value) |match| { |
| 4113 | self.freeAtom(&decl.link.macho, match); | 4302 | self.freeAtom(&decl.link.macho, match, false); |
| 4303 | self.freeUnnamedConsts(decl); | ||
| 4114 | } | 4304 | } |
| 4115 | // Appending to free lists is allowed to fail because the free lists are heuristics based anyway. | 4305 | // Appending to free lists is allowed to fail because the free lists are heuristics based anyway. |
| 4116 | if (decl.link.macho.local_sym_index != 0) { | 4306 | if (decl.link.macho.local_sym_index != 0) { |
| 4117 | self.locals_free_list.append(self.base.allocator, decl.link.macho.local_sym_index) catch {}; | 4307 | self.locals_free_list.append(self.base.allocator, decl.link.macho.local_sym_index) catch {}; |
| 4118 | 4308 | ||
| 4119 | // Try freeing GOT atom | 4309 | // Try freeing GOT atom if this decl had one |
| 4120 | const got_index = self.got_entries_map.getIndex(.{ .local = decl.link.macho.local_sym_index }).?; | 4310 | if (self.got_entries_table.get(.{ .local = decl.link.macho.local_sym_index })) |got_index| { |
| 4121 | self.got_entries_map_free_list.append(self.base.allocator, @intCast(u32, got_index)) catch {}; | 4311 | self.got_entries_free_list.append(self.base.allocator, @intCast(u32, got_index)) catch {}; |
| 4312 | self.got_entries.items[got_index] = .{ .target = .{ .local = 0 }, .atom = undefined }; | ||
| 4313 | _ = self.got_entries_table.swapRemove(.{ .local = decl.link.macho.local_sym_index }); | ||
| 4314 | } | ||
| 4122 | 4315 | ||
| 4123 | self.locals.items[decl.link.macho.local_sym_index].n_type = 0; | 4316 | self.locals.items[decl.link.macho.local_sym_index].n_type = 0; |
| 4124 | decl.link.macho.local_sym_index = 0; | 4317 | decl.link.macho.local_sym_index = 0; |
| ... | @@ -5932,8 +6125,8 @@ fn writeSymbolTable(self: *MachO) !void { | ... | @@ -5932,8 +6125,8 @@ fn writeSymbolTable(self: *MachO) !void { |
| 5932 | const data_segment = &self.load_commands.items[self.data_segment_cmd_index.?].segment; | 6125 | const data_segment = &self.load_commands.items[self.data_segment_cmd_index.?].segment; |
| 5933 | const la_symbol_ptr = &data_segment.sections.items[self.la_symbol_ptr_section_index.?]; | 6126 | const la_symbol_ptr = &data_segment.sections.items[self.la_symbol_ptr_section_index.?]; |
| 5934 | 6127 | ||
| 5935 | const nstubs = @intCast(u32, self.stubs_map.keys().len); | 6128 | const nstubs = @intCast(u32, self.stubs_table.keys().len); |
| 5936 | const ngot_entries = @intCast(u32, self.got_entries_map.keys().len); | 6129 | const ngot_entries = @intCast(u32, self.got_entries_table.keys().len); |
| 5937 | 6130 | ||
| 5938 | dysymtab.indirectsymoff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize); | 6131 | dysymtab.indirectsymoff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize); |
| 5939 | dysymtab.nindirectsyms = nstubs * 2 + ngot_entries; | 6132 | dysymtab.nindirectsyms = nstubs * 2 + ngot_entries; |
| ... | @@ -5953,7 +6146,7 @@ fn writeSymbolTable(self: *MachO) !void { | ... | @@ -5953,7 +6146,7 @@ fn writeSymbolTable(self: *MachO) !void { |
| 5953 | var writer = stream.writer(); | 6146 | var writer = stream.writer(); |
| 5954 | 6147 | ||
| 5955 | stubs.reserved1 = 0; | 6148 | stubs.reserved1 = 0; |
| 5956 | for (self.stubs_map.keys()) |key| { | 6149 | for (self.stubs_table.keys()) |key| { |
| 5957 | const resolv = self.symbol_resolver.get(key).?; | 6150 | const resolv = self.symbol_resolver.get(key).?; |
| 5958 | switch (resolv.where) { | 6151 | switch (resolv.where) { |
| 5959 | .global => try writer.writeIntLittle(u32, macho.INDIRECT_SYMBOL_LOCAL), | 6152 | .global => try writer.writeIntLittle(u32, macho.INDIRECT_SYMBOL_LOCAL), |
| ... | @@ -5962,7 +6155,7 @@ fn writeSymbolTable(self: *MachO) !void { | ... | @@ -5962,7 +6155,7 @@ fn writeSymbolTable(self: *MachO) !void { |
| 5962 | } | 6155 | } |
| 5963 | 6156 | ||
| 5964 | got.reserved1 = nstubs; | 6157 | got.reserved1 = nstubs; |
| 5965 | for (self.got_entries_map.keys()) |key| { | 6158 | for (self.got_entries_table.keys()) |key| { |
| 5966 | switch (key) { | 6159 | switch (key) { |
| 5967 | .local => try writer.writeIntLittle(u32, macho.INDIRECT_SYMBOL_LOCAL), | 6160 | .local => try writer.writeIntLittle(u32, macho.INDIRECT_SYMBOL_LOCAL), |
| 5968 | .global => |n_strx| { | 6161 | .global => |n_strx| { |
| ... | @@ -5976,7 +6169,7 @@ fn writeSymbolTable(self: *MachO) !void { | ... | @@ -5976,7 +6169,7 @@ fn writeSymbolTable(self: *MachO) !void { |
| 5976 | } | 6169 | } |
| 5977 | 6170 | ||
| 5978 | la_symbol_ptr.reserved1 = got.reserved1 + ngot_entries; | 6171 | la_symbol_ptr.reserved1 = got.reserved1 + ngot_entries; |
| 5979 | for (self.stubs_map.keys()) |key| { | 6172 | for (self.stubs_table.keys()) |key| { |
| 5980 | const resolv = self.symbol_resolver.get(key).?; | 6173 | const resolv = self.symbol_resolver.get(key).?; |
| 5981 | switch (resolv.where) { | 6174 | switch (resolv.where) { |
| 5982 | .global => try writer.writeIntLittle(u32, macho.INDIRECT_SYMBOL_LOCAL), | 6175 | .global => try writer.writeIntLittle(u32, macho.INDIRECT_SYMBOL_LOCAL), |
| ... | @@ -6348,7 +6541,7 @@ fn snapshotState(self: *MachO) !void { | ... | @@ -6348,7 +6541,7 @@ fn snapshotState(self: *MachO) !void { |
| 6348 | }; | 6541 | }; |
| 6349 | 6542 | ||
| 6350 | if (is_via_got) { | 6543 | if (is_via_got) { |
| 6351 | const got_atom = self.got_entries_map.get(rel.target) orelse break :blk 0; | 6544 | const got_atom = self.got_entries_table.get(rel.target) orelse break :blk 0; |
| 6352 | break :blk self.locals.items[got_atom.local_sym_index].n_value; | 6545 | break :blk self.locals.items[got_atom.local_sym_index].n_value; |
| 6353 | } | 6546 | } |
| 6354 | 6547 | ||
| ... | @@ -6380,10 +6573,11 @@ fn snapshotState(self: *MachO) !void { | ... | @@ -6380,10 +6573,11 @@ fn snapshotState(self: *MachO) !void { |
| 6380 | switch (resolv.where) { | 6573 | switch (resolv.where) { |
| 6381 | .global => break :blk self.globals.items[resolv.where_index].n_value, | 6574 | .global => break :blk self.globals.items[resolv.where_index].n_value, |
| 6382 | .undef => { | 6575 | .undef => { |
| 6383 | break :blk if (self.stubs_map.get(n_strx)) |stub_atom| | 6576 | if (self.stubs_table.get(n_strx)) |stub_index| { |
| 6384 | self.locals.items[stub_atom.local_sym_index].n_value | 6577 | const stub_atom = self.stubs.items[stub_index]; |
| 6385 | else | 6578 | break :blk self.locals.items[stub_atom.local_sym_index].n_value; |
| 6386 | 0; | 6579 | } |
| 6580 | break :blk 0; | ||
| 6387 | }, | 6581 | }, |
| 6388 | } | 6582 | } |
| 6389 | }, | 6583 | }, |
| ... | @@ -6508,15 +6702,20 @@ fn logSymtab(self: MachO) void { | ... | @@ -6508,15 +6702,20 @@ fn logSymtab(self: MachO) void { |
| 6508 | } | 6702 | } |
| 6509 | 6703 | ||
| 6510 | log.debug("GOT entries:", .{}); | 6704 | log.debug("GOT entries:", .{}); |
| 6511 | for (self.got_entries_map.keys()) |key| { | 6705 | for (self.got_entries_table.values()) |value| { |
| 6706 | const key = self.got_entries.items[value].target; | ||
| 6707 | const atom = self.got_entries.items[value].atom; | ||
| 6512 | switch (key) { | 6708 | switch (key) { |
| 6513 | .local => |sym_index| log.debug(" {} => {d}", .{ key, sym_index }), | 6709 | .local => { |
| 6710 | const sym = self.locals.items[atom.local_sym_index]; | ||
| 6711 | log.debug(" {} => {s}", .{ key, self.getString(sym.n_strx) }); | ||
| 6712 | }, | ||
| 6514 | .global => |n_strx| log.debug(" {} => {s}", .{ key, self.getString(n_strx) }), | 6713 | .global => |n_strx| log.debug(" {} => {s}", .{ key, self.getString(n_strx) }), |
| 6515 | } | 6714 | } |
| 6516 | } | 6715 | } |
| 6517 | 6716 | ||
| 6518 | log.debug("__thread_ptrs entries:", .{}); | 6717 | log.debug("__thread_ptrs entries:", .{}); |
| 6519 | for (self.tlv_ptr_entries_map.keys()) |key| { | 6718 | for (self.tlv_ptr_entries_table.keys()) |key| { |
| 6520 | switch (key) { | 6719 | switch (key) { |
| 6521 | .local => unreachable, | 6720 | .local => unreachable, |
| 6522 | .global => |n_strx| log.debug(" {} => {s}", .{ key, self.getString(n_strx) }), | 6721 | .global => |n_strx| log.debug(" {} => {s}", .{ key, self.getString(n_strx) }), |
| ... | @@ -6524,7 +6723,7 @@ fn logSymtab(self: MachO) void { | ... | @@ -6524,7 +6723,7 @@ fn logSymtab(self: MachO) void { |
| 6524 | } | 6723 | } |
| 6525 | 6724 | ||
| 6526 | log.debug("stubs:", .{}); | 6725 | log.debug("stubs:", .{}); |
| 6527 | for (self.stubs_map.keys()) |key| { | 6726 | for (self.stubs_table.keys()) |key| { |
| 6528 | log.debug(" {} => {s}", .{ key, self.getString(key) }); | 6727 | log.debug(" {} => {s}", .{ key, self.getString(key) }); |
| 6529 | } | 6728 | } |
| 6530 | } | 6729 | } |
src/link/MachO/Atom.zig+22-70| ... | @@ -545,28 +545,11 @@ fn addPtrBindingOrRebase( | ... | @@ -545,28 +545,11 @@ fn addPtrBindingOrRebase( |
| 545 | } | 545 | } |
| 546 | 546 | ||
| 547 | fn addTlvPtrEntry(target: Relocation.Target, context: RelocContext) !void { | 547 | fn addTlvPtrEntry(target: Relocation.Target, context: RelocContext) !void { |
| 548 | if (context.macho_file.tlv_ptr_entries_map.contains(target)) return; | 548 | if (context.macho_file.tlv_ptr_entries_table.contains(target)) return; |
| 549 | 549 | ||
| 550 | const value_ptr = blk: { | 550 | const index = try context.macho_file.allocateTlvPtrEntry(target); |
| 551 | if (context.macho_file.tlv_ptr_entries_map_free_list.popOrNull()) |i| { | ||
| 552 | log.debug("reusing __thread_ptrs entry index {d} for {}", .{ i, target }); | ||
| 553 | context.macho_file.tlv_ptr_entries_map.keys()[i] = target; | ||
| 554 | const value_ptr = context.macho_file.tlv_ptr_entries_map.getPtr(target).?; | ||
| 555 | break :blk value_ptr; | ||
| 556 | } else { | ||
| 557 | const res = try context.macho_file.tlv_ptr_entries_map.getOrPut( | ||
| 558 | context.macho_file.base.allocator, | ||
| 559 | target, | ||
| 560 | ); | ||
| 561 | log.debug("creating new __thread_ptrs entry at index {d} for {}", .{ | ||
| 562 | context.macho_file.tlv_ptr_entries_map.getIndex(target).?, | ||
| 563 | target, | ||
| 564 | }); | ||
| 565 | break :blk res.value_ptr; | ||
| 566 | } | ||
| 567 | }; | ||
| 568 | const atom = try context.macho_file.createTlvPtrAtom(target); | 551 | const atom = try context.macho_file.createTlvPtrAtom(target); |
| 569 | value_ptr.* = atom; | 552 | context.macho_file.tlv_ptr_entries.items[index].atom = atom; |
| 570 | 553 | ||
| 571 | const match = (try context.macho_file.getMatchingSection(.{ | 554 | const match = (try context.macho_file.getMatchingSection(.{ |
| 572 | .segname = MachO.makeStaticString("__DATA"), | 555 | .segname = MachO.makeStaticString("__DATA"), |
| ... | @@ -586,28 +569,11 @@ fn addTlvPtrEntry(target: Relocation.Target, context: RelocContext) !void { | ... | @@ -586,28 +569,11 @@ fn addTlvPtrEntry(target: Relocation.Target, context: RelocContext) !void { |
| 586 | } | 569 | } |
| 587 | 570 | ||
| 588 | fn addGotEntry(target: Relocation.Target, context: RelocContext) !void { | 571 | fn addGotEntry(target: Relocation.Target, context: RelocContext) !void { |
| 589 | if (context.macho_file.got_entries_map.contains(target)) return; | 572 | if (context.macho_file.got_entries_table.contains(target)) return; |
| 590 | 573 | ||
| 591 | const value_ptr = blk: { | 574 | const index = try context.macho_file.allocateGotEntry(target); |
| 592 | if (context.macho_file.got_entries_map_free_list.popOrNull()) |i| { | ||
| 593 | log.debug("reusing GOT entry index {d} for {}", .{ i, target }); | ||
| 594 | context.macho_file.got_entries_map.keys()[i] = target; | ||
| 595 | const value_ptr = context.macho_file.got_entries_map.getPtr(target).?; | ||
| 596 | break :blk value_ptr; | ||
| 597 | } else { | ||
| 598 | const res = try context.macho_file.got_entries_map.getOrPut( | ||
| 599 | context.macho_file.base.allocator, | ||
| 600 | target, | ||
| 601 | ); | ||
| 602 | log.debug("creating new GOT entry at index {d} for {}", .{ | ||
| 603 | context.macho_file.got_entries_map.getIndex(target).?, | ||
| 604 | target, | ||
| 605 | }); | ||
| 606 | break :blk res.value_ptr; | ||
| 607 | } | ||
| 608 | }; | ||
| 609 | const atom = try context.macho_file.createGotAtom(target); | 575 | const atom = try context.macho_file.createGotAtom(target); |
| 610 | value_ptr.* = atom; | 576 | context.macho_file.got_entries.items[index].atom = atom; |
| 611 | 577 | ||
| 612 | const match = MachO.MatchingSection{ | 578 | const match = MachO.MatchingSection{ |
| 613 | .seg = context.macho_file.data_const_segment_cmd_index.?, | 579 | .seg = context.macho_file.data_const_segment_cmd_index.?, |
| ... | @@ -627,30 +593,13 @@ fn addGotEntry(target: Relocation.Target, context: RelocContext) !void { | ... | @@ -627,30 +593,13 @@ fn addGotEntry(target: Relocation.Target, context: RelocContext) !void { |
| 627 | 593 | ||
| 628 | fn addStub(target: Relocation.Target, context: RelocContext) !void { | 594 | fn addStub(target: Relocation.Target, context: RelocContext) !void { |
| 629 | if (target != .global) return; | 595 | if (target != .global) return; |
| 630 | if (context.macho_file.stubs_map.contains(target.global)) return; | 596 | if (context.macho_file.stubs_table.contains(target.global)) return; |
| 631 | // If the symbol has been resolved as defined globally elsewhere (in a different translation unit), | 597 | // If the symbol has been resolved as defined globally elsewhere (in a different translation unit), |
| 632 | // then skip creating stub entry. | 598 | // then skip creating stub entry. |
| 633 | // TODO Is this the correct for the incremental? | 599 | // TODO Is this the correct for the incremental? |
| 634 | if (context.macho_file.symbol_resolver.get(target.global).?.where == .global) return; | 600 | if (context.macho_file.symbol_resolver.get(target.global).?.where == .global) return; |
| 635 | 601 | ||
| 636 | const value_ptr = blk: { | 602 | const stub_index = try context.macho_file.allocateStubEntry(target.global); |
| 637 | if (context.macho_file.stubs_map_free_list.popOrNull()) |i| { | ||
| 638 | log.debug("reusing stubs entry index {d} for {}", .{ i, target }); | ||
| 639 | context.macho_file.stubs_map.keys()[i] = target.global; | ||
| 640 | const value_ptr = context.macho_file.stubs_map.getPtr(target.global).?; | ||
| 641 | break :blk value_ptr; | ||
| 642 | } else { | ||
| 643 | const res = try context.macho_file.stubs_map.getOrPut( | ||
| 644 | context.macho_file.base.allocator, | ||
| 645 | target.global, | ||
| 646 | ); | ||
| 647 | log.debug("creating new stubs entry at index {d} for {}", .{ | ||
| 648 | context.macho_file.stubs_map.getIndex(target.global).?, | ||
| 649 | target, | ||
| 650 | }); | ||
| 651 | break :blk res.value_ptr; | ||
| 652 | } | ||
| 653 | }; | ||
| 654 | 603 | ||
| 655 | // TODO clean this up! | 604 | // TODO clean this up! |
| 656 | const stub_helper_atom = atom: { | 605 | const stub_helper_atom = atom: { |
| ... | @@ -707,7 +656,7 @@ fn addStub(target: Relocation.Target, context: RelocContext) !void { | ... | @@ -707,7 +656,7 @@ fn addStub(target: Relocation.Target, context: RelocContext) !void { |
| 707 | } else { | 656 | } else { |
| 708 | try context.object.end_atoms.putNoClobber(context.allocator, match, atom); | 657 | try context.object.end_atoms.putNoClobber(context.allocator, match, atom); |
| 709 | } | 658 | } |
| 710 | value_ptr.* = atom; | 659 | context.macho_file.stubs.items[stub_index] = atom; |
| 711 | } | 660 | } |
| 712 | 661 | ||
| 713 | pub fn resolveRelocs(self: *Atom, macho_file: *MachO) !void { | 662 | pub fn resolveRelocs(self: *Atom, macho_file: *MachO) !void { |
| ... | @@ -741,7 +690,7 @@ pub fn resolveRelocs(self: *Atom, macho_file: *MachO) !void { | ... | @@ -741,7 +690,7 @@ pub fn resolveRelocs(self: *Atom, macho_file: *MachO) !void { |
| 741 | }; | 690 | }; |
| 742 | 691 | ||
| 743 | if (is_via_got) { | 692 | if (is_via_got) { |
| 744 | const atom = macho_file.got_entries_map.get(rel.target) orelse { | 693 | const got_index = macho_file.got_entries_table.get(rel.target) orelse { |
| 745 | const n_strx = switch (rel.target) { | 694 | const n_strx = switch (rel.target) { |
| 746 | .local => |sym_index| macho_file.locals.items[sym_index].n_strx, | 695 | .local => |sym_index| macho_file.locals.items[sym_index].n_strx, |
| 747 | .global => |n_strx| n_strx, | 696 | .global => |n_strx| n_strx, |
| ... | @@ -750,6 +699,7 @@ pub fn resolveRelocs(self: *Atom, macho_file: *MachO) !void { | ... | @@ -750,6 +699,7 @@ pub fn resolveRelocs(self: *Atom, macho_file: *MachO) !void { |
| 750 | log.err(" this is an internal linker error", .{}); | 699 | log.err(" this is an internal linker error", .{}); |
| 751 | return error.FailedToResolveRelocationTarget; | 700 | return error.FailedToResolveRelocationTarget; |
| 752 | }; | 701 | }; |
| 702 | const atom = macho_file.got_entries.items[got_index].atom; | ||
| 753 | break :blk macho_file.locals.items[atom.local_sym_index].n_value; | 703 | break :blk macho_file.locals.items[atom.local_sym_index].n_value; |
| 754 | } | 704 | } |
| 755 | 705 | ||
| ... | @@ -795,15 +745,17 @@ pub fn resolveRelocs(self: *Atom, macho_file: *MachO) !void { | ... | @@ -795,15 +745,17 @@ pub fn resolveRelocs(self: *Atom, macho_file: *MachO) !void { |
| 795 | switch (resolv.where) { | 745 | switch (resolv.where) { |
| 796 | .global => break :blk macho_file.globals.items[resolv.where_index].n_value, | 746 | .global => break :blk macho_file.globals.items[resolv.where_index].n_value, |
| 797 | .undef => { | 747 | .undef => { |
| 798 | break :blk if (macho_file.stubs_map.get(n_strx)) |atom| | 748 | if (macho_file.stubs_table.get(n_strx)) |stub_index| { |
| 799 | macho_file.locals.items[atom.local_sym_index].n_value | 749 | const atom = macho_file.stubs.items[stub_index]; |
| 800 | else inner: { | 750 | break :blk macho_file.locals.items[atom.local_sym_index].n_value; |
| 801 | if (macho_file.tlv_ptr_entries_map.get(rel.target)) |atom| { | 751 | } else { |
| 752 | if (macho_file.tlv_ptr_entries_table.get(rel.target)) |tlv_ptr_index| { | ||
| 802 | is_via_thread_ptrs = true; | 753 | is_via_thread_ptrs = true; |
| 803 | break :inner macho_file.locals.items[atom.local_sym_index].n_value; | 754 | const atom = macho_file.tlv_ptr_entries.items[tlv_ptr_index].atom; |
| 755 | break :blk macho_file.locals.items[atom.local_sym_index].n_value; | ||
| 804 | } | 756 | } |
| 805 | break :inner 0; | 757 | break :blk 0; |
| 806 | }; | 758 | } |
| 807 | }, | 759 | }, |
| 808 | } | 760 | } |
| 809 | }, | 761 | }, |
src/link/Plan9.zig+9| ... | @@ -12,6 +12,7 @@ const File = link.File; | ... | @@ -12,6 +12,7 @@ const File = link.File; |
| 12 | const build_options = @import("build_options"); | 12 | const build_options = @import("build_options"); |
| 13 | const Air = @import("../Air.zig"); | 13 | const Air = @import("../Air.zig"); |
| 14 | const Liveness = @import("../Liveness.zig"); | 14 | const Liveness = @import("../Liveness.zig"); |
| 15 | const TypedValue = @import("../TypedValue.zig"); | ||
| 15 | 16 | ||
| 16 | const std = @import("std"); | 17 | const std = @import("std"); |
| 17 | const builtin = @import("builtin"); | 18 | const builtin = @import("builtin"); |
| ... | @@ -275,6 +276,14 @@ pub fn updateFunc(self: *Plan9, module: *Module, func: *Module.Fn, air: Air, liv | ... | @@ -275,6 +276,14 @@ pub fn updateFunc(self: *Plan9, module: *Module, func: *Module.Fn, air: Air, liv |
| 275 | return self.updateFinish(decl); | 276 | return self.updateFinish(decl); |
| 276 | } | 277 | } |
| 277 | 278 | ||
| 279 | pub fn lowerUnnamedConst(self: *Plan9, tv: TypedValue, decl: *Module.Decl) !u32 { | ||
| 280 | _ = self; | ||
| 281 | _ = tv; | ||
| 282 | _ = decl; | ||
| 283 | log.debug("TODO lowerUnnamedConst for Plan9", .{}); | ||
| 284 | return error.AnalysisFail; | ||
| 285 | } | ||
| 286 | |||
| 278 | pub fn updateDecl(self: *Plan9, module: *Module, decl: *Module.Decl) !void { | 287 | pub fn updateDecl(self: *Plan9, module: *Module, decl: *Module.Decl) !void { |
| 279 | if (decl.val.tag() == .extern_fn) { | 288 | if (decl.val.tag() == .extern_fn) { |
| 280 | return; // TODO Should we do more when front-end analyzed extern decl? | 289 | return; // TODO Should we do more when front-end analyzed extern decl? |
test/behavior/align.zig+1| ... | @@ -7,6 +7,7 @@ var foo: u8 align(4) = 100; | ... | @@ -7,6 +7,7 @@ var foo: u8 align(4) = 100; |
| 7 | 7 | ||
| 8 | test "global variable alignment" { | 8 | test "global variable alignment" { |
| 9 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | 9 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 10 | if (builtin.zig_backend == .stage2_x86_64 and builtin.os.tag == .macos) return error.SkipZigTest; | ||
| 10 | 11 | ||
| 11 | comptime try expect(@typeInfo(@TypeOf(&foo)).Pointer.alignment == 4); | 12 | comptime try expect(@typeInfo(@TypeOf(&foo)).Pointer.alignment == 4); |
| 12 | comptime try expect(@TypeOf(&foo) == *align(4) u8); | 13 | comptime try expect(@TypeOf(&foo) == *align(4) u8); |
test/behavior/cast.zig+13-10| ... | @@ -78,16 +78,19 @@ test "comptime_int @intToFloat" { | ... | @@ -78,16 +78,19 @@ test "comptime_int @intToFloat" { |
| 78 | try expect(@TypeOf(result) == f64); | 78 | try expect(@TypeOf(result) == f64); |
| 79 | try expect(result == 1234.0); | 79 | try expect(result == 1234.0); |
| 80 | } | 80 | } |
| 81 | { | 81 | if (builtin.zig_backend != .stage2_x86_64 or builtin.os.tag != .macos) { |
| 82 | const result = @intToFloat(f128, 1234); | 82 | // TODO investigate why this traps on x86_64-macos |
| 83 | try expect(@TypeOf(result) == f128); | 83 | { |
| 84 | try expect(result == 1234.0); | 84 | const result = @intToFloat(f128, 1234); |
| 85 | } | 85 | try expect(@TypeOf(result) == f128); |
| 86 | // big comptime_int (> 64 bits) to f128 conversion | 86 | try expect(result == 1234.0); |
| 87 | { | 87 | } |
| 88 | const result = @intToFloat(f128, 0x1_0000_0000_0000_0000); | 88 | // big comptime_int (> 64 bits) to f128 conversion |
| 89 | try expect(@TypeOf(result) == f128); | 89 | { |
| 90 | try expect(result == 0x1_0000_0000_0000_0000.0); | 90 | const result = @intToFloat(f128, 0x1_0000_0000_0000_0000); |
| 91 | try expect(@TypeOf(result) == f128); | ||
| 92 | try expect(result == 0x1_0000_0000_0000_0000.0); | ||
| 93 | } | ||
| 91 | } | 94 | } |
| 92 | } | 95 | } |
| 93 | 96 |
test/behavior/struct.zig+21| ... | @@ -51,6 +51,27 @@ test "non-packed struct has fields padded out to the required alignment" { | ... | @@ -51,6 +51,27 @@ test "non-packed struct has fields padded out to the required alignment" { |
| 51 | try expect(foo.fourth() == 2); | 51 | try expect(foo.fourth() == 2); |
| 52 | } | 52 | } |
| 53 | 53 | ||
| 54 | const SmallStruct = struct { | ||
| 55 | a: u8, | ||
| 56 | b: u32, | ||
| 57 | |||
| 58 | fn first(self: *SmallStruct) u8 { | ||
| 59 | return self.a; | ||
| 60 | } | ||
| 61 | |||
| 62 | fn second(self: *SmallStruct) u32 { | ||
| 63 | return self.b; | ||
| 64 | } | ||
| 65 | }; | ||
| 66 | |||
| 67 | test "lower unnamed constants" { | ||
| 68 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | ||
| 69 | |||
| 70 | var foo = SmallStruct{ .a = 1, .b = 255 }; | ||
| 71 | try expect(foo.first() == 1); | ||
| 72 | try expect(foo.second() == 255); | ||
| 73 | } | ||
| 74 | |||
| 54 | const StructWithNoFields = struct { | 75 | const StructWithNoFields = struct { |
| 55 | fn add(a: i32, b: i32) i32 { | 76 | fn add(a: i32, b: i32) i32 { |
| 56 | return a + b; | 77 | return a + b; |
test/stage2/x86_64.zig+88| ... | @@ -1844,6 +1844,94 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -1844,6 +1844,94 @@ pub fn addCases(ctx: *TestContext) !void { |
| 1844 | \\} | 1844 | \\} |
| 1845 | , ""); | 1845 | , ""); |
| 1846 | } | 1846 | } |
| 1847 | |||
| 1848 | { | ||
| 1849 | var case = ctx.exe("lower unnamed constants - structs", target); | ||
| 1850 | case.addCompareOutput( | ||
| 1851 | \\const Foo = struct { | ||
| 1852 | \\ a: u8, | ||
| 1853 | \\ b: u32, | ||
| 1854 | \\ | ||
| 1855 | \\ fn first(self: *Foo) u8 { | ||
| 1856 | \\ return self.a; | ||
| 1857 | \\ } | ||
| 1858 | \\ | ||
| 1859 | \\ fn second(self: *Foo) u32 { | ||
| 1860 | \\ return self.b; | ||
| 1861 | \\ } | ||
| 1862 | \\}; | ||
| 1863 | \\ | ||
| 1864 | \\pub fn main() void { | ||
| 1865 | \\ var foo = Foo{ .a = 1, .b = 5 }; | ||
| 1866 | \\ assert(foo.first() == 1); | ||
| 1867 | \\ assert(foo.second() == 5); | ||
| 1868 | \\} | ||
| 1869 | \\ | ||
| 1870 | \\fn assert(ok: bool) void { | ||
| 1871 | \\ if (!ok) unreachable; | ||
| 1872 | \\} | ||
| 1873 | , ""); | ||
| 1874 | |||
| 1875 | case.addCompareOutput( | ||
| 1876 | \\const Foo = struct { | ||
| 1877 | \\ a: u8, | ||
| 1878 | \\ b: u32, | ||
| 1879 | \\ | ||
| 1880 | \\ fn first(self: *Foo) u8 { | ||
| 1881 | \\ return self.a; | ||
| 1882 | \\ } | ||
| 1883 | \\ | ||
| 1884 | \\ fn second(self: *Foo) u32 { | ||
| 1885 | \\ return self.b; | ||
| 1886 | \\ } | ||
| 1887 | \\}; | ||
| 1888 | \\ | ||
| 1889 | \\pub fn main() void { | ||
| 1890 | \\ var foo = Foo{ .a = 1, .b = 5 }; | ||
| 1891 | \\ assert(foo.first() == 1); | ||
| 1892 | \\ assert(foo.second() == 5); | ||
| 1893 | \\ | ||
| 1894 | \\ foo.a = 10; | ||
| 1895 | \\ foo.b = 255; | ||
| 1896 | \\ | ||
| 1897 | \\ assert(foo.first() == 10); | ||
| 1898 | \\ assert(foo.second() == 255); | ||
| 1899 | \\ | ||
| 1900 | \\ var foo2 = Foo{ .a = 15, .b = 255 }; | ||
| 1901 | \\ assert(foo2.first() == 15); | ||
| 1902 | \\ assert(foo2.second() == 255); | ||
| 1903 | \\} | ||
| 1904 | \\ | ||
| 1905 | \\fn assert(ok: bool) void { | ||
| 1906 | \\ if (!ok) unreachable; | ||
| 1907 | \\} | ||
| 1908 | , ""); | ||
| 1909 | |||
| 1910 | case.addCompareOutput( | ||
| 1911 | \\const Foo = struct { | ||
| 1912 | \\ a: u8, | ||
| 1913 | \\ b: u32, | ||
| 1914 | \\ | ||
| 1915 | \\ fn first(self: *Foo) u8 { | ||
| 1916 | \\ return self.a; | ||
| 1917 | \\ } | ||
| 1918 | \\ | ||
| 1919 | \\ fn second(self: *Foo) u32 { | ||
| 1920 | \\ return self.b; | ||
| 1921 | \\ } | ||
| 1922 | \\}; | ||
| 1923 | \\ | ||
| 1924 | \\pub fn main() void { | ||
| 1925 | \\ var foo2 = Foo{ .a = 15, .b = 255 }; | ||
| 1926 | \\ assert(foo2.first() == 15); | ||
| 1927 | \\ assert(foo2.second() == 255); | ||
| 1928 | \\} | ||
| 1929 | \\ | ||
| 1930 | \\fn assert(ok: bool) void { | ||
| 1931 | \\ if (!ok) unreachable; | ||
| 1932 | \\} | ||
| 1933 | , ""); | ||
| 1934 | } | ||
| 1847 | } | 1935 | } |
| 1848 | } | 1936 | } |
| 1849 | 1937 |