| author | |
| committer | |
| log | 90989be0e31a91335f8d1c1eafb84c3b34792a8c |
| tree | 7b3e4b1769b02db219442bd9c83d4df185848d3d |
| parent | f1eed99f3d2d355054c6cf36d6f332d83b2ec595 |
| parent | 73f385eec57d4fc28069b60f059fa8553d3a0c1b |
| signature |
elf: replace .got.zig with a zig jump table27 files changed, 488 insertions(+), 787 deletions(-)
src/Builtin.zig+1-1| ... | ... | @@ -218,7 +218,7 @@ pub fn append(opts: @This(), buffer: *std.ArrayList(u8)) Allocator.Error!void { |
| 218 | 218 | |
| 219 | 219 | if (opts.is_test) { |
| 220 | 220 | try buffer.appendSlice( |
| 221 | \\pub var test_functions: []const std.builtin.TestFn = undefined; // overwritten later | |
| 221 | \\pub var test_functions: []const std.builtin.TestFn = &.{}; // overwritten later | |
| 222 | 222 | \\ |
| 223 | 223 | ); |
| 224 | 224 | } |
src/Compilation.zig+7| ... | ... | @@ -3092,6 +3092,10 @@ pub fn totalErrorCount(comp: *Compilation) u32 { |
| 3092 | 3092 | if (zcu.intern_pool.global_error_set.getNamesFromMainThread().len > zcu.error_limit) { |
| 3093 | 3093 | total += 1; |
| 3094 | 3094 | } |
| 3095 | ||
| 3096 | for (zcu.failed_codegen.keys()) |_| { | |
| 3097 | total += 1; | |
| 3098 | } | |
| 3095 | 3099 | } |
| 3096 | 3100 | |
| 3097 | 3101 | // The "no entry point found" error only counts if there are no semantic analysis errors. |
| ... | ... | @@ -3237,6 +3241,9 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle { |
| 3237 | 3241 | } |
| 3238 | 3242 | } |
| 3239 | 3243 | } |
| 3244 | for (zcu.failed_codegen.values()) |error_msg| { | |
| 3245 | try addModuleErrorMsg(zcu, &bundle, error_msg.*, &all_references); | |
| 3246 | } | |
| 3240 | 3247 | for (zcu.failed_exports.values()) |value| { |
| 3241 | 3248 | try addModuleErrorMsg(zcu, &bundle, value.*, &all_references); |
| 3242 | 3249 | } |
src/arch/aarch64/CodeGen.zig+7-34| ... | ... | @@ -4352,24 +4352,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 4352 | 4352 | // on linking. |
| 4353 | 4353 | if (try self.air.value(callee, pt)) |func_value| switch (ip.indexToKey(func_value.toIntern())) { |
| 4354 | 4354 | .func => |func| { |
| 4355 | if (self.bin_file.cast(.elf)) |elf_file| { | |
| 4356 | const zo = elf_file.zigObjectPtr().?; | |
| 4357 | const sym_index = try zo.getOrCreateMetadataForNav(elf_file, func.owner_nav); | |
| 4358 | const sym = zo.symbol(sym_index); | |
| 4359 | _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file); | |
| 4360 | const got_addr = @as(u32, @intCast(sym.zigGotAddress(elf_file))); | |
| 4361 | try self.genSetReg(Type.usize, .x30, .{ .memory = got_addr }); | |
| 4362 | } else if (self.bin_file.cast(.macho)) |macho_file| { | |
| 4363 | _ = macho_file; | |
| 4364 | @panic("TODO airCall"); | |
| 4365 | // const atom = try macho_file.getOrCreateAtomForNav(func.owner_nav); | |
| 4366 | // const sym_index = macho_file.getAtom(atom).getSymbolIndex().?; | |
| 4367 | // try self.genSetReg(Type.u64, .x30, .{ | |
| 4368 | // .linker_load = .{ | |
| 4369 | // .type = .got, | |
| 4370 | // .sym_index = sym_index, | |
| 4371 | // }, | |
| 4372 | // }); | |
| 4355 | if (self.bin_file.cast(.elf)) |_| { | |
| 4356 | return self.fail("TODO implement calling functions for Elf", .{}); | |
| 4357 | } else if (self.bin_file.cast(.macho)) |_| { | |
| 4358 | return self.fail("TODO implement calling functions for MachO", .{}); | |
| 4373 | 4359 | } else if (self.bin_file.cast(.coff)) |coff_file| { |
| 4374 | 4360 | const atom = try coff_file.getOrCreateAtomForNav(func.owner_nav); |
| 4375 | 4361 | const sym_index = coff_file.getAtom(atom).getSymbolIndex().?; |
| ... | ... | @@ -4393,21 +4379,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 4393 | 4379 | .@"extern" => |@"extern"| { |
| 4394 | 4380 | const nav_name = ip.getNav(@"extern".owner_nav).name.toSlice(ip); |
| 4395 | 4381 | const lib_name = @"extern".lib_name.toSlice(ip); |
| 4396 | if (self.bin_file.cast(.macho)) |macho_file| { | |
| 4397 | _ = macho_file; | |
| 4398 | @panic("TODO airCall"); | |
| 4399 | // const sym_index = try macho_file.getGlobalSymbol(nav_name, lib_name); | |
| 4400 | // const atom = try macho_file.getOrCreateAtomForNav(self.owner_nav); | |
| 4401 | // const atom_index = macho_file.getAtom(atom).getSymbolIndex().?; | |
| 4402 | // _ = try self.addInst(.{ | |
| 4403 | // .tag = .call_extern, | |
| 4404 | // .data = .{ | |
| 4405 | // .relocation = .{ | |
| 4406 | // .atom_index = atom_index, | |
| 4407 | // .sym_index = sym_index, | |
| 4408 | // }, | |
| 4409 | // }, | |
| 4410 | // }); | |
| 4382 | if (self.bin_file.cast(.macho)) |_| { | |
| 4383 | return self.fail("TODO implement calling extern functions for MachO", .{}); | |
| 4411 | 4384 | } else if (self.bin_file.cast(.coff)) |coff_file| { |
| 4412 | 4385 | const sym_index = try coff_file.getGlobalSymbol(nav_name, lib_name); |
| 4413 | 4386 | try self.genSetReg(Type.u64, .x30, .{ |
| ... | ... | @@ -6234,7 +6207,7 @@ fn genTypedValue(self: *Self, val: Value) InnerError!MCValue { |
| 6234 | 6207 | .memory => |addr| .{ .memory = addr }, |
| 6235 | 6208 | .load_got => |sym_index| .{ .linker_load = .{ .type = .got, .sym_index = sym_index } }, |
| 6236 | 6209 | .load_direct => |sym_index| .{ .linker_load = .{ .type = .direct, .sym_index = sym_index } }, |
| 6237 | .load_symbol, .load_tlv => unreachable, // TODO | |
| 6210 | .load_symbol, .load_tlv, .lea_symbol => unreachable, // TODO | |
| 6238 | 6211 | }, |
| 6239 | 6212 | .fail => |msg| { |
| 6240 | 6213 | self.err_msg = msg; |
src/arch/arm/CodeGen.zig+3-17| ... | ... | @@ -4333,22 +4333,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 4333 | 4333 | // Due to incremental compilation, how function calls are generated depends |
| 4334 | 4334 | // on linking. |
| 4335 | 4335 | if (try self.air.value(callee, pt)) |func_value| switch (ip.indexToKey(func_value.toIntern())) { |
| 4336 | .func => |func| { | |
| 4337 | if (self.bin_file.cast(.elf)) |elf_file| { | |
| 4338 | const zo = elf_file.zigObjectPtr().?; | |
| 4339 | const sym_index = try zo.getOrCreateMetadataForNav(elf_file, func.owner_nav); | |
| 4340 | const sym = zo.symbol(sym_index); | |
| 4341 | _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file); | |
| 4342 | const got_addr: u32 = @intCast(sym.zigGotAddress(elf_file)); | |
| 4343 | try self.genSetReg(Type.usize, .lr, .{ .memory = got_addr }); | |
| 4344 | } else if (self.bin_file.cast(.macho)) |_| { | |
| 4345 | unreachable; // unsupported architecture for MachO | |
| 4346 | } else { | |
| 4347 | return self.fail("TODO implement call on {s} for {s}", .{ | |
| 4348 | @tagName(self.bin_file.tag), | |
| 4349 | @tagName(self.target.cpu.arch), | |
| 4350 | }); | |
| 4351 | } | |
| 4336 | .func => { | |
| 4337 | return self.fail("TODO implement calling functions", .{}); | |
| 4352 | 4338 | }, |
| 4353 | 4339 | .@"extern" => { |
| 4354 | 4340 | return self.fail("TODO implement calling extern functions", .{}); |
| ... | ... | @@ -6184,7 +6170,7 @@ fn genTypedValue(self: *Self, val: Value) InnerError!MCValue { |
| 6184 | 6170 | .mcv => |mcv| switch (mcv) { |
| 6185 | 6171 | .none => .none, |
| 6186 | 6172 | .undef => .undef, |
| 6187 | .load_got, .load_symbol, .load_direct, .load_tlv => unreachable, // TODO | |
| 6173 | .load_got, .load_symbol, .load_direct, .load_tlv, .lea_symbol => unreachable, // TODO | |
| 6188 | 6174 | .immediate => |imm| .{ .immediate = @truncate(imm) }, |
| 6189 | 6175 | .memory => |addr| .{ .memory = addr }, |
| 6190 | 6176 | }, |
src/arch/riscv64/CodeGen.zig+6-5| ... | ... | @@ -4937,7 +4937,7 @@ fn genCall( |
| 4937 | 4937 | if (func.mod.pic) { |
| 4938 | 4938 | return func.fail("TODO: genCall pic", .{}); |
| 4939 | 4939 | } else { |
| 4940 | try func.genSetReg(Type.u64, .ra, .{ .load_symbol = .{ .sym = sym_index } }); | |
| 4940 | try func.genSetReg(Type.u64, .ra, .{ .lea_symbol = .{ .sym = sym_index } }); | |
| 4941 | 4941 | _ = try func.addInst(.{ |
| 4942 | 4942 | .tag = .jalr, |
| 4943 | 4943 | .data = .{ .i_type = .{ |
| ... | ... | @@ -6120,7 +6120,7 @@ fn airAsm(func: *Func, inst: Air.Inst.Index) !void { |
| 6120 | 6120 | arg_map.get(op_str["%[".len .. mod_index orelse op_str.len - "]".len]) orelse |
| 6121 | 6121 | return func.fail("no matching constraint: '{s}'", .{op_str}) |
| 6122 | 6122 | ]) { |
| 6123 | .load_symbol => |sym_off| if (mem.eql(u8, modifier, "plt")) blk: { | |
| 6123 | .lea_symbol => |sym_off| if (mem.eql(u8, modifier, "plt")) blk: { | |
| 6124 | 6124 | assert(sym_off.off == 0); |
| 6125 | 6125 | break :blk .{ .sym = sym_off }; |
| 6126 | 6126 | } else return func.fail("invalid modifier: '{s}'", .{modifier}), |
| ... | ... | @@ -6388,7 +6388,7 @@ fn genCopy(func: *Func, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !void { |
| 6388 | 6388 | ty, |
| 6389 | 6389 | src_mcv, |
| 6390 | 6390 | ), |
| 6391 | .load_tlv => { | |
| 6391 | .load_symbol, .load_tlv => { | |
| 6392 | 6392 | const addr_reg, const addr_lock = try func.allocReg(.int); |
| 6393 | 6393 | defer func.register_manager.unlockReg(addr_lock); |
| 6394 | 6394 | |
| ... | ... | @@ -6433,7 +6433,7 @@ fn genCopy(func: *Func, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !void { |
| 6433 | 6433 | part_disp += @intCast(dst_ty.abiSize(func.pt)); |
| 6434 | 6434 | } |
| 6435 | 6435 | }, |
| 6436 | else => return func.fail("TODO: genCopy to {s} from {s}", .{ @tagName(dst_mcv), @tagName(src_mcv) }), | |
| 6436 | else => return std.debug.panic("TODO: genCopy to {s} from {s}", .{ @tagName(dst_mcv), @tagName(src_mcv) }), | |
| 6437 | 6437 | } |
| 6438 | 6438 | } |
| 6439 | 6439 | |
| ... | ... | @@ -6594,7 +6594,7 @@ fn genInlineMemset( |
| 6594 | 6594 | .tag = .beq, |
| 6595 | 6595 | .data = .{ |
| 6596 | 6596 | .b_type = .{ |
| 6597 | .inst = @intCast(func.mir_instructions.len + 4), // points after the last inst | |
| 6597 | .inst = @intCast(func.mir_instructions.len + 3), // points after the last inst | |
| 6598 | 6598 | .rs1 = count, |
| 6599 | 6599 | .rs2 = .zero, |
| 6600 | 6600 | }, |
| ... | ... | @@ -8026,6 +8026,7 @@ fn genTypedValue(func: *Func, val: Value) InnerError!MCValue { |
| 8026 | 8026 | .mcv => |mcv| switch (mcv) { |
| 8027 | 8027 | .none => .none, |
| 8028 | 8028 | .undef => unreachable, |
| 8029 | .lea_symbol => |sym_index| .{ .lea_symbol = .{ .sym = sym_index } }, | |
| 8029 | 8030 | .load_symbol => |sym_index| .{ .load_symbol = .{ .sym = sym_index } }, |
| 8030 | 8031 | .load_tlv => |sym_index| .{ .lea_tlv = sym_index }, |
| 8031 | 8032 | .immediate => |imm| .{ .immediate = imm }, |
src/arch/riscv64/Emit.zig+5-17| ... | ... | @@ -43,31 +43,19 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 43 | 43 | .fmt = std.meta.activeTag(lowered_inst), |
| 44 | 44 | }), |
| 45 | 45 | .load_symbol_reloc => |symbol| { |
| 46 | const is_obj_or_static_lib = switch (emit.lower.output_mode) { | |
| 47 | .Exe => false, | |
| 48 | .Obj => true, | |
| 49 | .Lib => emit.lower.link_mode == .static, | |
| 50 | }; | |
| 51 | ||
| 52 | 46 | const elf_file = emit.bin_file.cast(.elf).?; |
| 53 | 47 | const zo = elf_file.zigObjectPtr().?; |
| 54 | 48 | |
| 55 | 49 | const atom_ptr = zo.symbol(symbol.atom_index).atom(elf_file).?; |
| 56 | 50 | const sym = zo.symbol(symbol.sym_index); |
| 57 | 51 | |
| 58 | var hi_r_type: u32 = @intFromEnum(std.elf.R_RISCV.HI20); | |
| 59 | var lo_r_type: u32 = @intFromEnum(std.elf.R_RISCV.LO12_I); | |
| 60 | ||
| 61 | if (sym.flags.needs_zig_got and !is_obj_or_static_lib) { | |
| 62 | _ = try sym.getOrCreateZigGotEntry(symbol.sym_index, elf_file); | |
| 63 | ||
| 64 | hi_r_type = Elf.R_ZIG_GOT_HI20; | |
| 65 | lo_r_type = Elf.R_ZIG_GOT_LO12; | |
| 66 | } else if (sym.flags.needs_got) { | |
| 67 | hi_r_type = Elf.R_GOT_HI20_STATIC; // TODO: rework this #20887 | |
| 68 | lo_r_type = Elf.R_GOT_LO12_I_STATIC; // TODO: rework this #20887 | |
| 52 | if (sym.flags.is_extern_ptr and emit.lower.pic) { | |
| 53 | return emit.fail("emit GOT relocation for symbol '{s}'", .{sym.name(elf_file)}); | |
| 69 | 54 | } |
| 70 | 55 | |
| 56 | const hi_r_type: u32 = @intFromEnum(std.elf.R_RISCV.HI20); | |
| 57 | const lo_r_type: u32 = @intFromEnum(std.elf.R_RISCV.LO12_I); | |
| 58 | ||
| 71 | 59 | try atom_ptr.addReloc(elf_file, .{ |
| 72 | 60 | .r_offset = start_offset, |
| 73 | 61 | .r_info = (@as(u64, @intCast(symbol.sym_index)) << 32) | hi_r_type, |
src/arch/sparc64/CodeGen.zig+3-29| ... | ... | @@ -1349,34 +1349,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 1349 | 1349 | // Due to incremental compilation, how function calls are generated depends |
| 1350 | 1350 | // on linking. |
| 1351 | 1351 | if (try self.air.value(callee, pt)) |func_value| switch (ip.indexToKey(func_value.toIntern())) { |
| 1352 | .func => |func| { | |
| 1353 | const got_addr = if (self.bin_file.cast(.elf)) |elf_file| blk: { | |
| 1354 | const zo = elf_file.zigObjectPtr().?; | |
| 1355 | const sym_index = try zo.getOrCreateMetadataForNav(elf_file, func.owner_nav); | |
| 1356 | const sym = zo.symbol(sym_index); | |
| 1357 | _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file); | |
| 1358 | break :blk @as(u32, @intCast(sym.zigGotAddress(elf_file))); | |
| 1359 | } else @panic("TODO SPARCv9 currently does not support non-ELF binaries"); | |
| 1360 | ||
| 1361 | try self.genSetReg(Type.usize, .o7, .{ .memory = got_addr }); | |
| 1362 | ||
| 1363 | _ = try self.addInst(.{ | |
| 1364 | .tag = .jmpl, | |
| 1365 | .data = .{ | |
| 1366 | .arithmetic_3op = .{ | |
| 1367 | .is_imm = false, | |
| 1368 | .rd = .o7, | |
| 1369 | .rs1 = .o7, | |
| 1370 | .rs2_or_imm = .{ .rs2 = .g0 }, | |
| 1371 | }, | |
| 1372 | }, | |
| 1373 | }); | |
| 1374 | ||
| 1375 | // TODO Find a way to fill this delay slot | |
| 1376 | _ = try self.addInst(.{ | |
| 1377 | .tag = .nop, | |
| 1378 | .data = .{ .nop = {} }, | |
| 1379 | }); | |
| 1352 | .func => { | |
| 1353 | return self.fail("TODO implement calling functions", .{}); | |
| 1380 | 1354 | }, |
| 1381 | 1355 | .@"extern" => { |
| 1382 | 1356 | return self.fail("TODO implement calling extern functions", .{}); |
| ... | ... | @@ -4153,7 +4127,7 @@ fn genTypedValue(self: *Self, val: Value) InnerError!MCValue { |
| 4153 | 4127 | .mcv => |mcv| switch (mcv) { |
| 4154 | 4128 | .none => .none, |
| 4155 | 4129 | .undef => .undef, |
| 4156 | .load_got, .load_symbol, .load_direct, .load_tlv => unreachable, // TODO | |
| 4130 | .load_got, .load_symbol, .load_direct, .load_tlv, .lea_symbol => unreachable, // TODO | |
| 4157 | 4131 | .immediate => |imm| .{ .immediate = imm }, |
| 4158 | 4132 | .memory => |addr| .{ .memory = addr }, |
| 4159 | 4133 | }, |
src/arch/x86_64/CodeGen.zig+52-53| ... | ... | @@ -1379,14 +1379,22 @@ fn asmImmediate(self: *Self, tag: Mir.Inst.FixedTag, imm: Immediate) !void { |
| 1379 | 1379 | .ops = switch (imm) { |
| 1380 | 1380 | .signed => .i_s, |
| 1381 | 1381 | .unsigned => .i_u, |
| 1382 | .reloc => .rel, | |
| 1382 | 1383 | }, |
| 1383 | .data = .{ .i = .{ | |
| 1384 | .fixes = tag[0], | |
| 1385 | .i = switch (imm) { | |
| 1386 | .signed => |s| @bitCast(s), | |
| 1387 | .unsigned => |u| @intCast(u), | |
| 1384 | .data = switch (imm) { | |
| 1385 | .reloc => |x| reloc: { | |
| 1386 | assert(tag[0] == ._); | |
| 1387 | break :reloc .{ .reloc = x }; | |
| 1388 | 1388 | }, |
| 1389 | } }, | |
| 1389 | .signed, .unsigned => .{ .i = .{ | |
| 1390 | .fixes = tag[0], | |
| 1391 | .i = switch (imm) { | |
| 1392 | .signed => |s| @bitCast(s), | |
| 1393 | .unsigned => |u| @intCast(u), | |
| 1394 | .reloc => unreachable, | |
| 1395 | }, | |
| 1396 | } }, | |
| 1397 | }, | |
| 1390 | 1398 | }); |
| 1391 | 1399 | } |
| 1392 | 1400 | |
| ... | ... | @@ -1406,6 +1414,7 @@ fn asmRegisterImmediate(self: *Self, tag: Mir.Inst.FixedTag, reg: Register, imm: |
| 1406 | 1414 | const ops: Mir.Inst.Ops = switch (imm) { |
| 1407 | 1415 | .signed => .ri_s, |
| 1408 | 1416 | .unsigned => |u| if (math.cast(u32, u)) |_| .ri_u else .ri64, |
| 1417 | .reloc => unreachable, | |
| 1409 | 1418 | }; |
| 1410 | 1419 | _ = try self.addInst(.{ |
| 1411 | 1420 | .tag = tag[1], |
| ... | ... | @@ -1417,6 +1426,7 @@ fn asmRegisterImmediate(self: *Self, tag: Mir.Inst.FixedTag, reg: Register, imm: |
| 1417 | 1426 | .i = switch (imm) { |
| 1418 | 1427 | .signed => |s| @bitCast(s), |
| 1419 | 1428 | .unsigned => |u| @intCast(u), |
| 1429 | .reloc => unreachable, | |
| 1420 | 1430 | }, |
| 1421 | 1431 | } }, |
| 1422 | 1432 | .ri64 => .{ .rx = .{ |
| ... | ... | @@ -1488,6 +1498,7 @@ fn asmRegisterRegisterRegisterImmediate( |
| 1488 | 1498 | .i = switch (imm) { |
| 1489 | 1499 | .signed => |s| @bitCast(@as(i8, @intCast(s))), |
| 1490 | 1500 | .unsigned => |u| @intCast(u), |
| 1501 | .reloc => unreachable, | |
| 1491 | 1502 | }, |
| 1492 | 1503 | } }, |
| 1493 | 1504 | }); |
| ... | ... | @@ -1505,6 +1516,7 @@ fn asmRegisterRegisterImmediate( |
| 1505 | 1516 | .ops = switch (imm) { |
| 1506 | 1517 | .signed => .rri_s, |
| 1507 | 1518 | .unsigned => .rri_u, |
| 1519 | .reloc => unreachable, | |
| 1508 | 1520 | }, |
| 1509 | 1521 | .data = .{ .rri = .{ |
| 1510 | 1522 | .fixes = tag[0], |
| ... | ... | @@ -1513,6 +1525,7 @@ fn asmRegisterRegisterImmediate( |
| 1513 | 1525 | .i = switch (imm) { |
| 1514 | 1526 | .signed => |s| @bitCast(s), |
| 1515 | 1527 | .unsigned => |u| @intCast(u), |
| 1528 | .reloc => unreachable, | |
| 1516 | 1529 | }, |
| 1517 | 1530 | } }, |
| 1518 | 1531 | }); |
| ... | ... | @@ -1610,6 +1623,7 @@ fn asmRegisterMemoryImmediate( |
| 1610 | 1623 | if (switch (imm) { |
| 1611 | 1624 | .signed => |s| if (math.cast(i16, s)) |x| @as(u16, @bitCast(x)) else null, |
| 1612 | 1625 | .unsigned => |u| math.cast(u16, u), |
| 1626 | .reloc => unreachable, | |
| 1613 | 1627 | }) |small_imm| { |
| 1614 | 1628 | _ = try self.addInst(.{ |
| 1615 | 1629 | .tag = tag[1], |
| ... | ... | @@ -1625,6 +1639,7 @@ fn asmRegisterMemoryImmediate( |
| 1625 | 1639 | const payload = try self.addExtra(Mir.Imm32{ .imm = switch (imm) { |
| 1626 | 1640 | .signed => |s| @bitCast(s), |
| 1627 | 1641 | .unsigned => unreachable, |
| 1642 | .reloc => unreachable, | |
| 1628 | 1643 | } }); |
| 1629 | 1644 | assert(payload + 1 == try self.addExtra(Mir.Memory.encode(m))); |
| 1630 | 1645 | _ = try self.addInst(.{ |
| ... | ... | @@ -1632,6 +1647,7 @@ fn asmRegisterMemoryImmediate( |
| 1632 | 1647 | .ops = switch (imm) { |
| 1633 | 1648 | .signed => .rmi_s, |
| 1634 | 1649 | .unsigned => .rmi_u, |
| 1650 | .reloc => unreachable, | |
| 1635 | 1651 | }, |
| 1636 | 1652 | .data = .{ .rx = .{ |
| 1637 | 1653 | .fixes = tag[0], |
| ... | ... | @@ -1679,6 +1695,7 @@ fn asmMemoryImmediate(self: *Self, tag: Mir.Inst.FixedTag, m: Memory, imm: Immed |
| 1679 | 1695 | const payload = try self.addExtra(Mir.Imm32{ .imm = switch (imm) { |
| 1680 | 1696 | .signed => |s| @bitCast(s), |
| 1681 | 1697 | .unsigned => |u| @intCast(u), |
| 1698 | .reloc => unreachable, | |
| 1682 | 1699 | } }); |
| 1683 | 1700 | assert(payload + 1 == try self.addExtra(Mir.Memory.encode(m))); |
| 1684 | 1701 | _ = try self.addInst(.{ |
| ... | ... | @@ -1686,6 +1703,7 @@ fn asmMemoryImmediate(self: *Self, tag: Mir.Inst.FixedTag, m: Memory, imm: Immed |
| 1686 | 1703 | .ops = switch (imm) { |
| 1687 | 1704 | .signed => .mi_s, |
| 1688 | 1705 | .unsigned => .mi_u, |
| 1706 | .reloc => unreachable, | |
| 1689 | 1707 | }, |
| 1690 | 1708 | .data = .{ .x = .{ |
| 1691 | 1709 | .fixes = tag[0], |
| ... | ... | @@ -12310,33 +12328,10 @@ fn genCall(self: *Self, info: union(enum) { |
| 12310 | 12328 | if (self.bin_file.cast(.elf)) |elf_file| { |
| 12311 | 12329 | const zo = elf_file.zigObjectPtr().?; |
| 12312 | 12330 | const sym_index = try zo.getOrCreateMetadataForNav(elf_file, func.owner_nav); |
| 12313 | if (self.mod.pic) { | |
| 12314 | const callee_reg: Register = switch (resolved_cc) { | |
| 12315 | .SysV => callee: { | |
| 12316 | if (!fn_info.is_var_args) break :callee .rax; | |
| 12317 | const param_regs = abi.getCAbiIntParamRegs(resolved_cc); | |
| 12318 | break :callee if (call_info.gp_count < param_regs.len) | |
| 12319 | param_regs[call_info.gp_count] | |
| 12320 | else | |
| 12321 | .r10; | |
| 12322 | }, | |
| 12323 | .Win64 => .rax, | |
| 12324 | else => unreachable, | |
| 12325 | }; | |
| 12326 | try self.genSetReg( | |
| 12327 | callee_reg, | |
| 12328 | Type.usize, | |
| 12329 | .{ .load_symbol = .{ .sym = sym_index } }, | |
| 12330 | .{}, | |
| 12331 | ); | |
| 12332 | try self.asmRegister(.{ ._, .call }, callee_reg); | |
| 12333 | } else try self.asmMemory(.{ ._, .call }, .{ | |
| 12334 | .base = .{ .reloc = .{ | |
| 12335 | .atom_index = try self.owner.getSymbolIndex(self), | |
| 12336 | .sym_index = sym_index, | |
| 12337 | } }, | |
| 12338 | .mod = .{ .rm = .{ .size = .qword } }, | |
| 12339 | }); | |
| 12331 | try self.asmImmediate(.{ ._, .call }, Immediate.rel(.{ | |
| 12332 | .atom_index = try self.owner.getSymbolIndex(self), | |
| 12333 | .sym_index = sym_index, | |
| 12334 | })); | |
| 12340 | 12335 | } else if (self.bin_file.cast(.coff)) |coff_file| { |
| 12341 | 12336 | const atom = try coff_file.getOrCreateAtomForNav(func.owner_nav); |
| 12342 | 12337 | const sym_index = coff_file.getAtom(atom).getSymbolIndex().?; |
| ... | ... | @@ -12365,7 +12360,16 @@ fn genCall(self: *Self, info: union(enum) { |
| 12365 | 12360 | }); |
| 12366 | 12361 | } else unreachable; |
| 12367 | 12362 | }, |
| 12368 | .@"extern" => |@"extern"| try self.genExternSymbolRef( | |
| 12363 | .@"extern" => |@"extern"| if (self.bin_file.cast(.elf)) |elf_file| { | |
| 12364 | const target_sym_index = try elf_file.getGlobalSymbol( | |
| 12365 | @"extern".name.toSlice(ip), | |
| 12366 | @"extern".lib_name.toSlice(ip), | |
| 12367 | ); | |
| 12368 | try self.asmImmediate(.{ ._, .call }, Immediate.rel(.{ | |
| 12369 | .atom_index = try self.owner.getSymbolIndex(self), | |
| 12370 | .sym_index = target_sym_index, | |
| 12371 | })); | |
| 12372 | } else try self.genExternSymbolRef( | |
| 12369 | 12373 | .call, |
| 12370 | 12374 | @"extern".lib_name.toSlice(ip), |
| 12371 | 12375 | @"extern".name.toSlice(ip), |
| ... | ... | @@ -12377,7 +12381,13 @@ fn genCall(self: *Self, info: union(enum) { |
| 12377 | 12381 | try self.genSetReg(.rax, Type.usize, .{ .air_ref = callee }, .{}); |
| 12378 | 12382 | try self.asmRegister(.{ ._, .call }, .rax); |
| 12379 | 12383 | }, |
| 12380 | .lib => |lib| try self.genExternSymbolRef(.call, lib.lib, lib.callee), | |
| 12384 | .lib => |lib| if (self.bin_file.cast(.elf)) |elf_file| { | |
| 12385 | const target_sym_index = try elf_file.getGlobalSymbol(lib.callee, lib.lib); | |
| 12386 | try self.asmImmediate(.{ ._, .call }, Immediate.rel(.{ | |
| 12387 | .atom_index = try self.owner.getSymbolIndex(self), | |
| 12388 | .sym_index = target_sym_index, | |
| 12389 | })); | |
| 12390 | } else try self.genExternSymbolRef(.call, lib.lib, lib.callee), | |
| 12381 | 12391 | } |
| 12382 | 12392 | return call_info.return_value.short; |
| 12383 | 12393 | } |
| ... | ... | @@ -14096,8 +14106,8 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 14096 | 14106 | .{ .reg = try self.copyToTmpRegister(Type.usize, .{ .lea_got = sym_index }) } |
| 14097 | 14107 | else |
| 14098 | 14108 | return self.fail("invalid modifier: '{s}'", .{modifier}), |
| 14099 | .load_symbol => |sym_off| if (mem.eql(u8, modifier, "P")) | |
| 14100 | .{ .reg = try self.copyToTmpRegister(Type.usize, .{ .load_symbol = sym_off }) } | |
| 14109 | .lea_symbol => |sym_off| if (mem.eql(u8, modifier, "P")) | |
| 14110 | .{ .reg = try self.copyToTmpRegister(Type.usize, .{ .lea_symbol = sym_off }) } | |
| 14101 | 14111 | else |
| 14102 | 14112 | return self.fail("invalid modifier: '{s}'", .{modifier}), |
| 14103 | 14113 | else => return self.fail("invalid constraint: '{s}'", .{op_str}), |
| ... | ... | @@ -15253,16 +15263,7 @@ fn genExternSymbolRef( |
| 15253 | 15263 | callee: []const u8, |
| 15254 | 15264 | ) InnerError!void { |
| 15255 | 15265 | const atom_index = try self.owner.getSymbolIndex(self); |
| 15256 | if (self.bin_file.cast(.elf)) |elf_file| { | |
| 15257 | _ = try self.addInst(.{ | |
| 15258 | .tag = tag, | |
| 15259 | .ops = .extern_fn_reloc, | |
| 15260 | .data = .{ .reloc = .{ | |
| 15261 | .atom_index = atom_index, | |
| 15262 | .sym_index = try elf_file.getGlobalSymbol(callee, lib), | |
| 15263 | } }, | |
| 15264 | }); | |
| 15265 | } else if (self.bin_file.cast(.coff)) |coff_file| { | |
| 15266 | if (self.bin_file.cast(.coff)) |coff_file| { | |
| 15266 | 15267 | const global_index = try coff_file.getGlobalSymbol(callee, lib); |
| 15267 | 15268 | _ = try self.addInst(.{ |
| 15268 | 15269 | .tag = .mov, |
| ... | ... | @@ -15306,7 +15307,7 @@ fn genLazySymbolRef( |
| 15306 | 15307 | if (self.mod.pic) { |
| 15307 | 15308 | switch (tag) { |
| 15308 | 15309 | .lea, .call => try self.genSetReg(reg, Type.usize, .{ |
| 15309 | .load_symbol = .{ .sym = sym_index }, | |
| 15310 | .lea_symbol = .{ .sym = sym_index }, | |
| 15310 | 15311 | }, .{}), |
| 15311 | 15312 | .mov => try self.genSetReg(reg, Type.usize, .{ |
| 15312 | 15313 | .load_symbol = .{ .sym = sym_index }, |
| ... | ... | @@ -15324,14 +15325,11 @@ fn genLazySymbolRef( |
| 15324 | 15325 | .sym_index = sym_index, |
| 15325 | 15326 | }; |
| 15326 | 15327 | switch (tag) { |
| 15327 | .lea, .mov => try self.asmRegisterMemory(.{ ._, .mov }, reg.to64(), .{ | |
| 15328 | .base = .{ .reloc = reloc }, | |
| 15329 | .mod = .{ .rm = .{ .size = .qword } }, | |
| 15330 | }), | |
| 15331 | .call => try self.asmMemory(.{ ._, .call }, .{ | |
| 15328 | .lea, .mov => try self.asmRegisterMemory(.{ ._, tag }, reg.to64(), .{ | |
| 15332 | 15329 | .base = .{ .reloc = reloc }, |
| 15333 | 15330 | .mod = .{ .rm = .{ .size = .qword } }, |
| 15334 | 15331 | }), |
| 15332 | .call => try self.asmImmediate(.{ ._, .call }, Immediate.rel(reloc)), | |
| 15335 | 15333 | else => unreachable, |
| 15336 | 15334 | } |
| 15337 | 15335 | } |
| ... | ... | @@ -18790,6 +18788,7 @@ fn genTypedValue(self: *Self, val: Value) InnerError!MCValue { |
| 18790 | 18788 | .immediate => |imm| .{ .immediate = imm }, |
| 18791 | 18789 | .memory => |addr| .{ .memory = addr }, |
| 18792 | 18790 | .load_symbol => |sym_index| .{ .load_symbol = .{ .sym = sym_index } }, |
| 18791 | .lea_symbol => |sym_index| .{ .lea_symbol = .{ .sym = sym_index } }, | |
| 18793 | 18792 | .load_direct => |sym_index| .{ .load_direct = sym_index }, |
| 18794 | 18793 | .load_got => |sym_index| .{ .lea_got = sym_index }, |
| 18795 | 18794 | .load_tlv => |sym_index| .{ .lea_tlv = sym_index }, |
src/arch/x86_64/Disassembler.zig+1-1| ... | ... | @@ -8,7 +8,7 @@ const bits = @import("bits.zig"); |
| 8 | 8 | const encoder = @import("encoder.zig"); |
| 9 | 9 | |
| 10 | 10 | const Encoding = @import("Encoding.zig"); |
| 11 | const Immediate = bits.Immediate; | |
| 11 | const Immediate = Instruction.Immediate; | |
| 12 | 12 | const Instruction = encoder.Instruction; |
| 13 | 13 | const LegacyPrefixes = encoder.LegacyPrefixes; |
| 14 | 14 | const Memory = Instruction.Memory; |
src/arch/x86_64/Emit.zig+10-33| ... | ... | @@ -110,21 +110,11 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 110 | 110 | }); |
| 111 | 111 | }, |
| 112 | 112 | .linker_reloc => |data| if (emit.lower.bin_file.cast(.elf)) |elf_file| { |
| 113 | const is_obj_or_static_lib = switch (emit.lower.output_mode) { | |
| 114 | .Exe => false, | |
| 115 | .Obj => true, | |
| 116 | .Lib => emit.lower.link_mode == .static, | |
| 117 | }; | |
| 118 | 113 | const zo = elf_file.zigObjectPtr().?; |
| 119 | 114 | const atom = zo.symbol(data.atom_index).atom(elf_file).?; |
| 120 | 115 | const sym = zo.symbol(data.sym_index); |
| 121 | if (sym.flags.needs_zig_got and !is_obj_or_static_lib) { | |
| 122 | _ = try sym.getOrCreateZigGotEntry(data.sym_index, elf_file); | |
| 123 | } | |
| 124 | 116 | if (emit.lower.pic) { |
| 125 | const r_type: u32 = if (sym.flags.needs_zig_got and !is_obj_or_static_lib) | |
| 126 | link.File.Elf.R_ZIG_GOTPCREL | |
| 127 | else if (sym.flags.needs_got) | |
| 117 | const r_type: u32 = if (sym.flags.is_extern_ptr) | |
| 128 | 118 | @intFromEnum(std.elf.R_X86_64.GOTPCREL) |
| 129 | 119 | else |
| 130 | 120 | @intFromEnum(std.elf.R_X86_64.PC32); |
| ... | ... | @@ -134,28 +124,15 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 134 | 124 | .r_addend = -4, |
| 135 | 125 | }); |
| 136 | 126 | } else { |
| 137 | if (lowered_inst.encoding.mnemonic == .call and sym.flags.needs_zig_got and is_obj_or_static_lib) { | |
| 138 | const r_type = @intFromEnum(std.elf.R_X86_64.PC32); | |
| 139 | try atom.addReloc(elf_file, .{ | |
| 140 | .r_offset = end_offset - 4, | |
| 141 | .r_info = (@as(u64, @intCast(data.sym_index)) << 32) | r_type, | |
| 142 | .r_addend = -4, | |
| 143 | }); | |
| 144 | } else { | |
| 145 | const r_type: u32 = if (sym.flags.needs_zig_got and !is_obj_or_static_lib) | |
| 146 | link.File.Elf.R_ZIG_GOT32 | |
| 147 | else if (sym.flags.needs_got) | |
| 148 | @intFromEnum(std.elf.R_X86_64.GOT32) | |
| 149 | else if (sym.flags.is_tls) | |
| 150 | @intFromEnum(std.elf.R_X86_64.TPOFF32) | |
| 151 | else | |
| 152 | @intFromEnum(std.elf.R_X86_64.@"32"); | |
| 153 | try atom.addReloc(elf_file, .{ | |
| 154 | .r_offset = end_offset - 4, | |
| 155 | .r_info = (@as(u64, @intCast(data.sym_index)) << 32) | r_type, | |
| 156 | .r_addend = 0, | |
| 157 | }); | |
| 158 | } | |
| 127 | const r_type: u32 = if (sym.flags.is_tls) | |
| 128 | @intFromEnum(std.elf.R_X86_64.TPOFF32) | |
| 129 | else | |
| 130 | @intFromEnum(std.elf.R_X86_64.@"32"); | |
| 131 | try atom.addReloc(elf_file, .{ | |
| 132 | .r_offset = end_offset - 4, | |
| 133 | .r_info = (@as(u64, @intCast(data.sym_index)) << 32) | r_type, | |
| 134 | .r_addend = 0, | |
| 135 | }); | |
| 159 | 136 | } |
| 160 | 137 | } else if (emit.lower.bin_file.cast(.macho)) |macho_file| { |
| 161 | 138 | const is_obj_or_static_lib = switch (emit.lower.output_mode) { |
src/arch/x86_64/Lower.zig+22-15| ... | ... | @@ -397,33 +397,40 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) |
| 397 | 397 | } |
| 398 | 398 | |
| 399 | 399 | _ = lower.reloc(.{ .linker_reloc = sym }); |
| 400 | break :op if (lower.pic) switch (mnemonic) { | |
| 400 | if (lower.pic) switch (mnemonic) { | |
| 401 | 401 | .lea => { |
| 402 | if (elf_sym.flags.is_extern_ptr) emit_mnemonic = .mov; | |
| 402 | 403 | break :op .{ .mem = Memory.rip(mem_op.sib.ptr_size, 0) }; |
| 403 | 404 | }, |
| 404 | 405 | .mov => { |
| 405 | if (is_obj_or_static_lib and elf_sym.flags.needs_zig_got) emit_mnemonic = .lea; | |
| 406 | if (elf_sym.flags.is_extern_ptr) { | |
| 407 | const reg = ops[0].reg; | |
| 408 | lower.result_insts[lower.result_insts_len] = | |
| 409 | try Instruction.new(.none, .mov, &[_]Operand{ | |
| 410 | .{ .reg = reg.to64() }, | |
| 411 | .{ .mem = Memory.rip(.qword, 0) }, | |
| 412 | }); | |
| 413 | lower.result_insts_len += 1; | |
| 414 | break :op .{ .mem = Memory.sib(mem_op.sib.ptr_size, .{ .base = .{ | |
| 415 | .reg = reg.to64(), | |
| 416 | } }) }; | |
| 417 | } | |
| 406 | 418 | break :op .{ .mem = Memory.rip(mem_op.sib.ptr_size, 0) }; |
| 407 | 419 | }, |
| 408 | 420 | else => unreachable, |
| 409 | 421 | } else switch (mnemonic) { |
| 410 | .call => break :op if (is_obj_or_static_lib and elf_sym.flags.needs_zig_got) .{ | |
| 411 | .imm = Immediate.s(0), | |
| 412 | } else .{ .mem = Memory.sib(mem_op.sib.ptr_size, .{ | |
| 422 | .call => break :op .{ .mem = Memory.sib(mem_op.sib.ptr_size, .{ | |
| 413 | 423 | .base = .{ .reg = .ds }, |
| 414 | 424 | }) }, |
| 415 | 425 | .lea => { |
| 416 | 426 | emit_mnemonic = .mov; |
| 417 | 427 | break :op .{ .imm = Immediate.s(0) }; |
| 418 | 428 | }, |
| 419 | .mov => { | |
| 420 | if (is_obj_or_static_lib and elf_sym.flags.needs_zig_got) emit_mnemonic = .lea; | |
| 421 | break :op .{ .mem = Memory.sib(mem_op.sib.ptr_size, .{ | |
| 422 | .base = .{ .reg = .ds }, | |
| 423 | }) }; | |
| 424 | }, | |
| 429 | .mov => break :op .{ .mem = Memory.sib(mem_op.sib.ptr_size, .{ | |
| 430 | .base = .{ .reg = .ds }, | |
| 431 | }) }, | |
| 425 | 432 | else => unreachable, |
| 426 | }; | |
| 433 | } | |
| 427 | 434 | } else if (lower.bin_file.cast(.macho)) |macho_file| { |
| 428 | 435 | const zo = macho_file.getZigObject().?; |
| 429 | 436 | const macho_sym = zo.symbols.items[sym.sym_index]; |
| ... | ... | @@ -485,7 +492,7 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void { |
| 485 | 492 | .rrmi => inst.data.rrix.fixes, |
| 486 | 493 | .mi_u, .mi_s => inst.data.x.fixes, |
| 487 | 494 | .m => inst.data.x.fixes, |
| 488 | .extern_fn_reloc, .got_reloc, .direct_reloc, .import_reloc, .tlv_reloc => ._, | |
| 495 | .extern_fn_reloc, .got_reloc, .direct_reloc, .import_reloc, .tlv_reloc, .rel => ._, | |
| 489 | 496 | else => return lower.fail("TODO lower .{s}", .{@tagName(inst.ops)}), |
| 490 | 497 | }; |
| 491 | 498 | try lower.emit(switch (fixes) { |
| ... | ... | @@ -617,7 +624,7 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void { |
| 617 | 624 | .{ .mem = lower.mem(inst.data.rrix.payload) }, |
| 618 | 625 | .{ .imm = lower.imm(inst.ops, inst.data.rrix.i) }, |
| 619 | 626 | }, |
| 620 | .extern_fn_reloc => &.{ | |
| 627 | .extern_fn_reloc, .rel => &.{ | |
| 621 | 628 | .{ .imm = lower.reloc(.{ .linker_extern_fn = inst.data.reloc }) }, |
| 622 | 629 | }, |
| 623 | 630 | .got_reloc, .direct_reloc, .import_reloc => ops: { |
| ... | ... | @@ -660,7 +667,7 @@ const std = @import("std"); |
| 660 | 667 | const Air = @import("../../Air.zig"); |
| 661 | 668 | const Allocator = std.mem.Allocator; |
| 662 | 669 | const ErrorMsg = Zcu.ErrorMsg; |
| 663 | const Immediate = bits.Immediate; | |
| 670 | const Immediate = Instruction.Immediate; | |
| 664 | 671 | const Instruction = encoder.Instruction; |
| 665 | 672 | const Lower = @This(); |
| 666 | 673 | const Memory = Instruction.Memory; |
src/arch/x86_64/Mir.zig+1-1| ... | ... | @@ -769,7 +769,7 @@ pub const Inst = struct { |
| 769 | 769 | /// Uses `imm` payload. |
| 770 | 770 | i_u, |
| 771 | 771 | /// Relative displacement operand. |
| 772 | /// Uses `imm` payload. | |
| 772 | /// Uses `reloc` payload. | |
| 773 | 773 | rel, |
| 774 | 774 | /// Register, memory operands. |
| 775 | 775 | /// Uses `rx` payload with extra data of type `Memory`. |
src/arch/x86_64/bits.zig+13-32| ... | ... | @@ -569,6 +569,7 @@ pub const Memory = struct { |
| 569 | 569 | pub const Immediate = union(enum) { |
| 570 | 570 | signed: i32, |
| 571 | 571 | unsigned: u64, |
| 572 | reloc: Symbol, | |
| 572 | 573 | |
| 573 | 574 | pub fn u(x: u64) Immediate { |
| 574 | 575 | return .{ .unsigned = x }; |
| ... | ... | @@ -578,39 +579,19 @@ pub const Immediate = union(enum) { |
| 578 | 579 | return .{ .signed = x }; |
| 579 | 580 | } |
| 580 | 581 | |
| 581 | pub fn asSigned(imm: Immediate, bit_size: u64) i64 { | |
| 582 | return switch (imm) { | |
| 583 | .signed => |x| switch (bit_size) { | |
| 584 | 1, 8 => @as(i8, @intCast(x)), | |
| 585 | 16 => @as(i16, @intCast(x)), | |
| 586 | 32, 64 => x, | |
| 587 | else => unreachable, | |
| 588 | }, | |
| 589 | .unsigned => |x| switch (bit_size) { | |
| 590 | 1, 8 => @as(i8, @bitCast(@as(u8, @intCast(x)))), | |
| 591 | 16 => @as(i16, @bitCast(@as(u16, @intCast(x)))), | |
| 592 | 32 => @as(i32, @bitCast(@as(u32, @intCast(x)))), | |
| 593 | 64 => @bitCast(x), | |
| 594 | else => unreachable, | |
| 595 | }, | |
| 596 | }; | |
| 582 | pub fn rel(symbol: Symbol) Immediate { | |
| 583 | return .{ .reloc = symbol }; | |
| 597 | 584 | } |
| 598 | 585 | |
| 599 | pub fn asUnsigned(imm: Immediate, bit_size: u64) u64 { | |
| 600 | return switch (imm) { | |
| 601 | .signed => |x| switch (bit_size) { | |
| 602 | 1, 8 => @as(u8, @bitCast(@as(i8, @intCast(x)))), | |
| 603 | 16 => @as(u16, @bitCast(@as(i16, @intCast(x)))), | |
| 604 | 32, 64 => @as(u32, @bitCast(x)), | |
| 605 | else => unreachable, | |
| 606 | }, | |
| 607 | .unsigned => |x| switch (bit_size) { | |
| 608 | 1, 8 => @as(u8, @intCast(x)), | |
| 609 | 16 => @as(u16, @intCast(x)), | |
| 610 | 32 => @as(u32, @intCast(x)), | |
| 611 | 64 => x, | |
| 612 | else => unreachable, | |
| 613 | }, | |
| 614 | }; | |
| 586 | pub fn format( | |
| 587 | imm: Immediate, | |
| 588 | comptime fmt: []const u8, | |
| 589 | options: std.fmt.FormatOptions, | |
| 590 | writer: anytype, | |
| 591 | ) @TypeOf(writer).Error!void { | |
| 592 | switch (imm) { | |
| 593 | .reloc => |x| try std.fmt.formatType(x, fmt, options, writer, 0), | |
| 594 | inline else => |x| try writer.print("{d}", .{x}), | |
| 595 | } | |
| 615 | 596 | } |
| 616 | 597 | }; |
src/arch/x86_64/encoder.zig+91-43| ... | ... | @@ -7,7 +7,6 @@ const testing = std.testing; |
| 7 | 7 | const bits = @import("bits.zig"); |
| 8 | 8 | const Encoding = @import("Encoding.zig"); |
| 9 | 9 | const FrameIndex = bits.FrameIndex; |
| 10 | const Immediate = bits.Immediate; | |
| 11 | 10 | const Register = bits.Register; |
| 12 | 11 | const Symbol = bits.Symbol; |
| 13 | 12 | |
| ... | ... | @@ -28,6 +27,55 @@ pub const Instruction = struct { |
| 28 | 27 | repnz, |
| 29 | 28 | }; |
| 30 | 29 | |
| 30 | pub const Immediate = union(enum) { | |
| 31 | signed: i32, | |
| 32 | unsigned: u64, | |
| 33 | ||
| 34 | pub fn u(x: u64) Immediate { | |
| 35 | return .{ .unsigned = x }; | |
| 36 | } | |
| 37 | ||
| 38 | pub fn s(x: i32) Immediate { | |
| 39 | return .{ .signed = x }; | |
| 40 | } | |
| 41 | ||
| 42 | pub fn asSigned(imm: Immediate, bit_size: u64) i64 { | |
| 43 | return switch (imm) { | |
| 44 | .signed => |x| switch (bit_size) { | |
| 45 | 1, 8 => @as(i8, @intCast(x)), | |
| 46 | 16 => @as(i16, @intCast(x)), | |
| 47 | 32, 64 => x, | |
| 48 | else => unreachable, | |
| 49 | }, | |
| 50 | .unsigned => |x| switch (bit_size) { | |
| 51 | 1, 8 => @as(i8, @bitCast(@as(u8, @intCast(x)))), | |
| 52 | 16 => @as(i16, @bitCast(@as(u16, @intCast(x)))), | |
| 53 | 32 => @as(i32, @bitCast(@as(u32, @intCast(x)))), | |
| 54 | 64 => @bitCast(x), | |
| 55 | else => unreachable, | |
| 56 | }, | |
| 57 | }; | |
| 58 | } | |
| 59 | ||
| 60 | pub fn asUnsigned(imm: Immediate, bit_size: u64) u64 { | |
| 61 | return switch (imm) { | |
| 62 | .signed => |x| switch (bit_size) { | |
| 63 | 1, 8 => @as(u8, @bitCast(@as(i8, @intCast(x)))), | |
| 64 | 16 => @as(u16, @bitCast(@as(i16, @intCast(x)))), | |
| 65 | 32, 64 => @as(u32, @bitCast(x)), | |
| 66 | else => unreachable, | |
| 67 | }, | |
| 68 | .unsigned => |x| switch (bit_size) { | |
| 69 | 1, 8 => @as(u8, @intCast(x)), | |
| 70 | 16 => @as(u16, @intCast(x)), | |
| 71 | 32 => @as(u32, @intCast(x)), | |
| 72 | 64 => x, | |
| 73 | else => unreachable, | |
| 74 | }, | |
| 75 | }; | |
| 76 | } | |
| 77 | }; | |
| 78 | ||
| 31 | 79 | pub const Memory = union(enum) { |
| 32 | 80 | sib: Sib, |
| 33 | 81 | rip: Rip, |
| ... | ... | @@ -1119,7 +1167,7 @@ test "encode" { |
| 1119 | 1167 | |
| 1120 | 1168 | const inst = try Instruction.new(.none, .mov, &.{ |
| 1121 | 1169 | .{ .reg = .rbx }, |
| 1122 | .{ .imm = Immediate.u(4) }, | |
| 1170 | .{ .imm = Instruction.Immediate.u(4) }, | |
| 1123 | 1171 | }); |
| 1124 | 1172 | try inst.encode(buf.writer(), .{}); |
| 1125 | 1173 | try testing.expectEqualSlices(u8, &.{ 0x48, 0xc7, 0xc3, 0x4, 0x0, 0x0, 0x0 }, buf.items); |
| ... | ... | @@ -1129,47 +1177,47 @@ test "lower I encoding" { |
| 1129 | 1177 | var enc = TestEncode{}; |
| 1130 | 1178 | |
| 1131 | 1179 | try enc.encode(.push, &.{ |
| 1132 | .{ .imm = Immediate.u(0x10) }, | |
| 1180 | .{ .imm = Instruction.Immediate.u(0x10) }, | |
| 1133 | 1181 | }); |
| 1134 | 1182 | try expectEqualHexStrings("\x6A\x10", enc.code(), "push 0x10"); |
| 1135 | 1183 | |
| 1136 | 1184 | try enc.encode(.push, &.{ |
| 1137 | .{ .imm = Immediate.u(0x1000) }, | |
| 1185 | .{ .imm = Instruction.Immediate.u(0x1000) }, | |
| 1138 | 1186 | }); |
| 1139 | 1187 | try expectEqualHexStrings("\x66\x68\x00\x10", enc.code(), "push 0x1000"); |
| 1140 | 1188 | |
| 1141 | 1189 | try enc.encode(.push, &.{ |
| 1142 | .{ .imm = Immediate.u(0x10000000) }, | |
| 1190 | .{ .imm = Instruction.Immediate.u(0x10000000) }, | |
| 1143 | 1191 | }); |
| 1144 | 1192 | try expectEqualHexStrings("\x68\x00\x00\x00\x10", enc.code(), "push 0x10000000"); |
| 1145 | 1193 | |
| 1146 | 1194 | try enc.encode(.adc, &.{ |
| 1147 | 1195 | .{ .reg = .rax }, |
| 1148 | .{ .imm = Immediate.u(0x10000000) }, | |
| 1196 | .{ .imm = Instruction.Immediate.u(0x10000000) }, | |
| 1149 | 1197 | }); |
| 1150 | 1198 | try expectEqualHexStrings("\x48\x15\x00\x00\x00\x10", enc.code(), "adc rax, 0x10000000"); |
| 1151 | 1199 | |
| 1152 | 1200 | try enc.encode(.add, &.{ |
| 1153 | 1201 | .{ .reg = .al }, |
| 1154 | .{ .imm = Immediate.u(0x10) }, | |
| 1202 | .{ .imm = Instruction.Immediate.u(0x10) }, | |
| 1155 | 1203 | }); |
| 1156 | 1204 | try expectEqualHexStrings("\x04\x10", enc.code(), "add al, 0x10"); |
| 1157 | 1205 | |
| 1158 | 1206 | try enc.encode(.add, &.{ |
| 1159 | 1207 | .{ .reg = .rax }, |
| 1160 | .{ .imm = Immediate.u(0x10) }, | |
| 1208 | .{ .imm = Instruction.Immediate.u(0x10) }, | |
| 1161 | 1209 | }); |
| 1162 | 1210 | try expectEqualHexStrings("\x48\x83\xC0\x10", enc.code(), "add rax, 0x10"); |
| 1163 | 1211 | |
| 1164 | 1212 | try enc.encode(.sbb, &.{ |
| 1165 | 1213 | .{ .reg = .ax }, |
| 1166 | .{ .imm = Immediate.u(0x10) }, | |
| 1214 | .{ .imm = Instruction.Immediate.u(0x10) }, | |
| 1167 | 1215 | }); |
| 1168 | 1216 | try expectEqualHexStrings("\x66\x1D\x10\x00", enc.code(), "sbb ax, 0x10"); |
| 1169 | 1217 | |
| 1170 | 1218 | try enc.encode(.xor, &.{ |
| 1171 | 1219 | .{ .reg = .al }, |
| 1172 | .{ .imm = Immediate.u(0x10) }, | |
| 1220 | .{ .imm = Instruction.Immediate.u(0x10) }, | |
| 1173 | 1221 | }); |
| 1174 | 1222 | try expectEqualHexStrings("\x34\x10", enc.code(), "xor al, 0x10"); |
| 1175 | 1223 | } |
| ... | ... | @@ -1179,43 +1227,43 @@ test "lower MI encoding" { |
| 1179 | 1227 | |
| 1180 | 1228 | try enc.encode(.mov, &.{ |
| 1181 | 1229 | .{ .reg = .r12 }, |
| 1182 | .{ .imm = Immediate.u(0x1000) }, | |
| 1230 | .{ .imm = Instruction.Immediate.u(0x1000) }, | |
| 1183 | 1231 | }); |
| 1184 | 1232 | try expectEqualHexStrings("\x49\xC7\xC4\x00\x10\x00\x00", enc.code(), "mov r12, 0x1000"); |
| 1185 | 1233 | |
| 1186 | 1234 | try enc.encode(.mov, &.{ |
| 1187 | 1235 | .{ .mem = Instruction.Memory.sib(.byte, .{ .base = .{ .reg = .r12 } }) }, |
| 1188 | .{ .imm = Immediate.u(0x10) }, | |
| 1236 | .{ .imm = Instruction.Immediate.u(0x10) }, | |
| 1189 | 1237 | }); |
| 1190 | 1238 | try expectEqualHexStrings("\x41\xC6\x04\x24\x10", enc.code(), "mov BYTE PTR [r12], 0x10"); |
| 1191 | 1239 | |
| 1192 | 1240 | try enc.encode(.mov, &.{ |
| 1193 | 1241 | .{ .reg = .r12 }, |
| 1194 | .{ .imm = Immediate.u(0x1000) }, | |
| 1242 | .{ .imm = Instruction.Immediate.u(0x1000) }, | |
| 1195 | 1243 | }); |
| 1196 | 1244 | try expectEqualHexStrings("\x49\xC7\xC4\x00\x10\x00\x00", enc.code(), "mov r12, 0x1000"); |
| 1197 | 1245 | |
| 1198 | 1246 | try enc.encode(.mov, &.{ |
| 1199 | 1247 | .{ .reg = .r12 }, |
| 1200 | .{ .imm = Immediate.u(0x1000) }, | |
| 1248 | .{ .imm = Instruction.Immediate.u(0x1000) }, | |
| 1201 | 1249 | }); |
| 1202 | 1250 | try expectEqualHexStrings("\x49\xC7\xC4\x00\x10\x00\x00", enc.code(), "mov r12, 0x1000"); |
| 1203 | 1251 | |
| 1204 | 1252 | try enc.encode(.mov, &.{ |
| 1205 | 1253 | .{ .reg = .rax }, |
| 1206 | .{ .imm = Immediate.u(0x10) }, | |
| 1254 | .{ .imm = Instruction.Immediate.u(0x10) }, | |
| 1207 | 1255 | }); |
| 1208 | 1256 | try expectEqualHexStrings("\x48\xc7\xc0\x10\x00\x00\x00", enc.code(), "mov rax, 0x10"); |
| 1209 | 1257 | |
| 1210 | 1258 | try enc.encode(.mov, &.{ |
| 1211 | 1259 | .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .r11 } }) }, |
| 1212 | .{ .imm = Immediate.u(0x10) }, | |
| 1260 | .{ .imm = Instruction.Immediate.u(0x10) }, | |
| 1213 | 1261 | }); |
| 1214 | 1262 | try expectEqualHexStrings("\x41\xc7\x03\x10\x00\x00\x00", enc.code(), "mov DWORD PTR [r11], 0x10"); |
| 1215 | 1263 | |
| 1216 | 1264 | try enc.encode(.mov, &.{ |
| 1217 | 1265 | .{ .mem = Instruction.Memory.rip(.qword, 0x10) }, |
| 1218 | .{ .imm = Immediate.u(0x10) }, | |
| 1266 | .{ .imm = Instruction.Immediate.u(0x10) }, | |
| 1219 | 1267 | }); |
| 1220 | 1268 | try expectEqualHexStrings( |
| 1221 | 1269 | "\x48\xC7\x05\x10\x00\x00\x00\x10\x00\x00\x00", |
| ... | ... | @@ -1225,19 +1273,19 @@ test "lower MI encoding" { |
| 1225 | 1273 | |
| 1226 | 1274 | try enc.encode(.mov, &.{ |
| 1227 | 1275 | .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .rbp }, .disp = -8 }) }, |
| 1228 | .{ .imm = Immediate.u(0x10) }, | |
| 1276 | .{ .imm = Instruction.Immediate.u(0x10) }, | |
| 1229 | 1277 | }); |
| 1230 | 1278 | try expectEqualHexStrings("\x48\xc7\x45\xf8\x10\x00\x00\x00", enc.code(), "mov QWORD PTR [rbp - 8], 0x10"); |
| 1231 | 1279 | |
| 1232 | 1280 | try enc.encode(.mov, &.{ |
| 1233 | 1281 | .{ .mem = Instruction.Memory.sib(.word, .{ .base = .{ .reg = .rbp }, .disp = -2 }) }, |
| 1234 | .{ .imm = Immediate.s(-16) }, | |
| 1282 | .{ .imm = Instruction.Immediate.s(-16) }, | |
| 1235 | 1283 | }); |
| 1236 | 1284 | try expectEqualHexStrings("\x66\xC7\x45\xFE\xF0\xFF", enc.code(), "mov WORD PTR [rbp - 2], -16"); |
| 1237 | 1285 | |
| 1238 | 1286 | try enc.encode(.mov, &.{ |
| 1239 | 1287 | .{ .mem = Instruction.Memory.sib(.byte, .{ .base = .{ .reg = .rbp }, .disp = -1 }) }, |
| 1240 | .{ .imm = Immediate.u(0x10) }, | |
| 1288 | .{ .imm = Instruction.Immediate.u(0x10) }, | |
| 1241 | 1289 | }); |
| 1242 | 1290 | try expectEqualHexStrings("\xC6\x45\xFF\x10", enc.code(), "mov BYTE PTR [rbp - 1], 0x10"); |
| 1243 | 1291 | |
| ... | ... | @@ -1247,7 +1295,7 @@ test "lower MI encoding" { |
| 1247 | 1295 | .disp = 0x10000000, |
| 1248 | 1296 | .scale_index = .{ .scale = 2, .index = .rcx }, |
| 1249 | 1297 | }) }, |
| 1250 | .{ .imm = Immediate.u(0x10) }, | |
| 1298 | .{ .imm = Instruction.Immediate.u(0x10) }, | |
| 1251 | 1299 | }); |
| 1252 | 1300 | try expectEqualHexStrings( |
| 1253 | 1301 | "\x48\xC7\x04\x4D\x00\x00\x00\x10\x10\x00\x00\x00", |
| ... | ... | @@ -1257,43 +1305,43 @@ test "lower MI encoding" { |
| 1257 | 1305 | |
| 1258 | 1306 | try enc.encode(.adc, &.{ |
| 1259 | 1307 | .{ .mem = Instruction.Memory.sib(.byte, .{ .base = .{ .reg = .rbp }, .disp = -0x10 }) }, |
| 1260 | .{ .imm = Immediate.u(0x10) }, | |
| 1308 | .{ .imm = Instruction.Immediate.u(0x10) }, | |
| 1261 | 1309 | }); |
| 1262 | 1310 | try expectEqualHexStrings("\x80\x55\xF0\x10", enc.code(), "adc BYTE PTR [rbp - 0x10], 0x10"); |
| 1263 | 1311 | |
| 1264 | 1312 | try enc.encode(.adc, &.{ |
| 1265 | 1313 | .{ .mem = Instruction.Memory.rip(.qword, 0) }, |
| 1266 | .{ .imm = Immediate.u(0x10) }, | |
| 1314 | .{ .imm = Instruction.Immediate.u(0x10) }, | |
| 1267 | 1315 | }); |
| 1268 | 1316 | try expectEqualHexStrings("\x48\x83\x15\x00\x00\x00\x00\x10", enc.code(), "adc QWORD PTR [rip], 0x10"); |
| 1269 | 1317 | |
| 1270 | 1318 | try enc.encode(.adc, &.{ |
| 1271 | 1319 | .{ .reg = .rax }, |
| 1272 | .{ .imm = Immediate.u(0x10) }, | |
| 1320 | .{ .imm = Instruction.Immediate.u(0x10) }, | |
| 1273 | 1321 | }); |
| 1274 | 1322 | try expectEqualHexStrings("\x48\x83\xD0\x10", enc.code(), "adc rax, 0x10"); |
| 1275 | 1323 | |
| 1276 | 1324 | try enc.encode(.add, &.{ |
| 1277 | 1325 | .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .rdx }, .disp = -8 }) }, |
| 1278 | .{ .imm = Immediate.u(0x10) }, | |
| 1326 | .{ .imm = Instruction.Immediate.u(0x10) }, | |
| 1279 | 1327 | }); |
| 1280 | 1328 | try expectEqualHexStrings("\x83\x42\xF8\x10", enc.code(), "add DWORD PTR [rdx - 8], 0x10"); |
| 1281 | 1329 | |
| 1282 | 1330 | try enc.encode(.add, &.{ |
| 1283 | 1331 | .{ .reg = .rax }, |
| 1284 | .{ .imm = Immediate.u(0x10) }, | |
| 1332 | .{ .imm = Instruction.Immediate.u(0x10) }, | |
| 1285 | 1333 | }); |
| 1286 | 1334 | try expectEqualHexStrings("\x48\x83\xC0\x10", enc.code(), "add rax, 0x10"); |
| 1287 | 1335 | |
| 1288 | 1336 | try enc.encode(.add, &.{ |
| 1289 | 1337 | .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .rbp }, .disp = -0x10 }) }, |
| 1290 | .{ .imm = Immediate.s(-0x10) }, | |
| 1338 | .{ .imm = Instruction.Immediate.s(-0x10) }, | |
| 1291 | 1339 | }); |
| 1292 | 1340 | try expectEqualHexStrings("\x48\x83\x45\xF0\xF0", enc.code(), "add QWORD PTR [rbp - 0x10], -0x10"); |
| 1293 | 1341 | |
| 1294 | 1342 | try enc.encode(.@"and", &.{ |
| 1295 | 1343 | .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .ds }, .disp = 0x10000000 }) }, |
| 1296 | .{ .imm = Immediate.u(0x10) }, | |
| 1344 | .{ .imm = Instruction.Immediate.u(0x10) }, | |
| 1297 | 1345 | }); |
| 1298 | 1346 | try expectEqualHexStrings( |
| 1299 | 1347 | "\x83\x24\x25\x00\x00\x00\x10\x10", |
| ... | ... | @@ -1303,7 +1351,7 @@ test "lower MI encoding" { |
| 1303 | 1351 | |
| 1304 | 1352 | try enc.encode(.@"and", &.{ |
| 1305 | 1353 | .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .es }, .disp = 0x10000000 }) }, |
| 1306 | .{ .imm = Immediate.u(0x10) }, | |
| 1354 | .{ .imm = Instruction.Immediate.u(0x10) }, | |
| 1307 | 1355 | }); |
| 1308 | 1356 | try expectEqualHexStrings( |
| 1309 | 1357 | "\x26\x83\x24\x25\x00\x00\x00\x10\x10", |
| ... | ... | @@ -1313,7 +1361,7 @@ test "lower MI encoding" { |
| 1313 | 1361 | |
| 1314 | 1362 | try enc.encode(.@"and", &.{ |
| 1315 | 1363 | .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .r12 }, .disp = 0x10000000 }) }, |
| 1316 | .{ .imm = Immediate.u(0x10) }, | |
| 1364 | .{ .imm = Instruction.Immediate.u(0x10) }, | |
| 1317 | 1365 | }); |
| 1318 | 1366 | try expectEqualHexStrings( |
| 1319 | 1367 | "\x41\x83\xA4\x24\x00\x00\x00\x10\x10", |
| ... | ... | @@ -1323,7 +1371,7 @@ test "lower MI encoding" { |
| 1323 | 1371 | |
| 1324 | 1372 | try enc.encode(.sub, &.{ |
| 1325 | 1373 | .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .r11 }, .disp = 0x10000000 }) }, |
| 1326 | .{ .imm = Immediate.u(0x10) }, | |
| 1374 | .{ .imm = Instruction.Immediate.u(0x10) }, | |
| 1327 | 1375 | }); |
| 1328 | 1376 | try expectEqualHexStrings( |
| 1329 | 1377 | "\x41\x83\xAB\x00\x00\x00\x10\x10", |
| ... | ... | @@ -1542,14 +1590,14 @@ test "lower RMI encoding" { |
| 1542 | 1590 | try enc.encode(.imul, &.{ |
| 1543 | 1591 | .{ .reg = .r11 }, |
| 1544 | 1592 | .{ .reg = .r12 }, |
| 1545 | .{ .imm = Immediate.s(-2) }, | |
| 1593 | .{ .imm = Instruction.Immediate.s(-2) }, | |
| 1546 | 1594 | }); |
| 1547 | 1595 | try expectEqualHexStrings("\x4D\x6B\xDC\xFE", enc.code(), "imul r11, r12, -2"); |
| 1548 | 1596 | |
| 1549 | 1597 | try enc.encode(.imul, &.{ |
| 1550 | 1598 | .{ .reg = .r11 }, |
| 1551 | 1599 | .{ .mem = Instruction.Memory.rip(.qword, -16) }, |
| 1552 | .{ .imm = Immediate.s(-1024) }, | |
| 1600 | .{ .imm = Instruction.Immediate.s(-1024) }, | |
| 1553 | 1601 | }); |
| 1554 | 1602 | try expectEqualHexStrings( |
| 1555 | 1603 | "\x4C\x69\x1D\xF0\xFF\xFF\xFF\x00\xFC\xFF\xFF", |
| ... | ... | @@ -1560,7 +1608,7 @@ test "lower RMI encoding" { |
| 1560 | 1608 | try enc.encode(.imul, &.{ |
| 1561 | 1609 | .{ .reg = .bx }, |
| 1562 | 1610 | .{ .mem = Instruction.Memory.sib(.word, .{ .base = .{ .reg = .rbp }, .disp = -16 }) }, |
| 1563 | .{ .imm = Immediate.s(-1024) }, | |
| 1611 | .{ .imm = Instruction.Immediate.s(-1024) }, | |
| 1564 | 1612 | }); |
| 1565 | 1613 | try expectEqualHexStrings( |
| 1566 | 1614 | "\x66\x69\x5D\xF0\x00\xFC", |
| ... | ... | @@ -1571,7 +1619,7 @@ test "lower RMI encoding" { |
| 1571 | 1619 | try enc.encode(.imul, &.{ |
| 1572 | 1620 | .{ .reg = .bx }, |
| 1573 | 1621 | .{ .mem = Instruction.Memory.sib(.word, .{ .base = .{ .reg = .rbp }, .disp = -16 }) }, |
| 1574 | .{ .imm = Immediate.u(1024) }, | |
| 1622 | .{ .imm = Instruction.Immediate.u(1024) }, | |
| 1575 | 1623 | }); |
| 1576 | 1624 | try expectEqualHexStrings( |
| 1577 | 1625 | "\x66\x69\x5D\xF0\x00\x04", |
| ... | ... | @@ -1687,7 +1735,7 @@ test "lower M encoding" { |
| 1687 | 1735 | try expectEqualHexStrings("\x65\xFF\x14\x25\x00\x00\x00\x00", enc.code(), "call gs:0x0"); |
| 1688 | 1736 | |
| 1689 | 1737 | try enc.encode(.call, &.{ |
| 1690 | .{ .imm = Immediate.s(0) }, | |
| 1738 | .{ .imm = Instruction.Immediate.s(0) }, | |
| 1691 | 1739 | }); |
| 1692 | 1740 | try expectEqualHexStrings("\xE8\x00\x00\x00\x00", enc.code(), "call 0x0"); |
| 1693 | 1741 | |
| ... | ... | @@ -1746,7 +1794,7 @@ test "lower OI encoding" { |
| 1746 | 1794 | |
| 1747 | 1795 | try enc.encode(.mov, &.{ |
| 1748 | 1796 | .{ .reg = .rax }, |
| 1749 | .{ .imm = Immediate.u(0x1000000000000000) }, | |
| 1797 | .{ .imm = Instruction.Immediate.u(0x1000000000000000) }, | |
| 1750 | 1798 | }); |
| 1751 | 1799 | try expectEqualHexStrings( |
| 1752 | 1800 | "\x48\xB8\x00\x00\x00\x00\x00\x00\x00\x10", |
| ... | ... | @@ -1756,7 +1804,7 @@ test "lower OI encoding" { |
| 1756 | 1804 | |
| 1757 | 1805 | try enc.encode(.mov, &.{ |
| 1758 | 1806 | .{ .reg = .r11 }, |
| 1759 | .{ .imm = Immediate.u(0x1000000000000000) }, | |
| 1807 | .{ .imm = Instruction.Immediate.u(0x1000000000000000) }, | |
| 1760 | 1808 | }); |
| 1761 | 1809 | try expectEqualHexStrings( |
| 1762 | 1810 | "\x49\xBB\x00\x00\x00\x00\x00\x00\x00\x10", |
| ... | ... | @@ -1766,19 +1814,19 @@ test "lower OI encoding" { |
| 1766 | 1814 | |
| 1767 | 1815 | try enc.encode(.mov, &.{ |
| 1768 | 1816 | .{ .reg = .r11d }, |
| 1769 | .{ .imm = Immediate.u(0x10000000) }, | |
| 1817 | .{ .imm = Instruction.Immediate.u(0x10000000) }, | |
| 1770 | 1818 | }); |
| 1771 | 1819 | try expectEqualHexStrings("\x41\xBB\x00\x00\x00\x10", enc.code(), "mov r11d, 0x10000000"); |
| 1772 | 1820 | |
| 1773 | 1821 | try enc.encode(.mov, &.{ |
| 1774 | 1822 | .{ .reg = .r11w }, |
| 1775 | .{ .imm = Immediate.u(0x1000) }, | |
| 1823 | .{ .imm = Instruction.Immediate.u(0x1000) }, | |
| 1776 | 1824 | }); |
| 1777 | 1825 | try expectEqualHexStrings("\x66\x41\xBB\x00\x10", enc.code(), "mov r11w, 0x1000"); |
| 1778 | 1826 | |
| 1779 | 1827 | try enc.encode(.mov, &.{ |
| 1780 | 1828 | .{ .reg = .r11b }, |
| 1781 | .{ .imm = Immediate.u(0x10) }, | |
| 1829 | .{ .imm = Instruction.Immediate.u(0x10) }, | |
| 1782 | 1830 | }); |
| 1783 | 1831 | try expectEqualHexStrings("\x41\xB3\x10", enc.code(), "mov r11b, 0x10"); |
| 1784 | 1832 | } |
| ... | ... | @@ -1900,7 +1948,7 @@ test "invalid instruction" { |
| 1900 | 1948 | .{ .reg = .r12d }, |
| 1901 | 1949 | }); |
| 1902 | 1950 | try invalidInstruction(.push, &.{ |
| 1903 | .{ .imm = Immediate.u(0x1000000000000000) }, | |
| 1951 | .{ .imm = Instruction.Immediate.u(0x1000000000000000) }, | |
| 1904 | 1952 | }); |
| 1905 | 1953 | } |
| 1906 | 1954 | |
| ... | ... | @@ -2213,7 +2261,7 @@ const Assembler = struct { |
| 2213 | 2261 | .immediate => { |
| 2214 | 2262 | const is_neg = if (as.expect(.minus)) |_| true else |_| false; |
| 2215 | 2263 | const imm_tok = try as.expect(.numeral); |
| 2216 | const imm: Immediate = if (is_neg) blk: { | |
| 2264 | const imm: Instruction.Immediate = if (is_neg) blk: { | |
| 2217 | 2265 | const imm = try std.fmt.parseInt(i32, as.source(imm_tok), 0); |
| 2218 | 2266 | break :blk .{ .signed = imm * -1 }; |
| 2219 | 2267 | } else .{ .unsigned = try std.fmt.parseInt(u64, as.source(imm_tok), 0) }; |
src/codegen.zig+6-4| ... | ... | @@ -828,6 +828,9 @@ pub const GenResult = union(enum) { |
| 828 | 828 | /// Reference to memory location but deferred until linker allocated the Decl in memory. |
| 829 | 829 | /// Traditionally, this corresponds to emitting a relocation in a relocatable object file. |
| 830 | 830 | load_symbol: u32, |
| 831 | /// Reference to memory location but deferred until linker allocated the Decl in memory. | |
| 832 | /// Traditionally, this corresponds to emitting a relocation in a relocatable object file. | |
| 833 | lea_symbol: u32, | |
| 831 | 834 | }; |
| 832 | 835 | |
| 833 | 836 | fn mcv(val: MCValue) GenResult { |
| ... | ... | @@ -895,16 +898,15 @@ fn genNavRef( |
| 895 | 898 | if (lf.cast(.elf)) |elf_file| { |
| 896 | 899 | const zo = elf_file.zigObjectPtr().?; |
| 897 | 900 | if (is_extern) { |
| 898 | // TODO audit this | |
| 899 | 901 | const sym_index = try elf_file.getGlobalSymbol(name.toSlice(ip), lib_name.toSlice(ip)); |
| 900 | zo.symbol(sym_index).flags.needs_got = true; | |
| 901 | return GenResult.mcv(.{ .load_symbol = sym_index }); | |
| 902 | zo.symbol(sym_index).flags.is_extern_ptr = true; | |
| 903 | return GenResult.mcv(.{ .lea_symbol = sym_index }); | |
| 902 | 904 | } |
| 903 | 905 | const sym_index = try zo.getOrCreateMetadataForNav(elf_file, nav_index); |
| 904 | 906 | if (!single_threaded and is_threadlocal) { |
| 905 | 907 | return GenResult.mcv(.{ .load_tlv = sym_index }); |
| 906 | 908 | } |
| 907 | return GenResult.mcv(.{ .load_symbol = sym_index }); | |
| 909 | return GenResult.mcv(.{ .lea_symbol = sym_index }); | |
| 908 | 910 | } else if (lf.cast(.macho)) |macho_file| { |
| 909 | 911 | const zo = macho_file.getZigObject().?; |
| 910 | 912 | if (is_extern) { |
src/link/Elf.zig+11-104| ... | ... | @@ -64,9 +64,6 @@ phdrs: std.ArrayListUnmanaged(elf.Elf64_Phdr) = .{}, |
| 64 | 64 | /// Tracked loadable segments during incremental linking. |
| 65 | 65 | /// The index into the program headers of a PT_LOAD program header with Read and Execute flags |
| 66 | 66 | phdr_zig_load_re_index: ?u16 = null, |
| 67 | /// The index into the program headers of the global offset table. | |
| 68 | /// It needs PT_LOAD and Read flags. | |
| 69 | phdr_zig_got_index: ?u16 = null, | |
| 70 | 67 | /// The index into the program headers of a PT_LOAD program header with Read flag |
| 71 | 68 | phdr_zig_load_ro_index: ?u16 = null, |
| 72 | 69 | /// The index into the program headers of a PT_LOAD program header with Write flag |
| ... | ... | @@ -130,8 +127,6 @@ plt_got: PltGotSection = .{}, |
| 130 | 127 | copy_rel: CopyRelSection = .{}, |
| 131 | 128 | /// .rela.plt section |
| 132 | 129 | rela_plt: std.ArrayListUnmanaged(elf.Elf64_Rela) = .{}, |
| 133 | /// .got.zig section | |
| 134 | zig_got: ZigGotSection = .{}, | |
| 135 | 130 | /// SHT_GROUP sections |
| 136 | 131 | /// Applies only to a relocatable. |
| 137 | 132 | comdat_group_sections: std.ArrayListUnmanaged(ComdatGroupSection) = .{}, |
| ... | ... | @@ -142,7 +137,6 @@ zig_text_section_index: ?u32 = null, |
| 142 | 137 | zig_data_rel_ro_section_index: ?u32 = null, |
| 143 | 138 | zig_data_section_index: ?u32 = null, |
| 144 | 139 | zig_bss_section_index: ?u32 = null, |
| 145 | zig_got_section_index: ?u32 = null, | |
| 146 | 140 | |
| 147 | 141 | debug_info_section_index: ?u32 = null, |
| 148 | 142 | debug_abbrev_section_index: ?u32 = null, |
| ... | ... | @@ -474,7 +468,6 @@ pub fn deinit(self: *Elf) void { |
| 474 | 468 | self.copy_rel.deinit(gpa); |
| 475 | 469 | self.rela_dyn.deinit(gpa); |
| 476 | 470 | self.rela_plt.deinit(gpa); |
| 477 | self.zig_got.deinit(gpa); | |
| 478 | 471 | self.comdat_group_sections.deinit(gpa); |
| 479 | 472 | } |
| 480 | 473 | |
| ... | ... | @@ -611,28 +604,13 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void { |
| 611 | 604 | .type = elf.PT_LOAD, |
| 612 | 605 | .offset = off, |
| 613 | 606 | .filesz = filesz, |
| 614 | .addr = if (ptr_bit_width >= 32) 0x8000000 else 0x8000, | |
| 607 | .addr = if (ptr_bit_width >= 32) 0x4000000 else 0x4000, | |
| 615 | 608 | .memsz = filesz, |
| 616 | 609 | .@"align" = self.page_size, |
| 617 | 610 | .flags = elf.PF_X | elf.PF_R | elf.PF_W, |
| 618 | 611 | }); |
| 619 | 612 | } |
| 620 | 613 | |
| 621 | if (self.phdr_zig_got_index == null) { | |
| 622 | const alignment = self.page_size; | |
| 623 | const filesz = @as(u64, ptr_size) * options.symbol_count_hint; | |
| 624 | const off = self.findFreeSpace(filesz, alignment); | |
| 625 | self.phdr_zig_got_index = try self.addPhdr(.{ | |
| 626 | .type = elf.PT_LOAD, | |
| 627 | .offset = off, | |
| 628 | .filesz = filesz, | |
| 629 | .addr = if (ptr_bit_width >= 32) 0x4000000 else 0x4000, | |
| 630 | .memsz = filesz, | |
| 631 | .@"align" = alignment, | |
| 632 | .flags = elf.PF_R | elf.PF_W, | |
| 633 | }); | |
| 634 | } | |
| 635 | ||
| 636 | 614 | if (self.phdr_zig_load_ro_index == null) { |
| 637 | 615 | const alignment = self.page_size; |
| 638 | 616 | const filesz: u64 = 1024; |
| ... | ... | @@ -701,27 +679,6 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void { |
| 701 | 679 | try self.last_atom_and_free_list_table.putNoClobber(gpa, self.zig_text_section_index.?, .{}); |
| 702 | 680 | } |
| 703 | 681 | |
| 704 | if (self.zig_got_section_index == null and !self.base.isRelocatable()) { | |
| 705 | self.zig_got_section_index = try self.addSection(.{ | |
| 706 | .name = try self.insertShString(".got.zig"), | |
| 707 | .type = elf.SHT_PROGBITS, | |
| 708 | .addralign = ptr_size, | |
| 709 | .flags = elf.SHF_ALLOC | elf.SHF_WRITE, | |
| 710 | .offset = std.math.maxInt(u64), | |
| 711 | }); | |
| 712 | const shdr = &self.shdrs.items[self.zig_got_section_index.?]; | |
| 713 | const phndx = self.phdr_zig_got_index.?; | |
| 714 | const phdr = self.phdrs.items[phndx]; | |
| 715 | shdr.sh_addr = phdr.p_vaddr; | |
| 716 | shdr.sh_offset = phdr.p_offset; | |
| 717 | shdr.sh_size = phdr.p_memsz; | |
| 718 | try self.phdr_to_shdr_table.putNoClobber( | |
| 719 | gpa, | |
| 720 | self.zig_got_section_index.?, | |
| 721 | self.phdr_zig_got_index.?, | |
| 722 | ); | |
| 723 | } | |
| 724 | ||
| 725 | 682 | if (self.zig_data_rel_ro_section_index == null) { |
| 726 | 683 | self.zig_data_rel_ro_section_index = try self.addSection(.{ |
| 727 | 684 | .name = try self.insertShString(".data.rel.ro.zig"), |
| ... | ... | @@ -900,6 +857,11 @@ pub fn growAllocSection(self: *Elf, shdr_index: u32, needed_size: u64) !void { |
| 900 | 857 | const shdr = &self.shdrs.items[shdr_index]; |
| 901 | 858 | const maybe_phdr = if (self.phdr_to_shdr_table.get(shdr_index)) |phndx| &self.phdrs.items[phndx] else null; |
| 902 | 859 | const is_zerofill = shdr.sh_type == elf.SHT_NOBITS; |
| 860 | log.debug("allocated size {x} of {s}, needed size {x}", .{ | |
| 861 | self.allocatedSize(shdr.sh_offset), | |
| 862 | self.getShString(shdr.sh_name), | |
| 863 | needed_size, | |
| 864 | }); | |
| 903 | 865 | |
| 904 | 866 | if (needed_size > self.allocatedSize(shdr.sh_offset) and !is_zerofill) { |
| 905 | 867 | const existing_size = shdr.sh_size; |
| ... | ... | @@ -3156,8 +3118,8 @@ fn initSyntheticSections(self: *Elf) !void { |
| 3156 | 3118 | }); |
| 3157 | 3119 | |
| 3158 | 3120 | const needs_rela_dyn = blk: { |
| 3159 | if (self.got.flags.needs_rela or self.got.flags.needs_tlsld or | |
| 3160 | self.zig_got.flags.needs_rela or self.copy_rel.symbols.items.len > 0) break :blk true; | |
| 3121 | if (self.got.flags.needs_rela or self.got.flags.needs_tlsld or self.copy_rel.symbols.items.len > 0) | |
| 3122 | break :blk true; | |
| 3161 | 3123 | if (self.zigObjectPtr()) |zig_object| { |
| 3162 | 3124 | if (zig_object.num_dynrelocs > 0) break :blk true; |
| 3163 | 3125 | } |
| ... | ... | @@ -3562,7 +3524,6 @@ fn sortPhdrs(self: *Elf) error{OutOfMemory}!void { |
| 3562 | 3524 | |
| 3563 | 3525 | for (&[_]*?u16{ |
| 3564 | 3526 | &self.phdr_zig_load_re_index, |
| 3565 | &self.phdr_zig_got_index, | |
| 3566 | 3527 | &self.phdr_zig_load_ro_index, |
| 3567 | 3528 | &self.phdr_zig_load_zerofill_index, |
| 3568 | 3529 | &self.phdr_table_index, |
| ... | ... | @@ -3694,7 +3655,6 @@ fn resetShdrIndexes(self: *Elf, backlinks: []const u32) !void { |
| 3694 | 3655 | &self.versym_section_index, |
| 3695 | 3656 | &self.verneed_section_index, |
| 3696 | 3657 | &self.zig_text_section_index, |
| 3697 | &self.zig_got_section_index, | |
| 3698 | 3658 | &self.zig_data_rel_ro_section_index, |
| 3699 | 3659 | &self.zig_data_section_index, |
| 3700 | 3660 | &self.zig_bss_section_index, |
| ... | ... | @@ -3893,7 +3853,7 @@ fn updateSectionSizes(self: *Elf) !void { |
| 3893 | 3853 | } |
| 3894 | 3854 | |
| 3895 | 3855 | if (self.rela_dyn_section_index) |shndx| { |
| 3896 | var num = self.got.numRela(self) + self.copy_rel.numRela() + self.zig_got.numRela(); | |
| 3856 | var num = self.got.numRela(self) + self.copy_rel.numRela(); | |
| 3897 | 3857 | if (self.zigObjectPtr()) |zig_object| { |
| 3898 | 3858 | num += zig_object.num_dynrelocs; |
| 3899 | 3859 | } |
| ... | ... | @@ -4431,15 +4391,6 @@ pub fn updateSymtabSize(self: *Elf) !void { |
| 4431 | 4391 | strsize += ctx.strsize; |
| 4432 | 4392 | } |
| 4433 | 4393 | |
| 4434 | if (self.zigObjectPtr()) |_| { | |
| 4435 | if (self.zig_got_section_index) |_| { | |
| 4436 | self.zig_got.output_symtab_ctx.ilocal = nlocals + 1; | |
| 4437 | self.zig_got.updateSymtabSize(self); | |
| 4438 | nlocals += self.zig_got.output_symtab_ctx.nlocals; | |
| 4439 | strsize += self.zig_got.output_symtab_ctx.strsize; | |
| 4440 | } | |
| 4441 | } | |
| 4442 | ||
| 4443 | 4394 | if (self.got_section_index) |_| { |
| 4444 | 4395 | self.got.output_symtab_ctx.ilocal = nlocals + 1; |
| 4445 | 4396 | self.got.updateSymtabSize(self); |
| ... | ... | @@ -4576,9 +4527,6 @@ fn writeSyntheticSections(self: *Elf) !void { |
| 4576 | 4527 | const shdr = self.shdrs.items[shndx]; |
| 4577 | 4528 | try self.got.addRela(self); |
| 4578 | 4529 | try self.copy_rel.addRela(self); |
| 4579 | if (self.zigObjectPtr()) |_| { | |
| 4580 | try self.zig_got.addRela(self); | |
| 4581 | } | |
| 4582 | 4530 | self.sortRelaDyn(); |
| 4583 | 4531 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.rela_dyn.items), shdr.sh_offset); |
| 4584 | 4532 | } |
| ... | ... | @@ -4674,10 +4622,6 @@ pub fn writeSymtab(self: *Elf) !void { |
| 4674 | 4622 | obj.asFile().writeSymtab(self); |
| 4675 | 4623 | } |
| 4676 | 4624 | |
| 4677 | if (self.zig_got_section_index) |_| { | |
| 4678 | self.zig_got.writeSymtab(self); | |
| 4679 | } | |
| 4680 | ||
| 4681 | 4625 | if (self.got_section_index) |_| { |
| 4682 | 4626 | self.got.writeSymtab(self); |
| 4683 | 4627 | } |
| ... | ... | @@ -5085,7 +5029,6 @@ pub fn isZigSection(self: Elf, shndx: u32) bool { |
| 5085 | 5029 | self.zig_data_rel_ro_section_index, |
| 5086 | 5030 | self.zig_data_section_index, |
| 5087 | 5031 | self.zig_bss_section_index, |
| 5088 | self.zig_got_section_index, | |
| 5089 | 5032 | }) |maybe_index| { |
| 5090 | 5033 | if (maybe_index) |index| { |
| 5091 | 5034 | if (index == shndx) return true; |
| ... | ... | @@ -5657,10 +5600,11 @@ fn fmtDumpState( |
| 5657 | 5600 | |
| 5658 | 5601 | if (self.zigObjectPtr()) |zig_object| { |
| 5659 | 5602 | try writer.print("zig_object({d}) : {s}\n", .{ zig_object.index, zig_object.path }); |
| 5660 | try writer.print("{}{}\n", .{ | |
| 5603 | try writer.print("{}{}", .{ | |
| 5661 | 5604 | zig_object.fmtAtoms(self), |
| 5662 | 5605 | zig_object.fmtSymtab(self), |
| 5663 | 5606 | }); |
| 5607 | try writer.writeByte('\n'); | |
| 5664 | 5608 | } |
| 5665 | 5609 | |
| 5666 | 5610 | for (self.objects.items) |index| { |
| ... | ... | @@ -5700,7 +5644,6 @@ fn fmtDumpState( |
| 5700 | 5644 | } |
| 5701 | 5645 | } |
| 5702 | 5646 | |
| 5703 | try writer.print("{}\n", .{self.zig_got.fmt(self)}); | |
| 5704 | 5647 | try writer.print("{}\n", .{self.got.fmt(self)}); |
| 5705 | 5648 | try writer.print("{}\n", .{self.plt.fmt(self)}); |
| 5706 | 5649 | |
| ... | ... | @@ -5991,41 +5934,6 @@ const RelaSection = struct { |
| 5991 | 5934 | }; |
| 5992 | 5935 | const RelaSectionTable = std.AutoArrayHashMapUnmanaged(u32, RelaSection); |
| 5993 | 5936 | |
| 5994 | pub const R_ZIG_GOT32: u32 = 0xff00; | |
| 5995 | pub const R_ZIG_GOTPCREL: u32 = 0xff01; | |
| 5996 | pub const R_ZIG_GOT_HI20: u32 = 0xff02; | |
| 5997 | pub const R_ZIG_GOT_LO12: u32 = 0xff03; | |
| 5998 | pub const R_GOT_HI20_STATIC: u32 = 0xff04; | |
| 5999 | pub const R_GOT_LO12_I_STATIC: u32 = 0xff05; | |
| 6000 | ||
| 6001 | // Comptime asserts that no Zig relocs overlap with another ISA's reloc number | |
| 6002 | comptime { | |
| 6003 | const zig_relocs = .{ | |
| 6004 | R_ZIG_GOT32, | |
| 6005 | R_ZIG_GOT_HI20, | |
| 6006 | R_ZIG_GOT_LO12, | |
| 6007 | R_ZIG_GOTPCREL, | |
| 6008 | R_GOT_HI20_STATIC, | |
| 6009 | R_GOT_LO12_I_STATIC, | |
| 6010 | }; | |
| 6011 | ||
| 6012 | const other_relocs = .{ | |
| 6013 | elf.R_X86_64, | |
| 6014 | elf.R_AARCH64, | |
| 6015 | elf.R_RISCV, | |
| 6016 | elf.R_PPC64, | |
| 6017 | }; | |
| 6018 | ||
| 6019 | @setEvalBranchQuota(@min(other_relocs.len * zig_relocs.len * 256, 6200)); | |
| 6020 | for (other_relocs) |relocs| { | |
| 6021 | for (@typeInfo(relocs).Enum.fields) |reloc| { | |
| 6022 | for (zig_relocs) |zig_reloc| { | |
| 6023 | assert(reloc.value != zig_reloc); | |
| 6024 | } | |
| 6025 | } | |
| 6026 | } | |
| 6027 | } | |
| 6028 | ||
| 6029 | 5937 | fn defaultEntrySymbolName(cpu_arch: std.Target.Cpu.Arch) []const u8 { |
| 6030 | 5938 | return switch (cpu_arch) { |
| 6031 | 5939 | .mips, .mipsel, .mips64, .mips64el => "__start", |
| ... | ... | @@ -6095,6 +6003,5 @@ const StringTable = @import("StringTable.zig"); |
| 6095 | 6003 | const Thunk = thunks.Thunk; |
| 6096 | 6004 | const Value = @import("../Value.zig"); |
| 6097 | 6005 | const VerneedSection = synthetic_sections.VerneedSection; |
| 6098 | const ZigGotSection = synthetic_sections.ZigGotSection; | |
| 6099 | 6006 | const ZigObject = @import("Elf/ZigObject.zig"); |
| 6100 | 6007 | const riscv = @import("riscv.zig"); |
src/link/Elf/Atom.zig+22-81| ... | ... | @@ -746,12 +746,10 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) RelocError!voi |
| 746 | 746 | const P = self.address(elf_file) + @as(i64, @intCast(rel.r_offset)); |
| 747 | 747 | // Addend from the relocation. |
| 748 | 748 | const A = rel.r_addend; |
| 749 | // Address of the target symbol - can be address of the symbol within an atom or address of PLT stub. | |
| 749 | // Address of the target symbol - can be address of the symbol within an atom or address of PLT stub, or address of a Zig trampoline. | |
| 750 | 750 | const S = target.address(.{}, elf_file); |
| 751 | 751 | // Address of the global offset table. |
| 752 | 752 | const GOT = elf_file.gotAddress(); |
| 753 | // Address of the .zig.got table entry if any. | |
| 754 | const ZIG_GOT = target.zigGotAddress(elf_file); | |
| 755 | 753 | // Relative offset to the start of the global offset table. |
| 756 | 754 | const G = target.gotAddress(elf_file) - GOT; |
| 757 | 755 | // // Address of the thread pointer. |
| ... | ... | @@ -759,19 +757,18 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) RelocError!voi |
| 759 | 757 | // Address of the dynamic thread pointer. |
| 760 | 758 | const DTP = elf_file.dtpAddress(); |
| 761 | 759 | |
| 762 | relocs_log.debug(" {s}: {x}: [{x} => {x}] G({x}) ZG({x}) ({s})", .{ | |
| 760 | relocs_log.debug(" {s}: {x}: [{x} => {x}] GOT({x}) ({s})", .{ | |
| 763 | 761 | relocation.fmtRelocType(rel.r_type(), cpu_arch), |
| 764 | 762 | r_offset, |
| 765 | 763 | P, |
| 766 | 764 | S + A, |
| 767 | 765 | G + GOT + A, |
| 768 | ZIG_GOT + A, | |
| 769 | 766 | target.name(elf_file), |
| 770 | 767 | }); |
| 771 | 768 | |
| 772 | 769 | try stream.seekTo(r_offset); |
| 773 | 770 | |
| 774 | const args = ResolveArgs{ P, A, S, GOT, G, TP, DTP, ZIG_GOT }; | |
| 771 | const args = ResolveArgs{ P, A, S, GOT, G, TP, DTP }; | |
| 775 | 772 | |
| 776 | 773 | switch (cpu_arch) { |
| 777 | 774 | .x86_64 => x86_64.resolveRelocAlloc(self, elf_file, rel, target, args, &it, code, &stream) catch |err| switch (err) { |
| ... | ... | @@ -956,7 +953,7 @@ pub fn resolveRelocsNonAlloc(self: Atom, elf_file: *Elf, code: []u8, undefs: any |
| 956 | 953 | // Address of the dynamic thread pointer. |
| 957 | 954 | const DTP = elf_file.dtpAddress(); |
| 958 | 955 | |
| 959 | const args = ResolveArgs{ P, A, S, GOT, 0, 0, DTP, 0 }; | |
| 956 | const args = ResolveArgs{ P, A, S, GOT, 0, 0, DTP }; | |
| 960 | 957 | |
| 961 | 958 | relocs_log.debug(" {}: {x}: [{x} => {x}] ({s})", .{ |
| 962 | 959 | relocation.fmtRelocType(rel.r_type(), cpu_arch), |
| ... | ... | @@ -1025,7 +1022,7 @@ pub fn format( |
| 1025 | 1022 | _ = unused_fmt_string; |
| 1026 | 1023 | _ = options; |
| 1027 | 1024 | _ = writer; |
| 1028 | @compileError("do not format symbols directly"); | |
| 1025 | @compileError("do not format Atom directly"); | |
| 1029 | 1026 | } |
| 1030 | 1027 | |
| 1031 | 1028 | pub fn fmt(atom: Atom, elf_file: *Elf) std.fmt.Formatter(format2) { |
| ... | ... | @@ -1051,8 +1048,8 @@ fn format2( |
| 1051 | 1048 | const atom = ctx.atom; |
| 1052 | 1049 | const elf_file = ctx.elf_file; |
| 1053 | 1050 | try writer.print("atom({d}) : {s} : @{x} : shdr({d}) : align({x}) : size({x})", .{ |
| 1054 | atom.atom_index, atom.name(elf_file), atom.address(elf_file), | |
| 1055 | atom.output_section_index, atom.alignment, atom.size, | |
| 1051 | atom.atom_index, atom.name(elf_file), atom.address(elf_file), | |
| 1052 | atom.output_section_index, atom.alignment.toByteUnits() orelse 0, atom.size, | |
| 1056 | 1053 | }); |
| 1057 | 1054 | if (atom.fdes(elf_file).len > 0) { |
| 1058 | 1055 | try writer.writeAll(" : fdes{ "); |
| ... | ... | @@ -1180,16 +1177,7 @@ const x86_64 = struct { |
| 1180 | 1177 | .TLSDESC_CALL, |
| 1181 | 1178 | => {}, |
| 1182 | 1179 | |
| 1183 | else => |x| switch (@intFromEnum(x)) { | |
| 1184 | // Zig custom relocations | |
| 1185 | Elf.R_ZIG_GOT32, | |
| 1186 | Elf.R_ZIG_GOTPCREL, | |
| 1187 | => { | |
| 1188 | assert(symbol.flags.has_zig_got); | |
| 1189 | }, | |
| 1190 | ||
| 1191 | else => try atom.reportUnhandledRelocError(rel, elf_file), | |
| 1192 | }, | |
| 1180 | else => try atom.reportUnhandledRelocError(rel, elf_file), | |
| 1193 | 1181 | } |
| 1194 | 1182 | } |
| 1195 | 1183 | |
| ... | ... | @@ -1209,7 +1197,7 @@ const x86_64 = struct { |
| 1209 | 1197 | |
| 1210 | 1198 | const cwriter = stream.writer(); |
| 1211 | 1199 | |
| 1212 | const P, const A, const S, const GOT, const G, const TP, const DTP, const ZIG_GOT = args; | |
| 1200 | const P, const A, const S, const GOT, const G, const TP, const DTP = args; | |
| 1213 | 1201 | |
| 1214 | 1202 | switch (r_type) { |
| 1215 | 1203 | .NONE => unreachable, |
| ... | ... | @@ -1224,9 +1212,8 @@ const x86_64 = struct { |
| 1224 | 1212 | ); |
| 1225 | 1213 | }, |
| 1226 | 1214 | |
| 1227 | .PLT32, | |
| 1228 | .PC32, | |
| 1229 | => try cwriter.writeInt(i32, @as(i32, @intCast(S + A - P)), .little), | |
| 1215 | .PLT32 => try cwriter.writeInt(i32, @as(i32, @intCast(S + A - P)), .little), | |
| 1216 | .PC32 => try cwriter.writeInt(i32, @as(i32, @intCast(S + A - P)), .little), | |
| 1230 | 1217 | |
| 1231 | 1218 | .GOTPCREL => try cwriter.writeInt(i32, @as(i32, @intCast(G + GOT + A - P)), .little), |
| 1232 | 1219 | .GOTPC32 => try cwriter.writeInt(i32, @as(i32, @intCast(GOT + A - P)), .little), |
| ... | ... | @@ -1327,15 +1314,9 @@ const x86_64 = struct { |
| 1327 | 1314 | } |
| 1328 | 1315 | }, |
| 1329 | 1316 | |
| 1330 | .GOT32 => try cwriter.writeInt(i32, @as(i32, @intCast(G + GOT + A)), .little), | |
| 1331 | ||
| 1332 | else => |x| switch (@intFromEnum(x)) { | |
| 1333 | // Zig custom relocations | |
| 1334 | Elf.R_ZIG_GOT32 => try cwriter.writeInt(u32, @as(u32, @intCast(ZIG_GOT + A)), .little), | |
| 1335 | Elf.R_ZIG_GOTPCREL => try cwriter.writeInt(i32, @as(i32, @intCast(ZIG_GOT + A - P)), .little), | |
| 1317 | .GOT32 => try cwriter.writeInt(i32, @as(i32, @intCast(G + A)), .little), | |
| 1336 | 1318 | |
| 1337 | else => try atom.reportUnhandledRelocError(rel, elf_file), | |
| 1338 | }, | |
| 1319 | else => try atom.reportUnhandledRelocError(rel, elf_file), | |
| 1339 | 1320 | } |
| 1340 | 1321 | } |
| 1341 | 1322 | |
| ... | ... | @@ -1355,7 +1336,7 @@ const x86_64 = struct { |
| 1355 | 1336 | const r_type: elf.R_X86_64 = @enumFromInt(rel.r_type()); |
| 1356 | 1337 | const cwriter = stream.writer(); |
| 1357 | 1338 | |
| 1358 | _, const A, const S, const GOT, _, _, const DTP, _ = args; | |
| 1339 | _, const A, const S, const GOT, _, _, const DTP = args; | |
| 1359 | 1340 | |
| 1360 | 1341 | switch (r_type) { |
| 1361 | 1342 | .NONE => unreachable, |
| ... | ... | @@ -1629,7 +1610,7 @@ const x86_64 = struct { |
| 1629 | 1610 | const bits = @import("../../arch/x86_64/bits.zig"); |
| 1630 | 1611 | const encoder = @import("../../arch/x86_64/encoder.zig"); |
| 1631 | 1612 | const Disassembler = @import("../../arch/x86_64/Disassembler.zig"); |
| 1632 | const Immediate = bits.Immediate; | |
| 1613 | const Immediate = Instruction.Immediate; | |
| 1633 | 1614 | const Instruction = encoder.Instruction; |
| 1634 | 1615 | }; |
| 1635 | 1616 | |
| ... | ... | @@ -1738,9 +1719,8 @@ const aarch64 = struct { |
| 1738 | 1719 | const code = code_buffer[r_offset..][0..4]; |
| 1739 | 1720 | const file_ptr = atom.file(elf_file).?; |
| 1740 | 1721 | |
| 1741 | const P, const A, const S, const GOT, const G, const TP, const DTP, const ZIG_GOT = args; | |
| 1722 | const P, const A, const S, const GOT, const G, const TP, const DTP = args; | |
| 1742 | 1723 | _ = DTP; |
| 1743 | _ = ZIG_GOT; | |
| 1744 | 1724 | |
| 1745 | 1725 | switch (r_type) { |
| 1746 | 1726 | .NONE => unreachable, |
| ... | ... | @@ -1942,7 +1922,7 @@ const aarch64 = struct { |
| 1942 | 1922 | const r_type: elf.R_AARCH64 = @enumFromInt(rel.r_type()); |
| 1943 | 1923 | const cwriter = stream.writer(); |
| 1944 | 1924 | |
| 1945 | _, const A, const S, _, _, _, _, _ = args; | |
| 1925 | _, const A, const S, _, _, _, _ = args; | |
| 1946 | 1926 | |
| 1947 | 1927 | switch (r_type) { |
| 1948 | 1928 | .NONE => unreachable, |
| ... | ... | @@ -1998,19 +1978,7 @@ const riscv = struct { |
| 1998 | 1978 | .SUB32, |
| 1999 | 1979 | => {}, |
| 2000 | 1980 | |
| 2001 | else => |x| switch (@intFromEnum(x)) { | |
| 2002 | Elf.R_ZIG_GOT_HI20, | |
| 2003 | Elf.R_ZIG_GOT_LO12, | |
| 2004 | => { | |
| 2005 | assert(symbol.flags.has_zig_got); | |
| 2006 | }, | |
| 2007 | ||
| 2008 | Elf.R_GOT_HI20_STATIC, | |
| 2009 | Elf.R_GOT_LO12_I_STATIC, | |
| 2010 | => symbol.flags.needs_got = true, | |
| 2011 | ||
| 2012 | else => try atom.reportUnhandledRelocError(rel, elf_file), | |
| 2013 | }, | |
| 1981 | else => try atom.reportUnhandledRelocError(rel, elf_file), | |
| 2014 | 1982 | } |
| 2015 | 1983 | } |
| 2016 | 1984 | |
| ... | ... | @@ -2028,7 +1996,7 @@ const riscv = struct { |
| 2028 | 1996 | const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow; |
| 2029 | 1997 | const cwriter = stream.writer(); |
| 2030 | 1998 | |
| 2031 | const P, const A, const S, const GOT, const G, const TP, const DTP, const ZIG_GOT = args; | |
| 1999 | const P, const A, const S, const GOT, const G, const TP, const DTP = args; | |
| 2032 | 2000 | _ = TP; |
| 2033 | 2001 | _ = DTP; |
| 2034 | 2002 | |
| ... | ... | @@ -2147,34 +2115,7 @@ const riscv = struct { |
| 2147 | 2115 | // TODO: annotates an ADD instruction that can be removed when TPREL is relaxed |
| 2148 | 2116 | }, |
| 2149 | 2117 | |
| 2150 | else => |x| switch (@intFromEnum(x)) { | |
| 2151 | // Zig custom relocations | |
| 2152 | Elf.R_ZIG_GOT_HI20 => { | |
| 2153 | assert(target.flags.has_zig_got); | |
| 2154 | const disp: u32 = @bitCast(math.cast(i32, ZIG_GOT + A) orelse return error.Overflow); | |
| 2155 | riscv_util.writeInstU(code[r_offset..][0..4], disp); | |
| 2156 | }, | |
| 2157 | ||
| 2158 | Elf.R_ZIG_GOT_LO12 => { | |
| 2159 | assert(target.flags.has_zig_got); | |
| 2160 | const value: u32 = @bitCast(math.cast(i32, ZIG_GOT + A) orelse return error.Overflow); | |
| 2161 | riscv_util.writeInstI(code[r_offset..][0..4], value); | |
| 2162 | }, | |
| 2163 | ||
| 2164 | Elf.R_GOT_HI20_STATIC => { | |
| 2165 | assert(target.flags.has_got); | |
| 2166 | const disp: u32 = @bitCast(math.cast(i32, G + GOT + A) orelse return error.Overflow); | |
| 2167 | riscv_util.writeInstU(code[r_offset..][0..4], disp); | |
| 2168 | }, | |
| 2169 | ||
| 2170 | Elf.R_GOT_LO12_I_STATIC => { | |
| 2171 | assert(target.flags.has_got); | |
| 2172 | const disp: u32 = @bitCast(math.cast(i32, G + GOT + A) orelse return error.Overflow); | |
| 2173 | riscv_util.writeInstI(code[r_offset..][0..4], disp); | |
| 2174 | }, | |
| 2175 | ||
| 2176 | else => try atom.reportUnhandledRelocError(rel, elf_file), | |
| 2177 | }, | |
| 2118 | else => try atom.reportUnhandledRelocError(rel, elf_file), | |
| 2178 | 2119 | } |
| 2179 | 2120 | } |
| 2180 | 2121 | |
| ... | ... | @@ -2194,7 +2135,7 @@ const riscv = struct { |
| 2194 | 2135 | const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow; |
| 2195 | 2136 | const cwriter = stream.writer(); |
| 2196 | 2137 | |
| 2197 | _, const A, const S, const GOT, _, _, const DTP, _ = args; | |
| 2138 | _, const A, const S, const GOT, _, _, const DTP = args; | |
| 2198 | 2139 | _ = GOT; |
| 2199 | 2140 | _ = DTP; |
| 2200 | 2141 | |
| ... | ... | @@ -2230,7 +2171,7 @@ const riscv = struct { |
| 2230 | 2171 | const riscv_util = @import("../riscv.zig"); |
| 2231 | 2172 | }; |
| 2232 | 2173 | |
| 2233 | const ResolveArgs = struct { i64, i64, i64, i64, i64, i64, i64, i64 }; | |
| 2174 | const ResolveArgs = struct { i64, i64, i64, i64, i64, i64, i64 }; | |
| 2234 | 2175 | |
| 2235 | 2176 | const RelocError = error{ |
| 2236 | 2177 | Overflow, |
src/link/Elf/Symbol.zig+22-30| ... | ... | @@ -101,7 +101,7 @@ pub fn symbolRank(symbol: Symbol, elf_file: *Elf) u32 { |
| 101 | 101 | return file_ptr.symbolRank(sym, in_archive); |
| 102 | 102 | } |
| 103 | 103 | |
| 104 | pub fn address(symbol: Symbol, opts: struct { plt: bool = true }, elf_file: *Elf) i64 { | |
| 104 | pub fn address(symbol: Symbol, opts: struct { plt: bool = true, trampoline: bool = true }, elf_file: *Elf) i64 { | |
| 105 | 105 | if (symbol.mergeSubsection(elf_file)) |msub| { |
| 106 | 106 | if (!msub.alive) return 0; |
| 107 | 107 | return msub.address(elf_file) + symbol.value; |
| ... | ... | @@ -109,6 +109,9 @@ pub fn address(symbol: Symbol, opts: struct { plt: bool = true }, elf_file: *Elf |
| 109 | 109 | if (symbol.flags.has_copy_rel) { |
| 110 | 110 | return symbol.copyRelAddress(elf_file); |
| 111 | 111 | } |
| 112 | if (symbol.flags.has_trampoline and opts.trampoline) { | |
| 113 | return symbol.trampolineAddress(elf_file); | |
| 114 | } | |
| 112 | 115 | if (symbol.flags.has_plt and opts.plt) { |
| 113 | 116 | if (!symbol.flags.is_canonical and symbol.flags.has_got) { |
| 114 | 117 | // We have a non-lazy bound function pointer, use that! |
| ... | ... | @@ -217,23 +220,11 @@ pub fn tlsDescAddress(symbol: Symbol, elf_file: *Elf) i64 { |
| 217 | 220 | return entry.address(elf_file); |
| 218 | 221 | } |
| 219 | 222 | |
| 220 | const GetOrCreateZigGotEntryResult = struct { | |
| 221 | found_existing: bool, | |
| 222 | index: ZigGotSection.Index, | |
| 223 | }; | |
| 224 | ||
| 225 | pub fn getOrCreateZigGotEntry(symbol: *Symbol, symbol_index: Index, elf_file: *Elf) !GetOrCreateZigGotEntryResult { | |
| 226 | assert(!elf_file.base.isRelocatable()); | |
| 227 | assert(symbol.flags.needs_zig_got); | |
| 228 | if (symbol.flags.has_zig_got) return .{ .found_existing = true, .index = symbol.extra(elf_file).zig_got }; | |
| 229 | const index = try elf_file.zig_got.addSymbol(symbol_index, elf_file); | |
| 230 | return .{ .found_existing = false, .index = index }; | |
| 231 | } | |
| 232 | ||
| 233 | pub fn zigGotAddress(symbol: Symbol, elf_file: *Elf) i64 { | |
| 234 | if (!symbol.flags.has_zig_got) return 0; | |
| 235 | const extras = symbol.extra(elf_file); | |
| 236 | return elf_file.zig_got.entryAddress(extras.zig_got, elf_file); | |
| 223 | pub fn trampolineAddress(symbol: Symbol, elf_file: *Elf) i64 { | |
| 224 | if (!symbol.flags.has_trampoline) return 0; | |
| 225 | const zo = elf_file.zigObjectPtr().?; | |
| 226 | const index = symbol.extra(elf_file).trampoline; | |
| 227 | return zo.symbol(index).address(.{}, elf_file); | |
| 237 | 228 | } |
| 238 | 229 | |
| 239 | 230 | pub fn dsoAlignment(symbol: Symbol, elf_file: *Elf) !u64 { |
| ... | ... | @@ -259,7 +250,7 @@ const AddExtraOpts = struct { |
| 259 | 250 | tlsgd: ?u32 = null, |
| 260 | 251 | gottp: ?u32 = null, |
| 261 | 252 | tlsdesc: ?u32 = null, |
| 262 | zig_got: ?u32 = null, | |
| 253 | trampoline: ?u32 = null, | |
| 263 | 254 | }; |
| 264 | 255 | |
| 265 | 256 | pub fn addExtra(symbol: *Symbol, opts: AddExtraOpts, elf_file: *Elf) void { |
| ... | ... | @@ -312,7 +303,7 @@ pub fn setOutputSym(symbol: Symbol, elf_file: *Elf, out: *elf.Elf64_Sym) void { |
| 312 | 303 | const shdr = elf_file.shdrs.items[st_shndx]; |
| 313 | 304 | if (shdr.sh_flags & elf.SHF_TLS != 0 and file_ptr != .linker_defined) |
| 314 | 305 | break :blk symbol.address(.{ .plt = false }, elf_file) - elf_file.tlsAddress(); |
| 315 | break :blk symbol.address(.{ .plt = false }, elf_file); | |
| 306 | break :blk symbol.address(.{ .plt = false, .trampoline = false }, elf_file); | |
| 316 | 307 | }; |
| 317 | 308 | out.st_info = (st_bind << 4) | st_type; |
| 318 | 309 | out.st_other = esym.st_other; |
| ... | ... | @@ -331,7 +322,7 @@ pub fn format( |
| 331 | 322 | _ = unused_fmt_string; |
| 332 | 323 | _ = options; |
| 333 | 324 | _ = writer; |
| 334 | @compileError("do not format symbols directly"); | |
| 325 | @compileError("do not format Symbol directly"); | |
| 335 | 326 | } |
| 336 | 327 | |
| 337 | 328 | const FormatContext = struct { |
| ... | ... | @@ -388,7 +379,7 @@ fn format2( |
| 388 | 379 | try writer.print("%{d} : {s} : @{x}", .{ |
| 389 | 380 | symbol.esym_index, |
| 390 | 381 | symbol.fmtName(elf_file), |
| 391 | symbol.address(.{}, elf_file), | |
| 382 | symbol.address(.{ .plt = false, .trampoline = false }, elf_file), | |
| 392 | 383 | }); |
| 393 | 384 | if (symbol.file(elf_file)) |file_ptr| { |
| 394 | 385 | if (symbol.isAbs(elf_file)) { |
| ... | ... | @@ -456,17 +447,18 @@ pub const Flags = packed struct { |
| 456 | 447 | needs_tlsdesc: bool = false, |
| 457 | 448 | has_tlsdesc: bool = false, |
| 458 | 449 | |
| 459 | /// Whether the symbol contains .zig.got indirection. | |
| 460 | needs_zig_got: bool = false, | |
| 461 | has_zig_got: bool = false, | |
| 450 | /// Whether the symbol is a merge subsection. | |
| 451 | merge_subsection: bool = false, | |
| 452 | ||
| 453 | /// ZigObject specific flags | |
| 454 | /// Whether the symbol has a trampoline. | |
| 455 | has_trampoline: bool = false, | |
| 462 | 456 | |
| 463 | 457 | /// Whether the symbol is a TLS variable. |
| 464 | /// TODO this is really not needed if only we operated on esyms between | |
| 465 | /// codegen and ZigObject. | |
| 466 | 458 | is_tls: bool = false, |
| 467 | 459 | |
| 468 | /// Whether the symbol is a merge subsection. | |
| 469 | merge_subsection: bool = false, | |
| 460 | /// Whether the symbol is an extern pointer (as opposed to function). | |
| 461 | is_extern_ptr: bool = false, | |
| 470 | 462 | }; |
| 471 | 463 | |
| 472 | 464 | pub const Extra = struct { |
| ... | ... | @@ -479,8 +471,8 @@ pub const Extra = struct { |
| 479 | 471 | tlsgd: u32 = 0, |
| 480 | 472 | gottp: u32 = 0, |
| 481 | 473 | tlsdesc: u32 = 0, |
| 482 | zig_got: u32 = 0, | |
| 483 | 474 | merge_section: u32 = 0, |
| 475 | trampoline: u32 = 0, | |
| 484 | 476 | }; |
| 485 | 477 | |
| 486 | 478 | pub const Index = u32; |
src/link/Elf/ZigObject.zig+180-55| ... | ... | @@ -102,23 +102,17 @@ pub fn deinit(self: *ZigObject, allocator: Allocator) void { |
| 102 | 102 | } |
| 103 | 103 | self.relocs.deinit(allocator); |
| 104 | 104 | |
| 105 | { | |
| 106 | var it = self.navs.iterator(); | |
| 107 | while (it.next()) |entry| { | |
| 108 | entry.value_ptr.exports.deinit(allocator); | |
| 109 | } | |
| 110 | self.navs.deinit(allocator); | |
| 105 | for (self.navs.values()) |*meta| { | |
| 106 | meta.exports.deinit(allocator); | |
| 111 | 107 | } |
| 108 | self.navs.deinit(allocator); | |
| 112 | 109 | |
| 113 | 110 | self.lazy_syms.deinit(allocator); |
| 114 | 111 | |
| 115 | { | |
| 116 | var it = self.uavs.iterator(); | |
| 117 | while (it.next()) |entry| { | |
| 118 | entry.value_ptr.exports.deinit(allocator); | |
| 119 | } | |
| 120 | self.uavs.deinit(allocator); | |
| 112 | for (self.uavs.values()) |*meta| { | |
| 113 | meta.exports.deinit(allocator); | |
| 121 | 114 | } |
| 115 | self.uavs.deinit(allocator); | |
| 122 | 116 | |
| 123 | 117 | for (self.tls_variables.values()) |*tlv| { |
| 124 | 118 | tlv.deinit(allocator); |
| ... | ... | @@ -161,6 +155,16 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi |
| 161 | 155 | if (metadata.rodata_state != .unused) metadata.rodata_state = .flushed; |
| 162 | 156 | } |
| 163 | 157 | |
| 158 | if (build_options.enable_logging) { | |
| 159 | const pt: Zcu.PerThread = .{ .zcu = elf_file.base.comp.module.?, .tid = tid }; | |
| 160 | for (self.navs.keys(), self.navs.values()) |nav_index, meta| { | |
| 161 | checkNavAllocated(pt, nav_index, meta); | |
| 162 | } | |
| 163 | for (self.uavs.keys(), self.uavs.values()) |uav_index, meta| { | |
| 164 | checkUavAllocated(pt, uav_index, meta); | |
| 165 | } | |
| 166 | } | |
| 167 | ||
| 164 | 168 | if (self.dwarf) |*dw| { |
| 165 | 169 | const pt: Zcu.PerThread = .{ .zcu = elf_file.base.comp.module.?, .tid = tid }; |
| 166 | 170 | try dw.flushModule(pt); |
| ... | ... | @@ -698,6 +702,7 @@ pub fn lowerUav( |
| 698 | 702 | else => explicit_alignment, |
| 699 | 703 | }; |
| 700 | 704 | if (self.uavs.get(uav)) |metadata| { |
| 705 | assert(metadata.allocated); | |
| 701 | 706 | const sym = self.symbol(metadata.symbol_index); |
| 702 | 707 | const existing_alignment = sym.atom(elf_file).?.alignment; |
| 703 | 708 | if (uav_alignment.order(existing_alignment).compare(.lte)) |
| ... | ... | @@ -729,7 +734,7 @@ pub fn lowerUav( |
| 729 | 734 | .ok => |sym_index| sym_index, |
| 730 | 735 | .fail => |em| return .{ .fail = em }, |
| 731 | 736 | }; |
| 732 | try self.uavs.put(gpa, uav, .{ .symbol_index = sym_index }); | |
| 737 | try self.uavs.put(gpa, uav, .{ .symbol_index = sym_index, .allocated = true }); | |
| 733 | 738 | return .{ .mcv = .{ .load_symbol = sym_index } }; |
| 734 | 739 | } |
| 735 | 740 | |
| ... | ... | @@ -747,13 +752,7 @@ pub fn getOrCreateMetadataForLazySymbol( |
| 747 | 752 | .const_data => .{ &gop.value_ptr.rodata_symbol_index, &gop.value_ptr.rodata_state }, |
| 748 | 753 | }; |
| 749 | 754 | switch (state_ptr.*) { |
| 750 | .unused => { | |
| 751 | const gpa = elf_file.base.comp.gpa; | |
| 752 | const symbol_index = try self.newSymbolWithAtom(gpa, 0); | |
| 753 | const sym = self.symbol(symbol_index); | |
| 754 | sym.flags.needs_zig_got = true; | |
| 755 | symbol_index_ptr.* = symbol_index; | |
| 756 | }, | |
| 755 | .unused => symbol_index_ptr.* = try self.newSymbolWithAtom(pt.zcu.gpa, 0), | |
| 757 | 756 | .pending_flush => return symbol_index_ptr.*, |
| 758 | 757 | .flushed => {}, |
| 759 | 758 | } |
| ... | ... | @@ -807,9 +806,6 @@ pub fn getOrCreateMetadataForNav( |
| 807 | 806 | sym.flags.is_tls = true; |
| 808 | 807 | } |
| 809 | 808 | } |
| 810 | if (!sym.flags.is_tls) { | |
| 811 | sym.flags.needs_zig_got = true; | |
| 812 | } | |
| 813 | 809 | gop.value_ptr.* = .{ .symbol_index = symbol_index }; |
| 814 | 810 | } |
| 815 | 811 | return gop.value_ptr.symbol_index; |
| ... | ... | @@ -820,9 +816,9 @@ fn getNavShdrIndex( |
| 820 | 816 | elf_file: *Elf, |
| 821 | 817 | zcu: *Zcu, |
| 822 | 818 | nav_index: InternPool.Nav.Index, |
| 819 | sym_index: Symbol.Index, | |
| 823 | 820 | code: []const u8, |
| 824 | 821 | ) error{OutOfMemory}!u32 { |
| 825 | _ = self; | |
| 826 | 822 | const ip = &zcu.intern_pool; |
| 827 | 823 | const any_non_single_threaded = elf_file.base.comp.config.any_non_single_threaded; |
| 828 | 824 | const nav_val = zcu.navValue(nav_index); |
| ... | ... | @@ -832,10 +828,12 @@ fn getNavShdrIndex( |
| 832 | 828 | .@"extern" => |@"extern"| .{ @"extern".is_const, @"extern".is_threadlocal, .none }, |
| 833 | 829 | else => .{ true, false, nav_val.toIntern() }, |
| 834 | 830 | }; |
| 831 | const has_relocs = self.symbol(sym_index).atom(elf_file).?.relocs(elf_file).len > 0; | |
| 835 | 832 | if (any_non_single_threaded and is_threadlocal) { |
| 836 | for (code) |byte| { | |
| 837 | if (byte != 0) break; | |
| 838 | } else return elf_file.sectionByName(".tbss") orelse try elf_file.addSection(.{ | |
| 833 | const is_bss = !has_relocs and for (code) |byte| { | |
| 834 | if (byte != 0) break false; | |
| 835 | } else true; | |
| 836 | if (is_bss) return elf_file.sectionByName(".tbss") orelse try elf_file.addSection(.{ | |
| 839 | 837 | .type = elf.SHT_NOBITS, |
| 840 | 838 | .flags = elf.SHF_ALLOC | elf.SHF_WRITE | elf.SHF_TLS, |
| 841 | 839 | .name = try elf_file.insertShString(".tbss"), |
| ... | ... | @@ -854,9 +852,10 @@ fn getNavShdrIndex( |
| 854 | 852 | .Debug, .ReleaseSafe => elf_file.zig_data_section_index.?, |
| 855 | 853 | .ReleaseFast, .ReleaseSmall => elf_file.zig_bss_section_index.?, |
| 856 | 854 | }; |
| 857 | for (code) |byte| { | |
| 858 | if (byte != 0) break; | |
| 859 | } else return elf_file.zig_bss_section_index.?; | |
| 855 | const is_bss = !has_relocs and for (code) |byte| { | |
| 856 | if (byte != 0) break false; | |
| 857 | } else true; | |
| 858 | if (is_bss) return elf_file.zig_bss_section_index.?; | |
| 860 | 859 | return elf_file.zig_data_section_index.?; |
| 861 | 860 | } |
| 862 | 861 | |
| ... | ... | @@ -909,13 +908,6 @@ fn updateNavCode( |
| 909 | 908 | if (old_vaddr != atom_ptr.value) { |
| 910 | 909 | sym.value = 0; |
| 911 | 910 | esym.st_value = 0; |
| 912 | ||
| 913 | if (!elf_file.base.isRelocatable()) { | |
| 914 | log.debug(" (writing new offset table entry)", .{}); | |
| 915 | assert(sym.flags.has_zig_got); | |
| 916 | const extra = sym.extra(elf_file); | |
| 917 | try elf_file.zig_got.writeOne(elf_file, extra.zig_got); | |
| 918 | } | |
| 919 | 911 | } |
| 920 | 912 | } else if (code.len < old_size) { |
| 921 | 913 | atom_ptr.shrink(elf_file); |
| ... | ... | @@ -925,15 +917,11 @@ fn updateNavCode( |
| 925 | 917 | errdefer self.freeNavMetadata(elf_file, sym_index); |
| 926 | 918 | |
| 927 | 919 | sym.value = 0; |
| 928 | sym.flags.needs_zig_got = true; | |
| 929 | 920 | esym.st_value = 0; |
| 930 | ||
| 931 | if (!elf_file.base.isRelocatable()) { | |
| 932 | const gop = try sym.getOrCreateZigGotEntry(sym_index, elf_file); | |
| 933 | try elf_file.zig_got.writeOne(elf_file, gop.index); | |
| 934 | } | |
| 935 | 921 | } |
| 936 | 922 | |
| 923 | self.navs.getPtr(nav_index).?.allocated = true; | |
| 924 | ||
| 937 | 925 | if (elf_file.base.child_pid) |pid| { |
| 938 | 926 | switch (builtin.os.tag) { |
| 939 | 927 | .linux => { |
| ... | ... | @@ -959,6 +947,7 @@ fn updateNavCode( |
| 959 | 947 | if (shdr.sh_type != elf.SHT_NOBITS) { |
| 960 | 948 | const file_offset = shdr.sh_offset + @as(u64, @intCast(atom_ptr.value)); |
| 961 | 949 | try elf_file.base.file.?.pwriteAll(code, file_offset); |
| 950 | log.debug("writing {} from 0x{x} to 0x{x}", .{ nav.fqn.fmt(ip), file_offset, file_offset + code.len }); | |
| 962 | 951 | } |
| 963 | 952 | } |
| 964 | 953 | |
| ... | ... | @@ -1001,6 +990,8 @@ fn updateTlv( |
| 1001 | 990 | atom_ptr.alignment = required_alignment; |
| 1002 | 991 | atom_ptr.size = code.len; |
| 1003 | 992 | |
| 993 | self.navs.getPtr(nav_index).?.allocated = true; | |
| 994 | ||
| 1004 | 995 | { |
| 1005 | 996 | const gop = try self.tls_variables.getOrPut(gpa, atom_ptr.atom_index); |
| 1006 | 997 | assert(!gop.found_existing); // TODO incremental updates |
| ... | ... | @@ -1065,8 +1056,21 @@ pub fn updateFunc( |
| 1065 | 1056 | }, |
| 1066 | 1057 | }; |
| 1067 | 1058 | |
| 1068 | const shndx = try self.getNavShdrIndex(elf_file, zcu, func.owner_nav, code); | |
| 1059 | const shndx = try self.getNavShdrIndex(elf_file, zcu, func.owner_nav, sym_index, code); | |
| 1060 | log.debug("setting shdr({x},{s}) for {}", .{ | |
| 1061 | shndx, | |
| 1062 | elf_file.getShString(elf_file.shdrs.items[shndx].sh_name), | |
| 1063 | ip.getNav(func.owner_nav).fqn.fmt(ip), | |
| 1064 | }); | |
| 1065 | const old_rva, const old_alignment = blk: { | |
| 1066 | const atom_ptr = self.symbol(sym_index).atom(elf_file).?; | |
| 1067 | break :blk .{ atom_ptr.value, atom_ptr.alignment }; | |
| 1068 | }; | |
| 1069 | 1069 | try self.updateNavCode(elf_file, pt, func.owner_nav, sym_index, shndx, code, elf.STT_FUNC); |
| 1070 | const new_rva, const new_alignment = blk: { | |
| 1071 | const atom_ptr = self.symbol(sym_index).atom(elf_file).?; | |
| 1072 | break :blk .{ atom_ptr.value, atom_ptr.alignment }; | |
| 1073 | }; | |
| 1070 | 1074 | |
| 1071 | 1075 | if (dwarf_state) |*ds| { |
| 1072 | 1076 | const sym = self.symbol(sym_index); |
| ... | ... | @@ -1080,6 +1084,41 @@ pub fn updateFunc( |
| 1080 | 1084 | } |
| 1081 | 1085 | |
| 1082 | 1086 | // Exports will be updated by `Zcu.processExports` after the update. |
| 1087 | ||
| 1088 | if (old_rva != new_rva and old_rva > 0) { | |
| 1089 | // If we had to reallocate the function, we re-use the existing slot for a trampoline. | |
| 1090 | // In the rare case that the function has been further overaligned we skip creating a | |
| 1091 | // trampoline and update all symbols referring this function. | |
| 1092 | if (old_alignment.order(new_alignment) == .lt) { | |
| 1093 | @panic("TODO update all symbols referring this function"); | |
| 1094 | } | |
| 1095 | ||
| 1096 | // Create a trampoline to the new location at `old_rva`. | |
| 1097 | if (!self.symbol(sym_index).flags.has_trampoline) { | |
| 1098 | const name = try std.fmt.allocPrint(gpa, "{s}$trampoline", .{ | |
| 1099 | self.symbol(sym_index).name(elf_file), | |
| 1100 | }); | |
| 1101 | defer gpa.free(name); | |
| 1102 | const name_off = try self.addString(gpa, name); | |
| 1103 | const tr_size = trampolineSize(elf_file.getTarget().cpu.arch); | |
| 1104 | const tr_sym_index = try self.newSymbolWithAtom(gpa, name_off); | |
| 1105 | const tr_sym = self.symbol(tr_sym_index); | |
| 1106 | const tr_esym = &self.symtab.items(.elf_sym)[tr_sym.esym_index]; | |
| 1107 | tr_esym.st_info |= elf.STT_OBJECT; | |
| 1108 | tr_esym.st_size = tr_size; | |
| 1109 | const tr_atom_ptr = tr_sym.atom(elf_file).?; | |
| 1110 | tr_atom_ptr.value = old_rva; | |
| 1111 | tr_atom_ptr.alive = true; | |
| 1112 | tr_atom_ptr.alignment = old_alignment; | |
| 1113 | tr_atom_ptr.output_section_index = elf_file.zig_text_section_index.?; | |
| 1114 | tr_atom_ptr.size = tr_size; | |
| 1115 | const target_sym = self.symbol(sym_index); | |
| 1116 | target_sym.addExtra(.{ .trampoline = tr_sym_index }, elf_file); | |
| 1117 | target_sym.flags.has_trampoline = true; | |
| 1118 | } | |
| 1119 | const target_sym = self.symbol(sym_index); | |
| 1120 | try writeTrampoline(self.symbol(target_sym.extra(elf_file).trampoline).*, target_sym.*, elf_file); | |
| 1121 | } | |
| 1083 | 1122 | } |
| 1084 | 1123 | |
| 1085 | 1124 | pub fn updateNav( |
| ... | ... | @@ -1102,13 +1141,12 @@ pub fn updateNav( |
| 1102 | 1141 | .variable => |variable| Value.fromInterned(variable.init), |
| 1103 | 1142 | .@"extern" => |@"extern"| { |
| 1104 | 1143 | if (ip.isFunctionType(@"extern".ty)) return; |
| 1105 | // Extern variable gets a .got entry only. | |
| 1106 | 1144 | const sym_index = try self.getGlobalSymbol( |
| 1107 | 1145 | elf_file, |
| 1108 | 1146 | nav.name.toSlice(ip), |
| 1109 | 1147 | @"extern".lib_name.toSlice(ip), |
| 1110 | 1148 | ); |
| 1111 | self.symbol(sym_index).flags.needs_got = true; | |
| 1149 | self.symbol(sym_index).flags.is_extern_ptr = true; | |
| 1112 | 1150 | return; |
| 1113 | 1151 | }, |
| 1114 | 1152 | else => nav_val, |
| ... | ... | @@ -1142,7 +1180,12 @@ pub fn updateNav( |
| 1142 | 1180 | }, |
| 1143 | 1181 | }; |
| 1144 | 1182 | |
| 1145 | const shndx = try self.getNavShdrIndex(elf_file, zcu, nav_index, code); | |
| 1183 | const shndx = try self.getNavShdrIndex(elf_file, zcu, nav_index, sym_index, code); | |
| 1184 | log.debug("setting shdr({x},{s}) for {}", .{ | |
| 1185 | shndx, | |
| 1186 | elf_file.getShString(elf_file.shdrs.items[shndx].sh_name), | |
| 1187 | nav.fqn.fmt(ip), | |
| 1188 | }); | |
| 1146 | 1189 | if (elf_file.shdrs.items[shndx].sh_flags & elf.SHF_TLS != 0) |
| 1147 | 1190 | try self.updateTlv(elf_file, pt, nav_index, sym_index, shndx, code) |
| 1148 | 1191 | else |
| ... | ... | @@ -1225,14 +1268,8 @@ fn updateLazySymbol( |
| 1225 | 1268 | errdefer self.freeNavMetadata(elf_file, symbol_index); |
| 1226 | 1269 | |
| 1227 | 1270 | local_sym.value = 0; |
| 1228 | local_sym.flags.needs_zig_got = true; | |
| 1229 | 1271 | local_esym.st_value = 0; |
| 1230 | 1272 | |
| 1231 | if (!elf_file.base.isRelocatable()) { | |
| 1232 | const gop = try local_sym.getOrCreateZigGotEntry(symbol_index, elf_file); | |
| 1233 | try elf_file.zig_got.writeOne(elf_file, gop.index); | |
| 1234 | } | |
| 1235 | ||
| 1236 | 1273 | const shdr = elf_file.shdrs.items[output_section_index]; |
| 1237 | 1274 | const file_offset = shdr.sh_offset + @as(u64, @intCast(atom_ptr.value)); |
| 1238 | 1275 | try elf_file.base.file.?.pwriteAll(code, file_offset); |
| ... | ... | @@ -1440,6 +1477,52 @@ pub fn getGlobalSymbol(self: *ZigObject, elf_file: *Elf, name: []const u8, lib_n |
| 1440 | 1477 | return lookup_gop.value_ptr.*; |
| 1441 | 1478 | } |
| 1442 | 1479 | |
| 1480 | const max_trampoline_len = 12; | |
| 1481 | ||
| 1482 | fn trampolineSize(cpu_arch: std.Target.Cpu.Arch) u64 { | |
| 1483 | const len = switch (cpu_arch) { | |
| 1484 | .x86_64 => 5, // jmp rel32 | |
| 1485 | else => @panic("TODO implement trampoline size for this CPU arch"), | |
| 1486 | }; | |
| 1487 | comptime assert(len <= max_trampoline_len); | |
| 1488 | return len; | |
| 1489 | } | |
| 1490 | ||
| 1491 | fn writeTrampoline(tr_sym: Symbol, target: Symbol, elf_file: *Elf) !void { | |
| 1492 | const atom_ptr = tr_sym.atom(elf_file).?; | |
| 1493 | const shdr = elf_file.shdrs.items[atom_ptr.output_section_index]; | |
| 1494 | const fileoff = shdr.sh_offset + @as(u64, @intCast(atom_ptr.value)); | |
| 1495 | const source_addr = tr_sym.address(.{}, elf_file); | |
| 1496 | const target_addr = target.address(.{ .trampoline = false }, elf_file); | |
| 1497 | var buf: [max_trampoline_len]u8 = undefined; | |
| 1498 | const out = switch (elf_file.getTarget().cpu.arch) { | |
| 1499 | .x86_64 => try x86_64.writeTrampolineCode(source_addr, target_addr, &buf), | |
| 1500 | else => @panic("TODO implement write trampoline for this CPU arch"), | |
| 1501 | }; | |
| 1502 | try elf_file.base.file.?.pwriteAll(out, fileoff); | |
| 1503 | ||
| 1504 | if (elf_file.base.child_pid) |pid| { | |
| 1505 | switch (builtin.os.tag) { | |
| 1506 | .linux => { | |
| 1507 | var local_vec: [1]std.posix.iovec_const = .{.{ | |
| 1508 | .base = out.ptr, | |
| 1509 | .len = out.len, | |
| 1510 | }}; | |
| 1511 | var remote_vec: [1]std.posix.iovec_const = .{.{ | |
| 1512 | .base = @as([*]u8, @ptrFromInt(@as(usize, @intCast(source_addr)))), | |
| 1513 | .len = out.len, | |
| 1514 | }}; | |
| 1515 | const rc = std.os.linux.process_vm_writev(pid, &local_vec, &remote_vec, 0); | |
| 1516 | switch (std.os.linux.E.init(rc)) { | |
| 1517 | .SUCCESS => assert(rc == out.len), | |
| 1518 | else => |errno| log.warn("process_vm_writev failure: {s}", .{@tagName(errno)}), | |
| 1519 | } | |
| 1520 | }, | |
| 1521 | else => return error.HotSwapUnavailableOnHostOperatingSystem, | |
| 1522 | } | |
| 1523 | } | |
| 1524 | } | |
| 1525 | ||
| 1443 | 1526 | pub fn asFile(self: *ZigObject) File { |
| 1444 | 1527 | return .{ .zig_object = self }; |
| 1445 | 1528 | } |
| ... | ... | @@ -1662,6 +1745,8 @@ const AvMetadata = struct { |
| 1662 | 1745 | symbol_index: Symbol.Index, |
| 1663 | 1746 | /// A list of all exports aliases of this Av. |
| 1664 | 1747 | exports: std.ArrayListUnmanaged(Symbol.Index) = .{}, |
| 1748 | /// Set to true if the AV has been initialized and allocated. | |
| 1749 | allocated: bool = false, | |
| 1665 | 1750 | |
| 1666 | 1751 | fn @"export"(m: AvMetadata, zig_object: *ZigObject, name: []const u8) ?*u32 { |
| 1667 | 1752 | for (m.exports.items) |*exp| { |
| ... | ... | @@ -1672,6 +1757,32 @@ const AvMetadata = struct { |
| 1672 | 1757 | } |
| 1673 | 1758 | }; |
| 1674 | 1759 | |
| 1760 | fn checkNavAllocated(pt: Zcu.PerThread, index: InternPool.Nav.Index, meta: AvMetadata) void { | |
| 1761 | if (!meta.allocated) { | |
| 1762 | const zcu = pt.zcu; | |
| 1763 | const ip = &zcu.intern_pool; | |
| 1764 | const nav = ip.getNav(index); | |
| 1765 | log.err("NAV {}({d}) assigned symbol {d} but not allocated!", .{ | |
| 1766 | nav.fqn.fmt(ip), | |
| 1767 | index, | |
| 1768 | meta.symbol_index, | |
| 1769 | }); | |
| 1770 | } | |
| 1771 | } | |
| 1772 | ||
| 1773 | fn checkUavAllocated(pt: Zcu.PerThread, index: InternPool.Index, meta: AvMetadata) void { | |
| 1774 | if (!meta.allocated) { | |
| 1775 | const zcu = pt.zcu; | |
| 1776 | const uav = Value.fromInterned(index); | |
| 1777 | const ty = uav.typeOf(zcu); | |
| 1778 | log.err("UAV {}({d}) assigned symbol {d} but not allocated!", .{ | |
| 1779 | ty.fmt(pt), | |
| 1780 | index, | |
| 1781 | meta.symbol_index, | |
| 1782 | }); | |
| 1783 | } | |
| 1784 | } | |
| 1785 | ||
| 1675 | 1786 | const TlsVariable = struct { |
| 1676 | 1787 | symbol_index: Symbol.Index, |
| 1677 | 1788 | code: []const u8 = &[0]u8{}, |
| ... | ... | @@ -1682,12 +1793,26 @@ const TlsVariable = struct { |
| 1682 | 1793 | }; |
| 1683 | 1794 | |
| 1684 | 1795 | const AtomList = std.ArrayListUnmanaged(Atom.Index); |
| 1685 | const NavTable = std.AutoHashMapUnmanaged(InternPool.Nav.Index, AvMetadata); | |
| 1686 | const UavTable = std.AutoHashMapUnmanaged(InternPool.Index, AvMetadata); | |
| 1796 | const NavTable = std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, AvMetadata); | |
| 1797 | const UavTable = std.AutoArrayHashMapUnmanaged(InternPool.Index, AvMetadata); | |
| 1687 | 1798 | const LazySymbolTable = std.AutoArrayHashMapUnmanaged(InternPool.Index, LazySymbolMetadata); |
| 1688 | 1799 | const TlsTable = std.AutoArrayHashMapUnmanaged(Atom.Index, TlsVariable); |
| 1689 | 1800 | |
| 1801 | const x86_64 = struct { | |
| 1802 | fn writeTrampolineCode(source_addr: i64, target_addr: i64, buf: *[max_trampoline_len]u8) ![]u8 { | |
| 1803 | const disp = @as(i64, @intCast(target_addr)) - source_addr - 5; | |
| 1804 | var bytes = [_]u8{ | |
| 1805 | 0xe9, 0x00, 0x00, 0x00, 0x00, // jmp rel32 | |
| 1806 | }; | |
| 1807 | assert(bytes.len == trampolineSize(.x86_64)); | |
| 1808 | mem.writeInt(i32, bytes[1..][0..4], @intCast(disp), .little); | |
| 1809 | @memcpy(buf[0..bytes.len], &bytes); | |
| 1810 | return buf[0..bytes.len]; | |
| 1811 | } | |
| 1812 | }; | |
| 1813 | ||
| 1690 | 1814 | const assert = std.debug.assert; |
| 1815 | const build_options = @import("build_options"); | |
| 1691 | 1816 | const builtin = @import("builtin"); |
| 1692 | 1817 | const codegen = @import("../../codegen.zig"); |
| 1693 | 1818 | const elf = std.elf; |
src/link/Elf/relocation.zig+5-13| ... | ... | @@ -112,19 +112,11 @@ fn formatRelocType( |
| 112 | 112 | _ = unused_fmt_string; |
| 113 | 113 | _ = options; |
| 114 | 114 | const r_type = ctx.r_type; |
| 115 | switch (r_type) { | |
| 116 | Elf.R_ZIG_GOT32 => try writer.writeAll("R_ZIG_GOT32"), | |
| 117 | Elf.R_ZIG_GOTPCREL => try writer.writeAll("R_ZIG_GOTPCREL"), | |
| 118 | Elf.R_ZIG_GOT_HI20 => try writer.writeAll("R_ZIG_GOT_HI20"), | |
| 119 | Elf.R_ZIG_GOT_LO12 => try writer.writeAll("R_ZIG_GOT_LO12"), | |
| 120 | Elf.R_GOT_HI20_STATIC => try writer.writeAll("R_GOT_HI20_STATIC"), | |
| 121 | Elf.R_GOT_LO12_I_STATIC => try writer.writeAll("R_GOT_LO12_I_STATIC"), | |
| 122 | else => switch (ctx.cpu_arch) { | |
| 123 | .x86_64 => try writer.print("R_X86_64_{s}", .{@tagName(@as(elf.R_X86_64, @enumFromInt(r_type)))}), | |
| 124 | .aarch64 => try writer.print("R_AARCH64_{s}", .{@tagName(@as(elf.R_AARCH64, @enumFromInt(r_type)))}), | |
| 125 | .riscv64 => try writer.print("R_RISCV_{s}", .{@tagName(@as(elf.R_RISCV, @enumFromInt(r_type)))}), | |
| 126 | else => unreachable, | |
| 127 | }, | |
| 115 | switch (ctx.cpu_arch) { | |
| 116 | .x86_64 => try writer.print("R_X86_64_{s}", .{@tagName(@as(elf.R_X86_64, @enumFromInt(r_type)))}), | |
| 117 | .aarch64 => try writer.print("R_AARCH64_{s}", .{@tagName(@as(elf.R_AARCH64, @enumFromInt(r_type)))}), | |
| 118 | .riscv64 => try writer.print("R_RISCV_{s}", .{@tagName(@as(elf.R_RISCV, @enumFromInt(r_type)))}), | |
| 119 | else => unreachable, | |
| 128 | 120 | } |
| 129 | 121 | } |
| 130 | 122 |
src/link/Elf/synthetic_sections.zig-209| ... | ... | @@ -223,215 +223,6 @@ pub const DynamicSection = struct { |
| 223 | 223 | } |
| 224 | 224 | }; |
| 225 | 225 | |
| 226 | pub const ZigGotSection = struct { | |
| 227 | entries: std.ArrayListUnmanaged(Symbol.Index) = .{}, | |
| 228 | output_symtab_ctx: Elf.SymtabCtx = .{}, | |
| 229 | flags: Flags = .{}, | |
| 230 | ||
| 231 | const Flags = packed struct { | |
| 232 | needs_rela: bool = false, | |
| 233 | dirty: bool = false, | |
| 234 | }; | |
| 235 | ||
| 236 | pub const Index = u32; | |
| 237 | ||
| 238 | pub fn deinit(zig_got: *ZigGotSection, allocator: Allocator) void { | |
| 239 | zig_got.entries.deinit(allocator); | |
| 240 | } | |
| 241 | ||
| 242 | fn allocateEntry(zig_got: *ZigGotSection, allocator: Allocator) !Index { | |
| 243 | try zig_got.entries.ensureUnusedCapacity(allocator, 1); | |
| 244 | // TODO add free list | |
| 245 | const index = @as(Index, @intCast(zig_got.entries.items.len)); | |
| 246 | _ = zig_got.entries.addOneAssumeCapacity(); | |
| 247 | zig_got.flags.dirty = true; | |
| 248 | return index; | |
| 249 | } | |
| 250 | ||
| 251 | pub fn addSymbol(zig_got: *ZigGotSection, sym_index: Symbol.Index, elf_file: *Elf) !Index { | |
| 252 | const comp = elf_file.base.comp; | |
| 253 | const gpa = comp.gpa; | |
| 254 | const zo = elf_file.zigObjectPtr().?; | |
| 255 | const index = try zig_got.allocateEntry(gpa); | |
| 256 | const entry = &zig_got.entries.items[index]; | |
| 257 | entry.* = sym_index; | |
| 258 | const symbol = zo.symbol(sym_index); | |
| 259 | symbol.flags.has_zig_got = true; | |
| 260 | if (elf_file.isEffectivelyDynLib() or (elf_file.base.isExe() and comp.config.pie)) { | |
| 261 | zig_got.flags.needs_rela = true; | |
| 262 | } | |
| 263 | symbol.addExtra(.{ .zig_got = index }, elf_file); | |
| 264 | return index; | |
| 265 | } | |
| 266 | ||
| 267 | pub fn entryOffset(zig_got: ZigGotSection, index: Index, elf_file: *Elf) u64 { | |
| 268 | _ = zig_got; | |
| 269 | const entry_size = elf_file.archPtrWidthBytes(); | |
| 270 | const shdr = elf_file.shdrs.items[elf_file.zig_got_section_index.?]; | |
| 271 | return shdr.sh_offset + @as(u64, entry_size) * index; | |
| 272 | } | |
| 273 | ||
| 274 | pub fn entryAddress(zig_got: ZigGotSection, index: Index, elf_file: *Elf) i64 { | |
| 275 | _ = zig_got; | |
| 276 | const entry_size = elf_file.archPtrWidthBytes(); | |
| 277 | const shdr = elf_file.shdrs.items[elf_file.zig_got_section_index.?]; | |
| 278 | return @as(i64, @intCast(shdr.sh_addr)) + entry_size * index; | |
| 279 | } | |
| 280 | ||
| 281 | pub fn size(zig_got: ZigGotSection, elf_file: *Elf) usize { | |
| 282 | return elf_file.archPtrWidthBytes() * zig_got.entries.items.len; | |
| 283 | } | |
| 284 | ||
| 285 | pub fn writeOne(zig_got: *ZigGotSection, elf_file: *Elf, index: Index) !void { | |
| 286 | const zo = elf_file.zigObjectPtr().?; | |
| 287 | if (zig_got.flags.dirty) { | |
| 288 | const needed_size = zig_got.size(elf_file); | |
| 289 | try elf_file.growAllocSection(elf_file.zig_got_section_index.?, needed_size); | |
| 290 | zig_got.flags.dirty = false; | |
| 291 | } | |
| 292 | const entry_size: u16 = elf_file.archPtrWidthBytes(); | |
| 293 | const target = elf_file.getTarget(); | |
| 294 | const endian = target.cpu.arch.endian(); | |
| 295 | const off = zig_got.entryOffset(index, elf_file); | |
| 296 | const vaddr: u64 = @intCast(zig_got.entryAddress(index, elf_file)); | |
| 297 | const entry = zig_got.entries.items[index]; | |
| 298 | const value = zo.symbol(entry).address(.{}, elf_file); | |
| 299 | switch (entry_size) { | |
| 300 | 2 => { | |
| 301 | var buf: [2]u8 = undefined; | |
| 302 | std.mem.writeInt(u16, &buf, @intCast(value), endian); | |
| 303 | try elf_file.base.file.?.pwriteAll(&buf, off); | |
| 304 | }, | |
| 305 | 4 => { | |
| 306 | var buf: [4]u8 = undefined; | |
| 307 | std.mem.writeInt(u32, &buf, @intCast(value), endian); | |
| 308 | try elf_file.base.file.?.pwriteAll(&buf, off); | |
| 309 | }, | |
| 310 | 8 => { | |
| 311 | var buf: [8]u8 = undefined; | |
| 312 | std.mem.writeInt(u64, &buf, @intCast(value), endian); | |
| 313 | try elf_file.base.file.?.pwriteAll(&buf, off); | |
| 314 | ||
| 315 | if (elf_file.base.child_pid) |pid| { | |
| 316 | switch (builtin.os.tag) { | |
| 317 | .linux => { | |
| 318 | var local_vec: [1]std.posix.iovec_const = .{.{ | |
| 319 | .base = &buf, | |
| 320 | .len = buf.len, | |
| 321 | }}; | |
| 322 | var remote_vec: [1]std.posix.iovec_const = .{.{ | |
| 323 | .base = @as([*]u8, @ptrFromInt(@as(usize, @intCast(vaddr)))), | |
| 324 | .len = buf.len, | |
| 325 | }}; | |
| 326 | const rc = std.os.linux.process_vm_writev(pid, &local_vec, &remote_vec, 0); | |
| 327 | switch (std.os.linux.E.init(rc)) { | |
| 328 | .SUCCESS => assert(rc == buf.len), | |
| 329 | else => |errno| log.warn("process_vm_writev failure: {s}", .{@tagName(errno)}), | |
| 330 | } | |
| 331 | }, | |
| 332 | else => return error.HotSwapUnavailableOnHostOperatingSystem, | |
| 333 | } | |
| 334 | } | |
| 335 | }, | |
| 336 | else => unreachable, | |
| 337 | } | |
| 338 | } | |
| 339 | ||
| 340 | pub fn writeAll(zig_got: ZigGotSection, elf_file: *Elf, writer: anytype) !void { | |
| 341 | const zo = elf_file.zigObjectPtr().?; | |
| 342 | for (zig_got.entries.items) |entry| { | |
| 343 | const symbol = zo.symbol(entry); | |
| 344 | const value = symbol.address(.{ .plt = false }, elf_file); | |
| 345 | try writeInt(value, elf_file, writer); | |
| 346 | } | |
| 347 | } | |
| 348 | ||
| 349 | pub fn numRela(zig_got: ZigGotSection) usize { | |
| 350 | return zig_got.entries.items.len; | |
| 351 | } | |
| 352 | ||
| 353 | pub fn addRela(zig_got: ZigGotSection, elf_file: *Elf) !void { | |
| 354 | const comp = elf_file.base.comp; | |
| 355 | const gpa = comp.gpa; | |
| 356 | const cpu_arch = elf_file.getTarget().cpu.arch; | |
| 357 | const zo = elf_file.zigObjectPtr().?; | |
| 358 | try elf_file.rela_dyn.ensureUnusedCapacity(gpa, zig_got.numRela()); | |
| 359 | for (zig_got.entries.items) |entry| { | |
| 360 | const symbol = zo.symbol(entry); | |
| 361 | const offset = symbol.zigGotAddress(elf_file); | |
| 362 | elf_file.addRelaDynAssumeCapacity(.{ | |
| 363 | .offset = @intCast(offset), | |
| 364 | .type = relocation.encode(.rel, cpu_arch), | |
| 365 | .addend = symbol.address(.{ .plt = false }, elf_file), | |
| 366 | }); | |
| 367 | } | |
| 368 | } | |
| 369 | ||
| 370 | pub fn updateSymtabSize(zig_got: *ZigGotSection, elf_file: *Elf) void { | |
| 371 | const zo = elf_file.zigObjectPtr().?; | |
| 372 | zig_got.output_symtab_ctx.nlocals = @as(u32, @intCast(zig_got.entries.items.len)); | |
| 373 | for (zig_got.entries.items) |entry| { | |
| 374 | const name = zo.symbol(entry).name(elf_file); | |
| 375 | zig_got.output_symtab_ctx.strsize += @as(u32, @intCast(name.len + "$ziggot".len)) + 1; | |
| 376 | } | |
| 377 | } | |
| 378 | ||
| 379 | pub fn writeSymtab(zig_got: ZigGotSection, elf_file: *Elf) void { | |
| 380 | const zo = elf_file.zigObjectPtr().?; | |
| 381 | for (zig_got.entries.items, zig_got.output_symtab_ctx.ilocal.., 0..) |entry, ilocal, index| { | |
| 382 | const symbol = zo.symbol(entry); | |
| 383 | const symbol_name = symbol.name(elf_file); | |
| 384 | const st_name = @as(u32, @intCast(elf_file.strtab.items.len)); | |
| 385 | elf_file.strtab.appendSliceAssumeCapacity(symbol_name); | |
| 386 | elf_file.strtab.appendSliceAssumeCapacity("$ziggot"); | |
| 387 | elf_file.strtab.appendAssumeCapacity(0); | |
| 388 | const st_value = zig_got.entryAddress(@intCast(index), elf_file); | |
| 389 | const st_size = elf_file.archPtrWidthBytes(); | |
| 390 | elf_file.symtab.items[ilocal] = .{ | |
| 391 | .st_name = st_name, | |
| 392 | .st_info = elf.STT_OBJECT, | |
| 393 | .st_other = 0, | |
| 394 | .st_shndx = @intCast(elf_file.zig_got_section_index.?), | |
| 395 | .st_value = @intCast(st_value), | |
| 396 | .st_size = st_size, | |
| 397 | }; | |
| 398 | } | |
| 399 | } | |
| 400 | ||
| 401 | const FormatCtx = struct { | |
| 402 | zig_got: ZigGotSection, | |
| 403 | elf_file: *Elf, | |
| 404 | }; | |
| 405 | ||
| 406 | pub fn fmt(zig_got: ZigGotSection, elf_file: *Elf) std.fmt.Formatter(format2) { | |
| 407 | return .{ .data = .{ .zig_got = zig_got, .elf_file = elf_file } }; | |
| 408 | } | |
| 409 | ||
| 410 | pub fn format2( | |
| 411 | ctx: FormatCtx, | |
| 412 | comptime unused_fmt_string: []const u8, | |
| 413 | options: std.fmt.FormatOptions, | |
| 414 | writer: anytype, | |
| 415 | ) !void { | |
| 416 | _ = options; | |
| 417 | _ = unused_fmt_string; | |
| 418 | const zig_got = ctx.zig_got; | |
| 419 | const elf_file = ctx.elf_file; | |
| 420 | try writer.writeAll(".zig.got\n"); | |
| 421 | for (zig_got.entries.items, 0..) |entry, index| { | |
| 422 | const zo = elf_file.zigObjectPtr().?; | |
| 423 | const symbol = zo.symbol(entry); | |
| 424 | try writer.print(" {d}@0x{x} => {d}@0x{x} ({s})\n", .{ | |
| 425 | index, | |
| 426 | zig_got.entryAddress(@intCast(index), elf_file), | |
| 427 | entry, | |
| 428 | symbol.address(.{}, elf_file), | |
| 429 | symbol.name(elf_file), | |
| 430 | }); | |
| 431 | } | |
| 432 | } | |
| 433 | }; | |
| 434 | ||
| 435 | 226 | pub const GotSection = struct { |
| 436 | 227 | entries: std.ArrayListUnmanaged(Entry) = .{}, |
| 437 | 228 | output_symtab_ctx: Elf.SymtabCtx = .{}, |
test/behavior/basic.zig-1| ... | ... | @@ -733,7 +733,6 @@ test "extern variable with non-pointer opaque type" { |
| 733 | 733 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 734 | 734 | if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; |
| 735 | 735 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO |
| 736 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | |
| 737 | 736 | |
| 738 | 737 | @export(var_to_export, .{ .name = "opaque_extern_var" }); |
| 739 | 738 | try expect(@as(*align(1) u32, @ptrCast(&opaque_extern_var)).* == 42); |
test/behavior/export_builtin.zig-2| ... | ... | @@ -48,7 +48,6 @@ test "exporting using field access" { |
| 48 | 48 | test "exporting comptime-known value" { |
| 49 | 49 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; |
| 50 | 50 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 51 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | |
| 52 | 51 | if (builtin.zig_backend == .stage2_x86_64 and |
| 53 | 52 | (builtin.target.ofmt != .elf and |
| 54 | 53 | builtin.target.ofmt != .macho and |
| ... | ... | @@ -68,7 +67,6 @@ test "exporting comptime-known value" { |
| 68 | 67 | test "exporting comptime var" { |
| 69 | 68 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; |
| 70 | 69 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 71 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | |
| 72 | 70 | if (builtin.zig_backend == .stage2_x86_64 and |
| 73 | 71 | (builtin.target.ofmt != .elf and |
| 74 | 72 | builtin.target.ofmt != .macho and |
test/behavior/extern.zig-1| ... | ... | @@ -7,7 +7,6 @@ test "anyopaque extern symbol" { |
| 7 | 7 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; |
| 8 | 8 | if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; |
| 9 | 9 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; |
| 10 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | |
| 11 | 10 | |
| 12 | 11 | const a = @extern(*anyopaque, .{ .name = "a_mystery_symbol" }); |
| 13 | 12 | const b: *i32 = @alignCast(@ptrCast(a)); |
test/behavior/fn.zig-1| ... | ... | @@ -429,7 +429,6 @@ test "implicit cast function to function ptr" { |
| 429 | 429 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 430 | 430 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; |
| 431 | 431 | if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; |
| 432 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | |
| 433 | 432 | |
| 434 | 433 | const S1 = struct { |
| 435 | 434 | export fn someFunctionThatReturnsAValue() c_int { |
test/behavior/pointers.zig-1| ... | ... | @@ -45,7 +45,6 @@ test "pointer-integer arithmetic" { |
| 45 | 45 | |
| 46 | 46 | test "pointer subtraction" { |
| 47 | 47 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 48 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | |
| 49 | 48 | |
| 50 | 49 | { |
| 51 | 50 | const a: *u8 = @ptrFromInt(100); |
test/link/elf.zig+20-4| ... | ... | @@ -1773,25 +1773,41 @@ fn testImportingDataDynamic(b: *Build, opts: Options) *Step { |
| 1773 | 1773 | .use_llvm = true, |
| 1774 | 1774 | }, .{ |
| 1775 | 1775 | .name = "a", |
| 1776 | .c_source_bytes = "int foo = 42;", | |
| 1776 | .c_source_bytes = | |
| 1777 | \\#include <stdio.h> | |
| 1778 | \\int foo = 42; | |
| 1779 | \\void printFoo() { fprintf(stderr, "lib foo=%d\n", foo); } | |
| 1780 | , | |
| 1777 | 1781 | }); |
| 1782 | dso.linkLibC(); | |
| 1778 | 1783 | |
| 1779 | 1784 | const main = addExecutable(b, opts, .{ |
| 1780 | 1785 | .name = "main", |
| 1781 | 1786 | .zig_source_bytes = |
| 1787 | \\const std = @import("std"); | |
| 1782 | 1788 | \\extern var foo: i32; |
| 1789 | \\extern fn printFoo() void; | |
| 1783 | 1790 | \\pub fn main() void { |
| 1784 | \\ @import("std").debug.print("{d}\n", .{foo}); | |
| 1791 | \\ std.debug.print("exe foo={d}\n", .{foo}); | |
| 1792 | \\ printFoo(); | |
| 1793 | \\ foo += 1; | |
| 1794 | \\ std.debug.print("exe foo={d}\n", .{foo}); | |
| 1795 | \\ printFoo(); | |
| 1785 | 1796 | \\} |
| 1786 | 1797 | , |
| 1787 | 1798 | .strip = true, // TODO temp hack |
| 1788 | 1799 | }); |
| 1789 | 1800 | main.pie = true; |
| 1790 | 1801 | main.linkLibrary(dso); |
| 1791 | main.linkLibC(); | |
| 1792 | 1802 | |
| 1793 | 1803 | const run = addRunArtifact(main); |
| 1794 | run.expectStdErrEqual("42\n"); | |
| 1804 | run.expectStdErrEqual( | |
| 1805 | \\exe foo=42 | |
| 1806 | \\lib foo=42 | |
| 1807 | \\exe foo=43 | |
| 1808 | \\lib foo=43 | |
| 1809 | \\ | |
| 1810 | ); | |
| 1795 | 1811 | test_step.dependOn(&run.step); |
| 1796 | 1812 | |
| 1797 | 1813 | return test_step; |