authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-08-16 21:19:44+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-08-16 21:19:44+02:00
log90989be0e31a91335f8d1c1eafb84c3b34792a8c
tree7b3e4b1769b02db219442bd9c83d4df185848d3d
parentf1eed99f3d2d355054c6cf36d6f332d83b2ec595
parent73f385eec57d4fc28069b60f059fa8553d3a0c1b
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #21065 from ziglang/elf-zig-got

elf: replace .got.zig with a zig jump table

27 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,7 +218,7 @@ pub fn append(opts: @This(), buffer: *std.ArrayList(u8)) Allocator.Error!void {
218218
219 if (opts.is_test) {219 if (opts.is_test) {
220 try buffer.appendSlice(220 try buffer.appendSlice(
221 \\pub var test_functions: []const std.builtin.TestFn = undefined; // overwritten later221 \\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,6 +3092,10 @@ pub fn totalErrorCount(comp: *Compilation) u32 {
3092 if (zcu.intern_pool.global_error_set.getNamesFromMainThread().len > zcu.error_limit) {3092 if (zcu.intern_pool.global_error_set.getNamesFromMainThread().len > zcu.error_limit) {
3093 total += 1;3093 total += 1;
3094 }3094 }
3095
3096 for (zcu.failed_codegen.keys()) |_| {
3097 total += 1;
3098 }
3095 }3099 }
30963100
3097 // The "no entry point found" error only counts if there are no semantic analysis errors.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,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 for (zcu.failed_exports.values()) |value| {3247 for (zcu.failed_exports.values()) |value| {
3241 try addModuleErrorMsg(zcu, &bundle, value.*, &all_references);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,24 +4352,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
4352 // on linking.4352 // on linking.
4353 if (try self.air.value(callee, pt)) |func_value| switch (ip.indexToKey(func_value.toIntern())) {4353 if (try self.air.value(callee, pt)) |func_value| switch (ip.indexToKey(func_value.toIntern())) {
4354 .func => |func| {4354 .func => |func| {
4355 if (self.bin_file.cast(.elf)) |elf_file| {4355 if (self.bin_file.cast(.elf)) |_| {
4356 const zo = elf_file.zigObjectPtr().?;4356 return self.fail("TODO implement calling functions for Elf", .{});
4357 const sym_index = try zo.getOrCreateMetadataForNav(elf_file, func.owner_nav);4357 } else if (self.bin_file.cast(.macho)) |_| {
4358 const sym = zo.symbol(sym_index);4358 return self.fail("TODO implement calling functions for MachO", .{});
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 // });
4373 } else if (self.bin_file.cast(.coff)) |coff_file| {4359 } else if (self.bin_file.cast(.coff)) |coff_file| {
4374 const atom = try coff_file.getOrCreateAtomForNav(func.owner_nav);4360 const atom = try coff_file.getOrCreateAtomForNav(func.owner_nav);
4375 const sym_index = coff_file.getAtom(atom).getSymbolIndex().?;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,21 +4379,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
4393 .@"extern" => |@"extern"| {4379 .@"extern" => |@"extern"| {
4394 const nav_name = ip.getNav(@"extern".owner_nav).name.toSlice(ip);4380 const nav_name = ip.getNav(@"extern".owner_nav).name.toSlice(ip);
4395 const lib_name = @"extern".lib_name.toSlice(ip);4381 const lib_name = @"extern".lib_name.toSlice(ip);
4396 if (self.bin_file.cast(.macho)) |macho_file| {4382 if (self.bin_file.cast(.macho)) |_| {
4397 _ = macho_file;4383 return self.fail("TODO implement calling extern functions for MachO", .{});
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 // });
4411 } else if (self.bin_file.cast(.coff)) |coff_file| {4384 } else if (self.bin_file.cast(.coff)) |coff_file| {
4412 const sym_index = try coff_file.getGlobalSymbol(nav_name, lib_name);4385 const sym_index = try coff_file.getGlobalSymbol(nav_name, lib_name);
4413 try self.genSetReg(Type.u64, .x30, .{4386 try self.genSetReg(Type.u64, .x30, .{
...@@ -6234,7 +6207,7 @@ fn genTypedValue(self: *Self, val: Value) InnerError!MCValue {...@@ -6234,7 +6207,7 @@ fn genTypedValue(self: *Self, val: Value) InnerError!MCValue {
6234 .memory => |addr| .{ .memory = addr },6207 .memory => |addr| .{ .memory = addr },
6235 .load_got => |sym_index| .{ .linker_load = .{ .type = .got, .sym_index = sym_index } },6208 .load_got => |sym_index| .{ .linker_load = .{ .type = .got, .sym_index = sym_index } },
6236 .load_direct => |sym_index| .{ .linker_load = .{ .type = .direct, .sym_index = sym_index } },6209 .load_direct => |sym_index| .{ .linker_load = .{ .type = .direct, .sym_index = sym_index } },
6237 .load_symbol, .load_tlv => unreachable, // TODO6210 .load_symbol, .load_tlv, .lea_symbol => unreachable, // TODO
6238 },6211 },
6239 .fail => |msg| {6212 .fail => |msg| {
6240 self.err_msg = msg;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,22 +4333,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
4333 // Due to incremental compilation, how function calls are generated depends4333 // Due to incremental compilation, how function calls are generated depends
4334 // on linking.4334 // on linking.
4335 if (try self.air.value(callee, pt)) |func_value| switch (ip.indexToKey(func_value.toIntern())) {4335 if (try self.air.value(callee, pt)) |func_value| switch (ip.indexToKey(func_value.toIntern())) {
4336 .func => |func| {4336 .func => {
4337 if (self.bin_file.cast(.elf)) |elf_file| {4337 return self.fail("TODO implement calling functions", .{});
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 }
4352 },4338 },
4353 .@"extern" => {4339 .@"extern" => {
4354 return self.fail("TODO implement calling extern functions", .{});4340 return self.fail("TODO implement calling extern functions", .{});
...@@ -6184,7 +6170,7 @@ fn genTypedValue(self: *Self, val: Value) InnerError!MCValue {...@@ -6184,7 +6170,7 @@ fn genTypedValue(self: *Self, val: Value) InnerError!MCValue {
6184 .mcv => |mcv| switch (mcv) {6170 .mcv => |mcv| switch (mcv) {
6185 .none => .none,6171 .none => .none,
6186 .undef => .undef,6172 .undef => .undef,
6187 .load_got, .load_symbol, .load_direct, .load_tlv => unreachable, // TODO6173 .load_got, .load_symbol, .load_direct, .load_tlv, .lea_symbol => unreachable, // TODO
6188 .immediate => |imm| .{ .immediate = @truncate(imm) },6174 .immediate => |imm| .{ .immediate = @truncate(imm) },
6189 .memory => |addr| .{ .memory = addr },6175 .memory => |addr| .{ .memory = addr },
6190 },6176 },
src/arch/riscv64/CodeGen.zig+6-5
...@@ -4937,7 +4937,7 @@ fn genCall(...@@ -4937,7 +4937,7 @@ fn genCall(
4937 if (func.mod.pic) {4937 if (func.mod.pic) {
4938 return func.fail("TODO: genCall pic", .{});4938 return func.fail("TODO: genCall pic", .{});
4939 } else {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 _ = try func.addInst(.{4941 _ = try func.addInst(.{
4942 .tag = .jalr,4942 .tag = .jalr,
4943 .data = .{ .i_type = .{4943 .data = .{ .i_type = .{
...@@ -6120,7 +6120,7 @@ fn airAsm(func: *Func, inst: Air.Inst.Index) !void {...@@ -6120,7 +6120,7 @@ fn airAsm(func: *Func, inst: Air.Inst.Index) !void {
6120 arg_map.get(op_str["%[".len .. mod_index orelse op_str.len - "]".len]) orelse6120 arg_map.get(op_str["%[".len .. mod_index orelse op_str.len - "]".len]) orelse
6121 return func.fail("no matching constraint: '{s}'", .{op_str})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 assert(sym_off.off == 0);6124 assert(sym_off.off == 0);
6125 break :blk .{ .sym = sym_off };6125 break :blk .{ .sym = sym_off };
6126 } else return func.fail("invalid modifier: '{s}'", .{modifier}),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,7 +6388,7 @@ fn genCopy(func: *Func, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !void {
6388 ty,6388 ty,
6389 src_mcv,6389 src_mcv,
6390 ),6390 ),
6391 .load_tlv => {6391 .load_symbol, .load_tlv => {
6392 const addr_reg, const addr_lock = try func.allocReg(.int);6392 const addr_reg, const addr_lock = try func.allocReg(.int);
6393 defer func.register_manager.unlockReg(addr_lock);6393 defer func.register_manager.unlockReg(addr_lock);
63946394
...@@ -6433,7 +6433,7 @@ fn genCopy(func: *Func, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !void {...@@ -6433,7 +6433,7 @@ fn genCopy(func: *Func, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !void {
6433 part_disp += @intCast(dst_ty.abiSize(func.pt));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}
64396439
...@@ -6594,7 +6594,7 @@ fn genInlineMemset(...@@ -6594,7 +6594,7 @@ fn genInlineMemset(
6594 .tag = .beq,6594 .tag = .beq,
6595 .data = .{6595 .data = .{
6596 .b_type = .{6596 .b_type = .{
6597 .inst = @intCast(func.mir_instructions.len + 4), // points after the last inst6597 .inst = @intCast(func.mir_instructions.len + 3), // points after the last inst
6598 .rs1 = count,6598 .rs1 = count,
6599 .rs2 = .zero,6599 .rs2 = .zero,
6600 },6600 },
...@@ -8026,6 +8026,7 @@ fn genTypedValue(func: *Func, val: Value) InnerError!MCValue {...@@ -8026,6 +8026,7 @@ fn genTypedValue(func: *Func, val: Value) InnerError!MCValue {
8026 .mcv => |mcv| switch (mcv) {8026 .mcv => |mcv| switch (mcv) {
8027 .none => .none,8027 .none => .none,
8028 .undef => unreachable,8028 .undef => unreachable,
8029 .lea_symbol => |sym_index| .{ .lea_symbol = .{ .sym = sym_index } },
8029 .load_symbol => |sym_index| .{ .load_symbol = .{ .sym = sym_index } },8030 .load_symbol => |sym_index| .{ .load_symbol = .{ .sym = sym_index } },
8030 .load_tlv => |sym_index| .{ .lea_tlv = sym_index },8031 .load_tlv => |sym_index| .{ .lea_tlv = sym_index },
8031 .immediate => |imm| .{ .immediate = imm },8032 .immediate => |imm| .{ .immediate = imm },
src/arch/riscv64/Emit.zig+5-17
...@@ -43,31 +43,19 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -43,31 +43,19 @@ pub fn emitMir(emit: *Emit) Error!void {
43 .fmt = std.meta.activeTag(lowered_inst),43 .fmt = std.meta.activeTag(lowered_inst),
44 }),44 }),
45 .load_symbol_reloc => |symbol| {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 const elf_file = emit.bin_file.cast(.elf).?;46 const elf_file = emit.bin_file.cast(.elf).?;
53 const zo = elf_file.zigObjectPtr().?;47 const zo = elf_file.zigObjectPtr().?;
5448
55 const atom_ptr = zo.symbol(symbol.atom_index).atom(elf_file).?;49 const atom_ptr = zo.symbol(symbol.atom_index).atom(elf_file).?;
56 const sym = zo.symbol(symbol.sym_index);50 const sym = zo.symbol(symbol.sym_index);
5751
58 var hi_r_type: u32 = @intFromEnum(std.elf.R_RISCV.HI20);52 if (sym.flags.is_extern_ptr and emit.lower.pic) {
59 var lo_r_type: u32 = @intFromEnum(std.elf.R_RISCV.LO12_I);53 return emit.fail("emit GOT relocation for symbol '{s}'", .{sym.name(elf_file)});
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
69 }54 }
7055
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 try atom_ptr.addReloc(elf_file, .{59 try atom_ptr.addReloc(elf_file, .{
72 .r_offset = start_offset,60 .r_offset = start_offset,
73 .r_info = (@as(u64, @intCast(symbol.sym_index)) << 32) | hi_r_type,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,34 +1349,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
1349 // Due to incremental compilation, how function calls are generated depends1349 // Due to incremental compilation, how function calls are generated depends
1350 // on linking.1350 // on linking.
1351 if (try self.air.value(callee, pt)) |func_value| switch (ip.indexToKey(func_value.toIntern())) {1351 if (try self.air.value(callee, pt)) |func_value| switch (ip.indexToKey(func_value.toIntern())) {
1352 .func => |func| {1352 .func => {
1353 const got_addr = if (self.bin_file.cast(.elf)) |elf_file| blk: {1353 return self.fail("TODO implement calling functions", .{});
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 });
1380 },1354 },
1381 .@"extern" => {1355 .@"extern" => {
1382 return self.fail("TODO implement calling extern functions", .{});1356 return self.fail("TODO implement calling extern functions", .{});
...@@ -4153,7 +4127,7 @@ fn genTypedValue(self: *Self, val: Value) InnerError!MCValue {...@@ -4153,7 +4127,7 @@ fn genTypedValue(self: *Self, val: Value) InnerError!MCValue {
4153 .mcv => |mcv| switch (mcv) {4127 .mcv => |mcv| switch (mcv) {
4154 .none => .none,4128 .none => .none,
4155 .undef => .undef,4129 .undef => .undef,
4156 .load_got, .load_symbol, .load_direct, .load_tlv => unreachable, // TODO4130 .load_got, .load_symbol, .load_direct, .load_tlv, .lea_symbol => unreachable, // TODO
4157 .immediate => |imm| .{ .immediate = imm },4131 .immediate => |imm| .{ .immediate = imm },
4158 .memory => |addr| .{ .memory = addr },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,14 +1379,22 @@ fn asmImmediate(self: *Self, tag: Mir.Inst.FixedTag, imm: Immediate) !void {
1379 .ops = switch (imm) {1379 .ops = switch (imm) {
1380 .signed => .i_s,1380 .signed => .i_s,
1381 .unsigned => .i_u,1381 .unsigned => .i_u,
1382 .reloc => .rel,
1382 },1383 },
1383 .data = .{ .i = .{1384 .data = switch (imm) {
1384 .fixes = tag[0],1385 .reloc => |x| reloc: {
1385 .i = switch (imm) {1386 assert(tag[0] == ._);
1386 .signed => |s| @bitCast(s),1387 break :reloc .{ .reloc = x };
1387 .unsigned => |u| @intCast(u),
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}
13921400
...@@ -1406,6 +1414,7 @@ fn asmRegisterImmediate(self: *Self, tag: Mir.Inst.FixedTag, reg: Register, imm:...@@ -1406,6 +1414,7 @@ fn asmRegisterImmediate(self: *Self, tag: Mir.Inst.FixedTag, reg: Register, imm:
1406 const ops: Mir.Inst.Ops = switch (imm) {1414 const ops: Mir.Inst.Ops = switch (imm) {
1407 .signed => .ri_s,1415 .signed => .ri_s,
1408 .unsigned => |u| if (math.cast(u32, u)) |_| .ri_u else .ri64,1416 .unsigned => |u| if (math.cast(u32, u)) |_| .ri_u else .ri64,
1417 .reloc => unreachable,
1409 };1418 };
1410 _ = try self.addInst(.{1419 _ = try self.addInst(.{
1411 .tag = tag[1],1420 .tag = tag[1],
...@@ -1417,6 +1426,7 @@ fn asmRegisterImmediate(self: *Self, tag: Mir.Inst.FixedTag, reg: Register, imm:...@@ -1417,6 +1426,7 @@ fn asmRegisterImmediate(self: *Self, tag: Mir.Inst.FixedTag, reg: Register, imm:
1417 .i = switch (imm) {1426 .i = switch (imm) {
1418 .signed => |s| @bitCast(s),1427 .signed => |s| @bitCast(s),
1419 .unsigned => |u| @intCast(u),1428 .unsigned => |u| @intCast(u),
1429 .reloc => unreachable,
1420 },1430 },
1421 } },1431 } },
1422 .ri64 => .{ .rx = .{1432 .ri64 => .{ .rx = .{
...@@ -1488,6 +1498,7 @@ fn asmRegisterRegisterRegisterImmediate(...@@ -1488,6 +1498,7 @@ fn asmRegisterRegisterRegisterImmediate(
1488 .i = switch (imm) {1498 .i = switch (imm) {
1489 .signed => |s| @bitCast(@as(i8, @intCast(s))),1499 .signed => |s| @bitCast(@as(i8, @intCast(s))),
1490 .unsigned => |u| @intCast(u),1500 .unsigned => |u| @intCast(u),
1501 .reloc => unreachable,
1491 },1502 },
1492 } },1503 } },
1493 });1504 });
...@@ -1505,6 +1516,7 @@ fn asmRegisterRegisterImmediate(...@@ -1505,6 +1516,7 @@ fn asmRegisterRegisterImmediate(
1505 .ops = switch (imm) {1516 .ops = switch (imm) {
1506 .signed => .rri_s,1517 .signed => .rri_s,
1507 .unsigned => .rri_u,1518 .unsigned => .rri_u,
1519 .reloc => unreachable,
1508 },1520 },
1509 .data = .{ .rri = .{1521 .data = .{ .rri = .{
1510 .fixes = tag[0],1522 .fixes = tag[0],
...@@ -1513,6 +1525,7 @@ fn asmRegisterRegisterImmediate(...@@ -1513,6 +1525,7 @@ fn asmRegisterRegisterImmediate(
1513 .i = switch (imm) {1525 .i = switch (imm) {
1514 .signed => |s| @bitCast(s),1526 .signed => |s| @bitCast(s),
1515 .unsigned => |u| @intCast(u),1527 .unsigned => |u| @intCast(u),
1528 .reloc => unreachable,
1516 },1529 },
1517 } },1530 } },
1518 });1531 });
...@@ -1610,6 +1623,7 @@ fn asmRegisterMemoryImmediate(...@@ -1610,6 +1623,7 @@ fn asmRegisterMemoryImmediate(
1610 if (switch (imm) {1623 if (switch (imm) {
1611 .signed => |s| if (math.cast(i16, s)) |x| @as(u16, @bitCast(x)) else null,1624 .signed => |s| if (math.cast(i16, s)) |x| @as(u16, @bitCast(x)) else null,
1612 .unsigned => |u| math.cast(u16, u),1625 .unsigned => |u| math.cast(u16, u),
1626 .reloc => unreachable,
1613 }) |small_imm| {1627 }) |small_imm| {
1614 _ = try self.addInst(.{1628 _ = try self.addInst(.{
1615 .tag = tag[1],1629 .tag = tag[1],
...@@ -1625,6 +1639,7 @@ fn asmRegisterMemoryImmediate(...@@ -1625,6 +1639,7 @@ fn asmRegisterMemoryImmediate(
1625 const payload = try self.addExtra(Mir.Imm32{ .imm = switch (imm) {1639 const payload = try self.addExtra(Mir.Imm32{ .imm = switch (imm) {
1626 .signed => |s| @bitCast(s),1640 .signed => |s| @bitCast(s),
1627 .unsigned => unreachable,1641 .unsigned => unreachable,
1642 .reloc => unreachable,
1628 } });1643 } });
1629 assert(payload + 1 == try self.addExtra(Mir.Memory.encode(m)));1644 assert(payload + 1 == try self.addExtra(Mir.Memory.encode(m)));
1630 _ = try self.addInst(.{1645 _ = try self.addInst(.{
...@@ -1632,6 +1647,7 @@ fn asmRegisterMemoryImmediate(...@@ -1632,6 +1647,7 @@ fn asmRegisterMemoryImmediate(
1632 .ops = switch (imm) {1647 .ops = switch (imm) {
1633 .signed => .rmi_s,1648 .signed => .rmi_s,
1634 .unsigned => .rmi_u,1649 .unsigned => .rmi_u,
1650 .reloc => unreachable,
1635 },1651 },
1636 .data = .{ .rx = .{1652 .data = .{ .rx = .{
1637 .fixes = tag[0],1653 .fixes = tag[0],
...@@ -1679,6 +1695,7 @@ fn asmMemoryImmediate(self: *Self, tag: Mir.Inst.FixedTag, m: Memory, imm: Immed...@@ -1679,6 +1695,7 @@ fn asmMemoryImmediate(self: *Self, tag: Mir.Inst.FixedTag, m: Memory, imm: Immed
1679 const payload = try self.addExtra(Mir.Imm32{ .imm = switch (imm) {1695 const payload = try self.addExtra(Mir.Imm32{ .imm = switch (imm) {
1680 .signed => |s| @bitCast(s),1696 .signed => |s| @bitCast(s),
1681 .unsigned => |u| @intCast(u),1697 .unsigned => |u| @intCast(u),
1698 .reloc => unreachable,
1682 } });1699 } });
1683 assert(payload + 1 == try self.addExtra(Mir.Memory.encode(m)));1700 assert(payload + 1 == try self.addExtra(Mir.Memory.encode(m)));
1684 _ = try self.addInst(.{1701 _ = try self.addInst(.{
...@@ -1686,6 +1703,7 @@ fn asmMemoryImmediate(self: *Self, tag: Mir.Inst.FixedTag, m: Memory, imm: Immed...@@ -1686,6 +1703,7 @@ fn asmMemoryImmediate(self: *Self, tag: Mir.Inst.FixedTag, m: Memory, imm: Immed
1686 .ops = switch (imm) {1703 .ops = switch (imm) {
1687 .signed => .mi_s,1704 .signed => .mi_s,
1688 .unsigned => .mi_u,1705 .unsigned => .mi_u,
1706 .reloc => unreachable,
1689 },1707 },
1690 .data = .{ .x = .{1708 .data = .{ .x = .{
1691 .fixes = tag[0],1709 .fixes = tag[0],
...@@ -12310,33 +12328,10 @@ fn genCall(self: *Self, info: union(enum) {...@@ -12310,33 +12328,10 @@ fn genCall(self: *Self, info: union(enum) {
12310 if (self.bin_file.cast(.elf)) |elf_file| {12328 if (self.bin_file.cast(.elf)) |elf_file| {
12311 const zo = elf_file.zigObjectPtr().?;12329 const zo = elf_file.zigObjectPtr().?;
12312 const sym_index = try zo.getOrCreateMetadataForNav(elf_file, func.owner_nav);12330 const sym_index = try zo.getOrCreateMetadataForNav(elf_file, func.owner_nav);
12313 if (self.mod.pic) {12331 try self.asmImmediate(.{ ._, .call }, Immediate.rel(.{
12314 const callee_reg: Register = switch (resolved_cc) {12332 .atom_index = try self.owner.getSymbolIndex(self),
12315 .SysV => callee: {12333 .sym_index = sym_index,
12316 if (!fn_info.is_var_args) break :callee .rax;12334 }));
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 });
12340 } else if (self.bin_file.cast(.coff)) |coff_file| {12335 } else if (self.bin_file.cast(.coff)) |coff_file| {
12341 const atom = try coff_file.getOrCreateAtomForNav(func.owner_nav);12336 const atom = try coff_file.getOrCreateAtomForNav(func.owner_nav);
12342 const sym_index = coff_file.getAtom(atom).getSymbolIndex().?;12337 const sym_index = coff_file.getAtom(atom).getSymbolIndex().?;
...@@ -12365,7 +12360,16 @@ fn genCall(self: *Self, info: union(enum) {...@@ -12365,7 +12360,16 @@ fn genCall(self: *Self, info: union(enum) {
12365 });12360 });
12366 } else unreachable;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 .call,12373 .call,
12370 @"extern".lib_name.toSlice(ip),12374 @"extern".lib_name.toSlice(ip),
12371 @"extern".name.toSlice(ip),12375 @"extern".name.toSlice(ip),
...@@ -12377,7 +12381,13 @@ fn genCall(self: *Self, info: union(enum) {...@@ -12377,7 +12381,13 @@ fn genCall(self: *Self, info: union(enum) {
12377 try self.genSetReg(.rax, Type.usize, .{ .air_ref = callee }, .{});12381 try self.genSetReg(.rax, Type.usize, .{ .air_ref = callee }, .{});
12378 try self.asmRegister(.{ ._, .call }, .rax);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 return call_info.return_value.short;12392 return call_info.return_value.short;
12383}12393}
...@@ -14096,8 +14106,8 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {...@@ -14096,8 +14106,8 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
14096 .{ .reg = try self.copyToTmpRegister(Type.usize, .{ .lea_got = sym_index }) }14106 .{ .reg = try self.copyToTmpRegister(Type.usize, .{ .lea_got = sym_index }) }
14097 else14107 else
14098 return self.fail("invalid modifier: '{s}'", .{modifier}),14108 return self.fail("invalid modifier: '{s}'", .{modifier}),
14099 .load_symbol => |sym_off| if (mem.eql(u8, modifier, "P"))14109 .lea_symbol => |sym_off| if (mem.eql(u8, modifier, "P"))
14100 .{ .reg = try self.copyToTmpRegister(Type.usize, .{ .load_symbol = sym_off }) }14110 .{ .reg = try self.copyToTmpRegister(Type.usize, .{ .lea_symbol = sym_off }) }
14101 else14111 else
14102 return self.fail("invalid modifier: '{s}'", .{modifier}),14112 return self.fail("invalid modifier: '{s}'", .{modifier}),
14103 else => return self.fail("invalid constraint: '{s}'", .{op_str}),14113 else => return self.fail("invalid constraint: '{s}'", .{op_str}),
...@@ -15253,16 +15263,7 @@ fn genExternSymbolRef(...@@ -15253,16 +15263,7 @@ fn genExternSymbolRef(
15253 callee: []const u8,15263 callee: []const u8,
15254) InnerError!void {15264) InnerError!void {
15255 const atom_index = try self.owner.getSymbolIndex(self);15265 const atom_index = try self.owner.getSymbolIndex(self);
15256 if (self.bin_file.cast(.elf)) |elf_file| {15266 if (self.bin_file.cast(.coff)) |coff_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 const global_index = try coff_file.getGlobalSymbol(callee, lib);15267 const global_index = try coff_file.getGlobalSymbol(callee, lib);
15267 _ = try self.addInst(.{15268 _ = try self.addInst(.{
15268 .tag = .mov,15269 .tag = .mov,
...@@ -15306,7 +15307,7 @@ fn genLazySymbolRef(...@@ -15306,7 +15307,7 @@ fn genLazySymbolRef(
15306 if (self.mod.pic) {15307 if (self.mod.pic) {
15307 switch (tag) {15308 switch (tag) {
15308 .lea, .call => try self.genSetReg(reg, Type.usize, .{15309 .lea, .call => try self.genSetReg(reg, Type.usize, .{
15309 .load_symbol = .{ .sym = sym_index },15310 .lea_symbol = .{ .sym = sym_index },
15310 }, .{}),15311 }, .{}),
15311 .mov => try self.genSetReg(reg, Type.usize, .{15312 .mov => try self.genSetReg(reg, Type.usize, .{
15312 .load_symbol = .{ .sym = sym_index },15313 .load_symbol = .{ .sym = sym_index },
...@@ -15324,14 +15325,11 @@ fn genLazySymbolRef(...@@ -15324,14 +15325,11 @@ fn genLazySymbolRef(
15324 .sym_index = sym_index,15325 .sym_index = sym_index,
15325 };15326 };
15326 switch (tag) {15327 switch (tag) {
15327 .lea, .mov => try self.asmRegisterMemory(.{ ._, .mov }, reg.to64(), .{15328 .lea, .mov => try self.asmRegisterMemory(.{ ._, tag }, reg.to64(), .{
15328 .base = .{ .reloc = reloc },
15329 .mod = .{ .rm = .{ .size = .qword } },
15330 }),
15331 .call => try self.asmMemory(.{ ._, .call }, .{
15332 .base = .{ .reloc = reloc },15329 .base = .{ .reloc = reloc },
15333 .mod = .{ .rm = .{ .size = .qword } },15330 .mod = .{ .rm = .{ .size = .qword } },
15334 }),15331 }),
15332 .call => try self.asmImmediate(.{ ._, .call }, Immediate.rel(reloc)),
15335 else => unreachable,15333 else => unreachable,
15336 }15334 }
15337 }15335 }
...@@ -18790,6 +18788,7 @@ fn genTypedValue(self: *Self, val: Value) InnerError!MCValue {...@@ -18790,6 +18788,7 @@ fn genTypedValue(self: *Self, val: Value) InnerError!MCValue {
18790 .immediate => |imm| .{ .immediate = imm },18788 .immediate => |imm| .{ .immediate = imm },
18791 .memory => |addr| .{ .memory = addr },18789 .memory => |addr| .{ .memory = addr },
18792 .load_symbol => |sym_index| .{ .load_symbol = .{ .sym = sym_index } },18790 .load_symbol => |sym_index| .{ .load_symbol = .{ .sym = sym_index } },
18791 .lea_symbol => |sym_index| .{ .lea_symbol = .{ .sym = sym_index } },
18793 .load_direct => |sym_index| .{ .load_direct = sym_index },18792 .load_direct => |sym_index| .{ .load_direct = sym_index },
18794 .load_got => |sym_index| .{ .lea_got = sym_index },18793 .load_got => |sym_index| .{ .lea_got = sym_index },
18795 .load_tlv => |sym_index| .{ .lea_tlv = sym_index },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,7 +8,7 @@ const bits = @import("bits.zig");
8const encoder = @import("encoder.zig");8const encoder = @import("encoder.zig");
99
10const Encoding = @import("Encoding.zig");10const Encoding = @import("Encoding.zig");
11const Immediate = bits.Immediate;11const Immediate = Instruction.Immediate;
12const Instruction = encoder.Instruction;12const Instruction = encoder.Instruction;
13const LegacyPrefixes = encoder.LegacyPrefixes;13const LegacyPrefixes = encoder.LegacyPrefixes;
14const Memory = Instruction.Memory;14const Memory = Instruction.Memory;
src/arch/x86_64/Emit.zig+10-33
...@@ -110,21 +110,11 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -110,21 +110,11 @@ pub fn emitMir(emit: *Emit) Error!void {
110 });110 });
111 },111 },
112 .linker_reloc => |data| if (emit.lower.bin_file.cast(.elf)) |elf_file| {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 const zo = elf_file.zigObjectPtr().?;113 const zo = elf_file.zigObjectPtr().?;
119 const atom = zo.symbol(data.atom_index).atom(elf_file).?;114 const atom = zo.symbol(data.atom_index).atom(elf_file).?;
120 const sym = zo.symbol(data.sym_index);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 if (emit.lower.pic) {116 if (emit.lower.pic) {
125 const r_type: u32 = if (sym.flags.needs_zig_got and !is_obj_or_static_lib)117 const r_type: u32 = if (sym.flags.is_extern_ptr)
126 link.File.Elf.R_ZIG_GOTPCREL
127 else if (sym.flags.needs_got)
128 @intFromEnum(std.elf.R_X86_64.GOTPCREL)118 @intFromEnum(std.elf.R_X86_64.GOTPCREL)
129 else119 else
130 @intFromEnum(std.elf.R_X86_64.PC32);120 @intFromEnum(std.elf.R_X86_64.PC32);
...@@ -134,28 +124,15 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -134,28 +124,15 @@ pub fn emitMir(emit: *Emit) Error!void {
134 .r_addend = -4,124 .r_addend = -4,
135 });125 });
136 } else {126 } else {
137 if (lowered_inst.encoding.mnemonic == .call and sym.flags.needs_zig_got and is_obj_or_static_lib) {127 const r_type: u32 = if (sym.flags.is_tls)
138 const r_type = @intFromEnum(std.elf.R_X86_64.PC32);128 @intFromEnum(std.elf.R_X86_64.TPOFF32)
139 try atom.addReloc(elf_file, .{129 else
140 .r_offset = end_offset - 4,130 @intFromEnum(std.elf.R_X86_64.@"32");
141 .r_info = (@as(u64, @intCast(data.sym_index)) << 32) | r_type,131 try atom.addReloc(elf_file, .{
142 .r_addend = -4,132 .r_offset = end_offset - 4,
143 });133 .r_info = (@as(u64, @intCast(data.sym_index)) << 32) | r_type,
144 } else {134 .r_addend = 0,
145 const r_type: u32 = if (sym.flags.needs_zig_got and !is_obj_or_static_lib)135 });
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 }
159 }136 }
160 } else if (emit.lower.bin_file.cast(.macho)) |macho_file| {137 } else if (emit.lower.bin_file.cast(.macho)) |macho_file| {
161 const is_obj_or_static_lib = switch (emit.lower.output_mode) {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,33 +397,40 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand)
397 }397 }
398398
399 _ = lower.reloc(.{ .linker_reloc = sym });399 _ = lower.reloc(.{ .linker_reloc = sym });
400 break :op if (lower.pic) switch (mnemonic) {400 if (lower.pic) switch (mnemonic) {
401 .lea => {401 .lea => {
402 if (elf_sym.flags.is_extern_ptr) emit_mnemonic = .mov;
402 break :op .{ .mem = Memory.rip(mem_op.sib.ptr_size, 0) };403 break :op .{ .mem = Memory.rip(mem_op.sib.ptr_size, 0) };
403 },404 },
404 .mov => {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 break :op .{ .mem = Memory.rip(mem_op.sib.ptr_size, 0) };418 break :op .{ .mem = Memory.rip(mem_op.sib.ptr_size, 0) };
407 },419 },
408 else => unreachable,420 else => unreachable,
409 } else switch (mnemonic) {421 } else switch (mnemonic) {
410 .call => break :op if (is_obj_or_static_lib and elf_sym.flags.needs_zig_got) .{422 .call => break :op .{ .mem = Memory.sib(mem_op.sib.ptr_size, .{
411 .imm = Immediate.s(0),
412 } else .{ .mem = Memory.sib(mem_op.sib.ptr_size, .{
413 .base = .{ .reg = .ds },423 .base = .{ .reg = .ds },
414 }) },424 }) },
415 .lea => {425 .lea => {
416 emit_mnemonic = .mov;426 emit_mnemonic = .mov;
417 break :op .{ .imm = Immediate.s(0) };427 break :op .{ .imm = Immediate.s(0) };
418 },428 },
419 .mov => {429 .mov => break :op .{ .mem = Memory.sib(mem_op.sib.ptr_size, .{
420 if (is_obj_or_static_lib and elf_sym.flags.needs_zig_got) emit_mnemonic = .lea;430 .base = .{ .reg = .ds },
421 break :op .{ .mem = Memory.sib(mem_op.sib.ptr_size, .{431 }) },
422 .base = .{ .reg = .ds },
423 }) };
424 },
425 else => unreachable,432 else => unreachable,
426 };433 }
427 } else if (lower.bin_file.cast(.macho)) |macho_file| {434 } else if (lower.bin_file.cast(.macho)) |macho_file| {
428 const zo = macho_file.getZigObject().?;435 const zo = macho_file.getZigObject().?;
429 const macho_sym = zo.symbols.items[sym.sym_index];436 const macho_sym = zo.symbols.items[sym.sym_index];
...@@ -485,7 +492,7 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void {...@@ -485,7 +492,7 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void {
485 .rrmi => inst.data.rrix.fixes,492 .rrmi => inst.data.rrix.fixes,
486 .mi_u, .mi_s => inst.data.x.fixes,493 .mi_u, .mi_s => inst.data.x.fixes,
487 .m => inst.data.x.fixes,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 else => return lower.fail("TODO lower .{s}", .{@tagName(inst.ops)}),496 else => return lower.fail("TODO lower .{s}", .{@tagName(inst.ops)}),
490 };497 };
491 try lower.emit(switch (fixes) {498 try lower.emit(switch (fixes) {
...@@ -617,7 +624,7 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void {...@@ -617,7 +624,7 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void {
617 .{ .mem = lower.mem(inst.data.rrix.payload) },624 .{ .mem = lower.mem(inst.data.rrix.payload) },
618 .{ .imm = lower.imm(inst.ops, inst.data.rrix.i) },625 .{ .imm = lower.imm(inst.ops, inst.data.rrix.i) },
619 },626 },
620 .extern_fn_reloc => &.{627 .extern_fn_reloc, .rel => &.{
621 .{ .imm = lower.reloc(.{ .linker_extern_fn = inst.data.reloc }) },628 .{ .imm = lower.reloc(.{ .linker_extern_fn = inst.data.reloc }) },
622 },629 },
623 .got_reloc, .direct_reloc, .import_reloc => ops: {630 .got_reloc, .direct_reloc, .import_reloc => ops: {
...@@ -660,7 +667,7 @@ const std = @import("std");...@@ -660,7 +667,7 @@ const std = @import("std");
660const Air = @import("../../Air.zig");667const Air = @import("../../Air.zig");
661const Allocator = std.mem.Allocator;668const Allocator = std.mem.Allocator;
662const ErrorMsg = Zcu.ErrorMsg;669const ErrorMsg = Zcu.ErrorMsg;
663const Immediate = bits.Immediate;670const Immediate = Instruction.Immediate;
664const Instruction = encoder.Instruction;671const Instruction = encoder.Instruction;
665const Lower = @This();672const Lower = @This();
666const Memory = Instruction.Memory;673const Memory = Instruction.Memory;
src/arch/x86_64/Mir.zig+1-1
...@@ -769,7 +769,7 @@ pub const Inst = struct {...@@ -769,7 +769,7 @@ pub const Inst = struct {
769 /// Uses `imm` payload.769 /// Uses `imm` payload.
770 i_u,770 i_u,
771 /// Relative displacement operand.771 /// Relative displacement operand.
772 /// Uses `imm` payload.772 /// Uses `reloc` payload.
773 rel,773 rel,
774 /// Register, memory operands.774 /// Register, memory operands.
775 /// Uses `rx` payload with extra data of type `Memory`.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,6 +569,7 @@ pub const Memory = struct {
569pub const Immediate = union(enum) {569pub const Immediate = union(enum) {
570 signed: i32,570 signed: i32,
571 unsigned: u64,571 unsigned: u64,
572 reloc: Symbol,
572573
573 pub fn u(x: u64) Immediate {574 pub fn u(x: u64) Immediate {
574 return .{ .unsigned = x };575 return .{ .unsigned = x };
...@@ -578,39 +579,19 @@ pub const Immediate = union(enum) {...@@ -578,39 +579,19 @@ pub const Immediate = union(enum) {
578 return .{ .signed = x };579 return .{ .signed = x };
579 }580 }
580581
581 pub fn asSigned(imm: Immediate, bit_size: u64) i64 {582 pub fn rel(symbol: Symbol) Immediate {
582 return switch (imm) {583 return .{ .reloc = symbol };
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 };
597 }584 }
598585
599 pub fn asUnsigned(imm: Immediate, bit_size: u64) u64 {586 pub fn format(
600 return switch (imm) {587 imm: Immediate,
601 .signed => |x| switch (bit_size) {588 comptime fmt: []const u8,
602 1, 8 => @as(u8, @bitCast(@as(i8, @intCast(x)))),589 options: std.fmt.FormatOptions,
603 16 => @as(u16, @bitCast(@as(i16, @intCast(x)))),590 writer: anytype,
604 32, 64 => @as(u32, @bitCast(x)),591 ) @TypeOf(writer).Error!void {
605 else => unreachable,592 switch (imm) {
606 },593 .reloc => |x| try std.fmt.formatType(x, fmt, options, writer, 0),
607 .unsigned => |x| switch (bit_size) {594 inline else => |x| try writer.print("{d}", .{x}),
608 1, 8 => @as(u8, @intCast(x)),595 }
609 16 => @as(u16, @intCast(x)),
610 32 => @as(u32, @intCast(x)),
611 64 => x,
612 else => unreachable,
613 },
614 };
615 }596 }
616};597};
src/arch/x86_64/encoder.zig+91-43
...@@ -7,7 +7,6 @@ const testing = std.testing;...@@ -7,7 +7,6 @@ const testing = std.testing;
7const bits = @import("bits.zig");7const bits = @import("bits.zig");
8const Encoding = @import("Encoding.zig");8const Encoding = @import("Encoding.zig");
9const FrameIndex = bits.FrameIndex;9const FrameIndex = bits.FrameIndex;
10const Immediate = bits.Immediate;
11const Register = bits.Register;10const Register = bits.Register;
12const Symbol = bits.Symbol;11const Symbol = bits.Symbol;
1312
...@@ -28,6 +27,55 @@ pub const Instruction = struct {...@@ -28,6 +27,55 @@ pub const Instruction = struct {
28 repnz,27 repnz,
29 };28 };
3029
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 pub const Memory = union(enum) {79 pub const Memory = union(enum) {
32 sib: Sib,80 sib: Sib,
33 rip: Rip,81 rip: Rip,
...@@ -1119,7 +1167,7 @@ test "encode" {...@@ -1119,7 +1167,7 @@ test "encode" {
11191167
1120 const inst = try Instruction.new(.none, .mov, &.{1168 const inst = try Instruction.new(.none, .mov, &.{
1121 .{ .reg = .rbx },1169 .{ .reg = .rbx },
1122 .{ .imm = Immediate.u(4) },1170 .{ .imm = Instruction.Immediate.u(4) },
1123 });1171 });
1124 try inst.encode(buf.writer(), .{});1172 try inst.encode(buf.writer(), .{});
1125 try testing.expectEqualSlices(u8, &.{ 0x48, 0xc7, 0xc3, 0x4, 0x0, 0x0, 0x0 }, buf.items);1173 try testing.expectEqualSlices(u8, &.{ 0x48, 0xc7, 0xc3, 0x4, 0x0, 0x0, 0x0 }, buf.items);
...@@ -1129,47 +1177,47 @@ test "lower I encoding" {...@@ -1129,47 +1177,47 @@ test "lower I encoding" {
1129 var enc = TestEncode{};1177 var enc = TestEncode{};
11301178
1131 try enc.encode(.push, &.{1179 try enc.encode(.push, &.{
1132 .{ .imm = Immediate.u(0x10) },1180 .{ .imm = Instruction.Immediate.u(0x10) },
1133 });1181 });
1134 try expectEqualHexStrings("\x6A\x10", enc.code(), "push 0x10");1182 try expectEqualHexStrings("\x6A\x10", enc.code(), "push 0x10");
11351183
1136 try enc.encode(.push, &.{1184 try enc.encode(.push, &.{
1137 .{ .imm = Immediate.u(0x1000) },1185 .{ .imm = Instruction.Immediate.u(0x1000) },
1138 });1186 });
1139 try expectEqualHexStrings("\x66\x68\x00\x10", enc.code(), "push 0x1000");1187 try expectEqualHexStrings("\x66\x68\x00\x10", enc.code(), "push 0x1000");
11401188
1141 try enc.encode(.push, &.{1189 try enc.encode(.push, &.{
1142 .{ .imm = Immediate.u(0x10000000) },1190 .{ .imm = Instruction.Immediate.u(0x10000000) },
1143 });1191 });
1144 try expectEqualHexStrings("\x68\x00\x00\x00\x10", enc.code(), "push 0x10000000");1192 try expectEqualHexStrings("\x68\x00\x00\x00\x10", enc.code(), "push 0x10000000");
11451193
1146 try enc.encode(.adc, &.{1194 try enc.encode(.adc, &.{
1147 .{ .reg = .rax },1195 .{ .reg = .rax },
1148 .{ .imm = Immediate.u(0x10000000) },1196 .{ .imm = Instruction.Immediate.u(0x10000000) },
1149 });1197 });
1150 try expectEqualHexStrings("\x48\x15\x00\x00\x00\x10", enc.code(), "adc rax, 0x10000000");1198 try expectEqualHexStrings("\x48\x15\x00\x00\x00\x10", enc.code(), "adc rax, 0x10000000");
11511199
1152 try enc.encode(.add, &.{1200 try enc.encode(.add, &.{
1153 .{ .reg = .al },1201 .{ .reg = .al },
1154 .{ .imm = Immediate.u(0x10) },1202 .{ .imm = Instruction.Immediate.u(0x10) },
1155 });1203 });
1156 try expectEqualHexStrings("\x04\x10", enc.code(), "add al, 0x10");1204 try expectEqualHexStrings("\x04\x10", enc.code(), "add al, 0x10");
11571205
1158 try enc.encode(.add, &.{1206 try enc.encode(.add, &.{
1159 .{ .reg = .rax },1207 .{ .reg = .rax },
1160 .{ .imm = Immediate.u(0x10) },1208 .{ .imm = Instruction.Immediate.u(0x10) },
1161 });1209 });
1162 try expectEqualHexStrings("\x48\x83\xC0\x10", enc.code(), "add rax, 0x10");1210 try expectEqualHexStrings("\x48\x83\xC0\x10", enc.code(), "add rax, 0x10");
11631211
1164 try enc.encode(.sbb, &.{1212 try enc.encode(.sbb, &.{
1165 .{ .reg = .ax },1213 .{ .reg = .ax },
1166 .{ .imm = Immediate.u(0x10) },1214 .{ .imm = Instruction.Immediate.u(0x10) },
1167 });1215 });
1168 try expectEqualHexStrings("\x66\x1D\x10\x00", enc.code(), "sbb ax, 0x10");1216 try expectEqualHexStrings("\x66\x1D\x10\x00", enc.code(), "sbb ax, 0x10");
11691217
1170 try enc.encode(.xor, &.{1218 try enc.encode(.xor, &.{
1171 .{ .reg = .al },1219 .{ .reg = .al },
1172 .{ .imm = Immediate.u(0x10) },1220 .{ .imm = Instruction.Immediate.u(0x10) },
1173 });1221 });
1174 try expectEqualHexStrings("\x34\x10", enc.code(), "xor al, 0x10");1222 try expectEqualHexStrings("\x34\x10", enc.code(), "xor al, 0x10");
1175}1223}
...@@ -1179,43 +1227,43 @@ test "lower MI encoding" {...@@ -1179,43 +1227,43 @@ test "lower MI encoding" {
11791227
1180 try enc.encode(.mov, &.{1228 try enc.encode(.mov, &.{
1181 .{ .reg = .r12 },1229 .{ .reg = .r12 },
1182 .{ .imm = Immediate.u(0x1000) },1230 .{ .imm = Instruction.Immediate.u(0x1000) },
1183 });1231 });
1184 try expectEqualHexStrings("\x49\xC7\xC4\x00\x10\x00\x00", enc.code(), "mov r12, 0x1000");1232 try expectEqualHexStrings("\x49\xC7\xC4\x00\x10\x00\x00", enc.code(), "mov r12, 0x1000");
11851233
1186 try enc.encode(.mov, &.{1234 try enc.encode(.mov, &.{
1187 .{ .mem = Instruction.Memory.sib(.byte, .{ .base = .{ .reg = .r12 } }) },1235 .{ .mem = Instruction.Memory.sib(.byte, .{ .base = .{ .reg = .r12 } }) },
1188 .{ .imm = Immediate.u(0x10) },1236 .{ .imm = Instruction.Immediate.u(0x10) },
1189 });1237 });
1190 try expectEqualHexStrings("\x41\xC6\x04\x24\x10", enc.code(), "mov BYTE PTR [r12], 0x10");1238 try expectEqualHexStrings("\x41\xC6\x04\x24\x10", enc.code(), "mov BYTE PTR [r12], 0x10");
11911239
1192 try enc.encode(.mov, &.{1240 try enc.encode(.mov, &.{
1193 .{ .reg = .r12 },1241 .{ .reg = .r12 },
1194 .{ .imm = Immediate.u(0x1000) },1242 .{ .imm = Instruction.Immediate.u(0x1000) },
1195 });1243 });
1196 try expectEqualHexStrings("\x49\xC7\xC4\x00\x10\x00\x00", enc.code(), "mov r12, 0x1000");1244 try expectEqualHexStrings("\x49\xC7\xC4\x00\x10\x00\x00", enc.code(), "mov r12, 0x1000");
11971245
1198 try enc.encode(.mov, &.{1246 try enc.encode(.mov, &.{
1199 .{ .reg = .r12 },1247 .{ .reg = .r12 },
1200 .{ .imm = Immediate.u(0x1000) },1248 .{ .imm = Instruction.Immediate.u(0x1000) },
1201 });1249 });
1202 try expectEqualHexStrings("\x49\xC7\xC4\x00\x10\x00\x00", enc.code(), "mov r12, 0x1000");1250 try expectEqualHexStrings("\x49\xC7\xC4\x00\x10\x00\x00", enc.code(), "mov r12, 0x1000");
12031251
1204 try enc.encode(.mov, &.{1252 try enc.encode(.mov, &.{
1205 .{ .reg = .rax },1253 .{ .reg = .rax },
1206 .{ .imm = Immediate.u(0x10) },1254 .{ .imm = Instruction.Immediate.u(0x10) },
1207 });1255 });
1208 try expectEqualHexStrings("\x48\xc7\xc0\x10\x00\x00\x00", enc.code(), "mov rax, 0x10");1256 try expectEqualHexStrings("\x48\xc7\xc0\x10\x00\x00\x00", enc.code(), "mov rax, 0x10");
12091257
1210 try enc.encode(.mov, &.{1258 try enc.encode(.mov, &.{
1211 .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .r11 } }) },1259 .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .r11 } }) },
1212 .{ .imm = Immediate.u(0x10) },1260 .{ .imm = Instruction.Immediate.u(0x10) },
1213 });1261 });
1214 try expectEqualHexStrings("\x41\xc7\x03\x10\x00\x00\x00", enc.code(), "mov DWORD PTR [r11], 0x10");1262 try expectEqualHexStrings("\x41\xc7\x03\x10\x00\x00\x00", enc.code(), "mov DWORD PTR [r11], 0x10");
12151263
1216 try enc.encode(.mov, &.{1264 try enc.encode(.mov, &.{
1217 .{ .mem = Instruction.Memory.rip(.qword, 0x10) },1265 .{ .mem = Instruction.Memory.rip(.qword, 0x10) },
1218 .{ .imm = Immediate.u(0x10) },1266 .{ .imm = Instruction.Immediate.u(0x10) },
1219 });1267 });
1220 try expectEqualHexStrings(1268 try expectEqualHexStrings(
1221 "\x48\xC7\x05\x10\x00\x00\x00\x10\x00\x00\x00",1269 "\x48\xC7\x05\x10\x00\x00\x00\x10\x00\x00\x00",
...@@ -1225,19 +1273,19 @@ test "lower MI encoding" {...@@ -1225,19 +1273,19 @@ test "lower MI encoding" {
12251273
1226 try enc.encode(.mov, &.{1274 try enc.encode(.mov, &.{
1227 .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .rbp }, .disp = -8 }) },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 try expectEqualHexStrings("\x48\xc7\x45\xf8\x10\x00\x00\x00", enc.code(), "mov QWORD PTR [rbp - 8], 0x10");1278 try expectEqualHexStrings("\x48\xc7\x45\xf8\x10\x00\x00\x00", enc.code(), "mov QWORD PTR [rbp - 8], 0x10");
12311279
1232 try enc.encode(.mov, &.{1280 try enc.encode(.mov, &.{
1233 .{ .mem = Instruction.Memory.sib(.word, .{ .base = .{ .reg = .rbp }, .disp = -2 }) },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 try expectEqualHexStrings("\x66\xC7\x45\xFE\xF0\xFF", enc.code(), "mov WORD PTR [rbp - 2], -16");1284 try expectEqualHexStrings("\x66\xC7\x45\xFE\xF0\xFF", enc.code(), "mov WORD PTR [rbp - 2], -16");
12371285
1238 try enc.encode(.mov, &.{1286 try enc.encode(.mov, &.{
1239 .{ .mem = Instruction.Memory.sib(.byte, .{ .base = .{ .reg = .rbp }, .disp = -1 }) },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 try expectEqualHexStrings("\xC6\x45\xFF\x10", enc.code(), "mov BYTE PTR [rbp - 1], 0x10");1290 try expectEqualHexStrings("\xC6\x45\xFF\x10", enc.code(), "mov BYTE PTR [rbp - 1], 0x10");
12431291
...@@ -1247,7 +1295,7 @@ test "lower MI encoding" {...@@ -1247,7 +1295,7 @@ test "lower MI encoding" {
1247 .disp = 0x10000000,1295 .disp = 0x10000000,
1248 .scale_index = .{ .scale = 2, .index = .rcx },1296 .scale_index = .{ .scale = 2, .index = .rcx },
1249 }) },1297 }) },
1250 .{ .imm = Immediate.u(0x10) },1298 .{ .imm = Instruction.Immediate.u(0x10) },
1251 });1299 });
1252 try expectEqualHexStrings(1300 try expectEqualHexStrings(
1253 "\x48\xC7\x04\x4D\x00\x00\x00\x10\x10\x00\x00\x00",1301 "\x48\xC7\x04\x4D\x00\x00\x00\x10\x10\x00\x00\x00",
...@@ -1257,43 +1305,43 @@ test "lower MI encoding" {...@@ -1257,43 +1305,43 @@ test "lower MI encoding" {
12571305
1258 try enc.encode(.adc, &.{1306 try enc.encode(.adc, &.{
1259 .{ .mem = Instruction.Memory.sib(.byte, .{ .base = .{ .reg = .rbp }, .disp = -0x10 }) },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 try expectEqualHexStrings("\x80\x55\xF0\x10", enc.code(), "adc BYTE PTR [rbp - 0x10], 0x10");1310 try expectEqualHexStrings("\x80\x55\xF0\x10", enc.code(), "adc BYTE PTR [rbp - 0x10], 0x10");
12631311
1264 try enc.encode(.adc, &.{1312 try enc.encode(.adc, &.{
1265 .{ .mem = Instruction.Memory.rip(.qword, 0) },1313 .{ .mem = Instruction.Memory.rip(.qword, 0) },
1266 .{ .imm = Immediate.u(0x10) },1314 .{ .imm = Instruction.Immediate.u(0x10) },
1267 });1315 });
1268 try expectEqualHexStrings("\x48\x83\x15\x00\x00\x00\x00\x10", enc.code(), "adc QWORD PTR [rip], 0x10");1316 try expectEqualHexStrings("\x48\x83\x15\x00\x00\x00\x00\x10", enc.code(), "adc QWORD PTR [rip], 0x10");
12691317
1270 try enc.encode(.adc, &.{1318 try enc.encode(.adc, &.{
1271 .{ .reg = .rax },1319 .{ .reg = .rax },
1272 .{ .imm = Immediate.u(0x10) },1320 .{ .imm = Instruction.Immediate.u(0x10) },
1273 });1321 });
1274 try expectEqualHexStrings("\x48\x83\xD0\x10", enc.code(), "adc rax, 0x10");1322 try expectEqualHexStrings("\x48\x83\xD0\x10", enc.code(), "adc rax, 0x10");
12751323
1276 try enc.encode(.add, &.{1324 try enc.encode(.add, &.{
1277 .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .rdx }, .disp = -8 }) },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 try expectEqualHexStrings("\x83\x42\xF8\x10", enc.code(), "add DWORD PTR [rdx - 8], 0x10");1328 try expectEqualHexStrings("\x83\x42\xF8\x10", enc.code(), "add DWORD PTR [rdx - 8], 0x10");
12811329
1282 try enc.encode(.add, &.{1330 try enc.encode(.add, &.{
1283 .{ .reg = .rax },1331 .{ .reg = .rax },
1284 .{ .imm = Immediate.u(0x10) },1332 .{ .imm = Instruction.Immediate.u(0x10) },
1285 });1333 });
1286 try expectEqualHexStrings("\x48\x83\xC0\x10", enc.code(), "add rax, 0x10");1334 try expectEqualHexStrings("\x48\x83\xC0\x10", enc.code(), "add rax, 0x10");
12871335
1288 try enc.encode(.add, &.{1336 try enc.encode(.add, &.{
1289 .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .rbp }, .disp = -0x10 }) },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 try expectEqualHexStrings("\x48\x83\x45\xF0\xF0", enc.code(), "add QWORD PTR [rbp - 0x10], -0x10");1340 try expectEqualHexStrings("\x48\x83\x45\xF0\xF0", enc.code(), "add QWORD PTR [rbp - 0x10], -0x10");
12931341
1294 try enc.encode(.@"and", &.{1342 try enc.encode(.@"and", &.{
1295 .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .ds }, .disp = 0x10000000 }) },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 try expectEqualHexStrings(1346 try expectEqualHexStrings(
1299 "\x83\x24\x25\x00\x00\x00\x10\x10",1347 "\x83\x24\x25\x00\x00\x00\x10\x10",
...@@ -1303,7 +1351,7 @@ test "lower MI encoding" {...@@ -1303,7 +1351,7 @@ test "lower MI encoding" {
13031351
1304 try enc.encode(.@"and", &.{1352 try enc.encode(.@"and", &.{
1305 .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .es }, .disp = 0x10000000 }) },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 try expectEqualHexStrings(1356 try expectEqualHexStrings(
1309 "\x26\x83\x24\x25\x00\x00\x00\x10\x10",1357 "\x26\x83\x24\x25\x00\x00\x00\x10\x10",
...@@ -1313,7 +1361,7 @@ test "lower MI encoding" {...@@ -1313,7 +1361,7 @@ test "lower MI encoding" {
13131361
1314 try enc.encode(.@"and", &.{1362 try enc.encode(.@"and", &.{
1315 .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .r12 }, .disp = 0x10000000 }) },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 try expectEqualHexStrings(1366 try expectEqualHexStrings(
1319 "\x41\x83\xA4\x24\x00\x00\x00\x10\x10",1367 "\x41\x83\xA4\x24\x00\x00\x00\x10\x10",
...@@ -1323,7 +1371,7 @@ test "lower MI encoding" {...@@ -1323,7 +1371,7 @@ test "lower MI encoding" {
13231371
1324 try enc.encode(.sub, &.{1372 try enc.encode(.sub, &.{
1325 .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .r11 }, .disp = 0x10000000 }) },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 try expectEqualHexStrings(1376 try expectEqualHexStrings(
1329 "\x41\x83\xAB\x00\x00\x00\x10\x10",1377 "\x41\x83\xAB\x00\x00\x00\x10\x10",
...@@ -1542,14 +1590,14 @@ test "lower RMI encoding" {...@@ -1542,14 +1590,14 @@ test "lower RMI encoding" {
1542 try enc.encode(.imul, &.{1590 try enc.encode(.imul, &.{
1543 .{ .reg = .r11 },1591 .{ .reg = .r11 },
1544 .{ .reg = .r12 },1592 .{ .reg = .r12 },
1545 .{ .imm = Immediate.s(-2) },1593 .{ .imm = Instruction.Immediate.s(-2) },
1546 });1594 });
1547 try expectEqualHexStrings("\x4D\x6B\xDC\xFE", enc.code(), "imul r11, r12, -2");1595 try expectEqualHexStrings("\x4D\x6B\xDC\xFE", enc.code(), "imul r11, r12, -2");
15481596
1549 try enc.encode(.imul, &.{1597 try enc.encode(.imul, &.{
1550 .{ .reg = .r11 },1598 .{ .reg = .r11 },
1551 .{ .mem = Instruction.Memory.rip(.qword, -16) },1599 .{ .mem = Instruction.Memory.rip(.qword, -16) },
1552 .{ .imm = Immediate.s(-1024) },1600 .{ .imm = Instruction.Immediate.s(-1024) },
1553 });1601 });
1554 try expectEqualHexStrings(1602 try expectEqualHexStrings(
1555 "\x4C\x69\x1D\xF0\xFF\xFF\xFF\x00\xFC\xFF\xFF",1603 "\x4C\x69\x1D\xF0\xFF\xFF\xFF\x00\xFC\xFF\xFF",
...@@ -1560,7 +1608,7 @@ test "lower RMI encoding" {...@@ -1560,7 +1608,7 @@ test "lower RMI encoding" {
1560 try enc.encode(.imul, &.{1608 try enc.encode(.imul, &.{
1561 .{ .reg = .bx },1609 .{ .reg = .bx },
1562 .{ .mem = Instruction.Memory.sib(.word, .{ .base = .{ .reg = .rbp }, .disp = -16 }) },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 try expectEqualHexStrings(1613 try expectEqualHexStrings(
1566 "\x66\x69\x5D\xF0\x00\xFC",1614 "\x66\x69\x5D\xF0\x00\xFC",
...@@ -1571,7 +1619,7 @@ test "lower RMI encoding" {...@@ -1571,7 +1619,7 @@ test "lower RMI encoding" {
1571 try enc.encode(.imul, &.{1619 try enc.encode(.imul, &.{
1572 .{ .reg = .bx },1620 .{ .reg = .bx },
1573 .{ .mem = Instruction.Memory.sib(.word, .{ .base = .{ .reg = .rbp }, .disp = -16 }) },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 try expectEqualHexStrings(1624 try expectEqualHexStrings(
1577 "\x66\x69\x5D\xF0\x00\x04",1625 "\x66\x69\x5D\xF0\x00\x04",
...@@ -1687,7 +1735,7 @@ test "lower M encoding" {...@@ -1687,7 +1735,7 @@ test "lower M encoding" {
1687 try expectEqualHexStrings("\x65\xFF\x14\x25\x00\x00\x00\x00", enc.code(), "call gs:0x0");1735 try expectEqualHexStrings("\x65\xFF\x14\x25\x00\x00\x00\x00", enc.code(), "call gs:0x0");
16881736
1689 try enc.encode(.call, &.{1737 try enc.encode(.call, &.{
1690 .{ .imm = Immediate.s(0) },1738 .{ .imm = Instruction.Immediate.s(0) },
1691 });1739 });
1692 try expectEqualHexStrings("\xE8\x00\x00\x00\x00", enc.code(), "call 0x0");1740 try expectEqualHexStrings("\xE8\x00\x00\x00\x00", enc.code(), "call 0x0");
16931741
...@@ -1746,7 +1794,7 @@ test "lower OI encoding" {...@@ -1746,7 +1794,7 @@ test "lower OI encoding" {
17461794
1747 try enc.encode(.mov, &.{1795 try enc.encode(.mov, &.{
1748 .{ .reg = .rax },1796 .{ .reg = .rax },
1749 .{ .imm = Immediate.u(0x1000000000000000) },1797 .{ .imm = Instruction.Immediate.u(0x1000000000000000) },
1750 });1798 });
1751 try expectEqualHexStrings(1799 try expectEqualHexStrings(
1752 "\x48\xB8\x00\x00\x00\x00\x00\x00\x00\x10",1800 "\x48\xB8\x00\x00\x00\x00\x00\x00\x00\x10",
...@@ -1756,7 +1804,7 @@ test "lower OI encoding" {...@@ -1756,7 +1804,7 @@ test "lower OI encoding" {
17561804
1757 try enc.encode(.mov, &.{1805 try enc.encode(.mov, &.{
1758 .{ .reg = .r11 },1806 .{ .reg = .r11 },
1759 .{ .imm = Immediate.u(0x1000000000000000) },1807 .{ .imm = Instruction.Immediate.u(0x1000000000000000) },
1760 });1808 });
1761 try expectEqualHexStrings(1809 try expectEqualHexStrings(
1762 "\x49\xBB\x00\x00\x00\x00\x00\x00\x00\x10",1810 "\x49\xBB\x00\x00\x00\x00\x00\x00\x00\x10",
...@@ -1766,19 +1814,19 @@ test "lower OI encoding" {...@@ -1766,19 +1814,19 @@ test "lower OI encoding" {
17661814
1767 try enc.encode(.mov, &.{1815 try enc.encode(.mov, &.{
1768 .{ .reg = .r11d },1816 .{ .reg = .r11d },
1769 .{ .imm = Immediate.u(0x10000000) },1817 .{ .imm = Instruction.Immediate.u(0x10000000) },
1770 });1818 });
1771 try expectEqualHexStrings("\x41\xBB\x00\x00\x00\x10", enc.code(), "mov r11d, 0x10000000");1819 try expectEqualHexStrings("\x41\xBB\x00\x00\x00\x10", enc.code(), "mov r11d, 0x10000000");
17721820
1773 try enc.encode(.mov, &.{1821 try enc.encode(.mov, &.{
1774 .{ .reg = .r11w },1822 .{ .reg = .r11w },
1775 .{ .imm = Immediate.u(0x1000) },1823 .{ .imm = Instruction.Immediate.u(0x1000) },
1776 });1824 });
1777 try expectEqualHexStrings("\x66\x41\xBB\x00\x10", enc.code(), "mov r11w, 0x1000");1825 try expectEqualHexStrings("\x66\x41\xBB\x00\x10", enc.code(), "mov r11w, 0x1000");
17781826
1779 try enc.encode(.mov, &.{1827 try enc.encode(.mov, &.{
1780 .{ .reg = .r11b },1828 .{ .reg = .r11b },
1781 .{ .imm = Immediate.u(0x10) },1829 .{ .imm = Instruction.Immediate.u(0x10) },
1782 });1830 });
1783 try expectEqualHexStrings("\x41\xB3\x10", enc.code(), "mov r11b, 0x10");1831 try expectEqualHexStrings("\x41\xB3\x10", enc.code(), "mov r11b, 0x10");
1784}1832}
...@@ -1900,7 +1948,7 @@ test "invalid instruction" {...@@ -1900,7 +1948,7 @@ test "invalid instruction" {
1900 .{ .reg = .r12d },1948 .{ .reg = .r12d },
1901 });1949 });
1902 try invalidInstruction(.push, &.{1950 try invalidInstruction(.push, &.{
1903 .{ .imm = Immediate.u(0x1000000000000000) },1951 .{ .imm = Instruction.Immediate.u(0x1000000000000000) },
1904 });1952 });
1905}1953}
19061954
...@@ -2213,7 +2261,7 @@ const Assembler = struct {...@@ -2213,7 +2261,7 @@ const Assembler = struct {
2213 .immediate => {2261 .immediate => {
2214 const is_neg = if (as.expect(.minus)) |_| true else |_| false;2262 const is_neg = if (as.expect(.minus)) |_| true else |_| false;
2215 const imm_tok = try as.expect(.numeral);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 const imm = try std.fmt.parseInt(i32, as.source(imm_tok), 0);2265 const imm = try std.fmt.parseInt(i32, as.source(imm_tok), 0);
2218 break :blk .{ .signed = imm * -1 };2266 break :blk .{ .signed = imm * -1 };
2219 } else .{ .unsigned = try std.fmt.parseInt(u64, as.source(imm_tok), 0) };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,6 +828,9 @@ pub const GenResult = union(enum) {
828 /// Reference to memory location but deferred until linker allocated the Decl in memory.828 /// Reference to memory location but deferred until linker allocated the Decl in memory.
829 /// Traditionally, this corresponds to emitting a relocation in a relocatable object file.829 /// Traditionally, this corresponds to emitting a relocation in a relocatable object file.
830 load_symbol: u32,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 };
832835
833 fn mcv(val: MCValue) GenResult {836 fn mcv(val: MCValue) GenResult {
...@@ -895,16 +898,15 @@ fn genNavRef(...@@ -895,16 +898,15 @@ fn genNavRef(
895 if (lf.cast(.elf)) |elf_file| {898 if (lf.cast(.elf)) |elf_file| {
896 const zo = elf_file.zigObjectPtr().?;899 const zo = elf_file.zigObjectPtr().?;
897 if (is_extern) {900 if (is_extern) {
898 // TODO audit this
899 const sym_index = try elf_file.getGlobalSymbol(name.toSlice(ip), lib_name.toSlice(ip));901 const sym_index = try elf_file.getGlobalSymbol(name.toSlice(ip), lib_name.toSlice(ip));
900 zo.symbol(sym_index).flags.needs_got = true;902 zo.symbol(sym_index).flags.is_extern_ptr = true;
901 return GenResult.mcv(.{ .load_symbol = sym_index });903 return GenResult.mcv(.{ .lea_symbol = sym_index });
902 }904 }
903 const sym_index = try zo.getOrCreateMetadataForNav(elf_file, nav_index);905 const sym_index = try zo.getOrCreateMetadataForNav(elf_file, nav_index);
904 if (!single_threaded and is_threadlocal) {906 if (!single_threaded and is_threadlocal) {
905 return GenResult.mcv(.{ .load_tlv = sym_index });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 } else if (lf.cast(.macho)) |macho_file| {910 } else if (lf.cast(.macho)) |macho_file| {
909 const zo = macho_file.getZigObject().?;911 const zo = macho_file.getZigObject().?;
910 if (is_extern) {912 if (is_extern) {
src/link/Elf.zig+11-104
...@@ -64,9 +64,6 @@ phdrs: std.ArrayListUnmanaged(elf.Elf64_Phdr) = .{},...@@ -64,9 +64,6 @@ phdrs: std.ArrayListUnmanaged(elf.Elf64_Phdr) = .{},
64/// Tracked loadable segments during incremental linking.64/// Tracked loadable segments during incremental linking.
65/// The index into the program headers of a PT_LOAD program header with Read and Execute flags65/// The index into the program headers of a PT_LOAD program header with Read and Execute flags
66phdr_zig_load_re_index: ?u16 = null,66phdr_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.
69phdr_zig_got_index: ?u16 = null,
70/// The index into the program headers of a PT_LOAD program header with Read flag67/// The index into the program headers of a PT_LOAD program header with Read flag
71phdr_zig_load_ro_index: ?u16 = null,68phdr_zig_load_ro_index: ?u16 = null,
72/// The index into the program headers of a PT_LOAD program header with Write flag69/// The index into the program headers of a PT_LOAD program header with Write flag
...@@ -130,8 +127,6 @@ plt_got: PltGotSection = .{},...@@ -130,8 +127,6 @@ plt_got: PltGotSection = .{},
130copy_rel: CopyRelSection = .{},127copy_rel: CopyRelSection = .{},
131/// .rela.plt section128/// .rela.plt section
132rela_plt: std.ArrayListUnmanaged(elf.Elf64_Rela) = .{},129rela_plt: std.ArrayListUnmanaged(elf.Elf64_Rela) = .{},
133/// .got.zig section
134zig_got: ZigGotSection = .{},
135/// SHT_GROUP sections130/// SHT_GROUP sections
136/// Applies only to a relocatable.131/// Applies only to a relocatable.
137comdat_group_sections: std.ArrayListUnmanaged(ComdatGroupSection) = .{},132comdat_group_sections: std.ArrayListUnmanaged(ComdatGroupSection) = .{},
...@@ -142,7 +137,6 @@ zig_text_section_index: ?u32 = null,...@@ -142,7 +137,6 @@ zig_text_section_index: ?u32 = null,
142zig_data_rel_ro_section_index: ?u32 = null,137zig_data_rel_ro_section_index: ?u32 = null,
143zig_data_section_index: ?u32 = null,138zig_data_section_index: ?u32 = null,
144zig_bss_section_index: ?u32 = null,139zig_bss_section_index: ?u32 = null,
145zig_got_section_index: ?u32 = null,
146140
147debug_info_section_index: ?u32 = null,141debug_info_section_index: ?u32 = null,
148debug_abbrev_section_index: ?u32 = null,142debug_abbrev_section_index: ?u32 = null,
...@@ -474,7 +468,6 @@ pub fn deinit(self: *Elf) void {...@@ -474,7 +468,6 @@ pub fn deinit(self: *Elf) void {
474 self.copy_rel.deinit(gpa);468 self.copy_rel.deinit(gpa);
475 self.rela_dyn.deinit(gpa);469 self.rela_dyn.deinit(gpa);
476 self.rela_plt.deinit(gpa);470 self.rela_plt.deinit(gpa);
477 self.zig_got.deinit(gpa);
478 self.comdat_group_sections.deinit(gpa);471 self.comdat_group_sections.deinit(gpa);
479}472}
480473
...@@ -611,28 +604,13 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {...@@ -611,28 +604,13 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {
611 .type = elf.PT_LOAD,604 .type = elf.PT_LOAD,
612 .offset = off,605 .offset = off,
613 .filesz = filesz,606 .filesz = filesz,
614 .addr = if (ptr_bit_width >= 32) 0x8000000 else 0x8000,607 .addr = if (ptr_bit_width >= 32) 0x4000000 else 0x4000,
615 .memsz = filesz,608 .memsz = filesz,
616 .@"align" = self.page_size,609 .@"align" = self.page_size,
617 .flags = elf.PF_X | elf.PF_R | elf.PF_W,610 .flags = elf.PF_X | elf.PF_R | elf.PF_W,
618 });611 });
619 }612 }
620613
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 if (self.phdr_zig_load_ro_index == null) {614 if (self.phdr_zig_load_ro_index == null) {
637 const alignment = self.page_size;615 const alignment = self.page_size;
638 const filesz: u64 = 1024;616 const filesz: u64 = 1024;
...@@ -701,27 +679,6 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {...@@ -701,27 +679,6 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {
701 try self.last_atom_and_free_list_table.putNoClobber(gpa, self.zig_text_section_index.?, .{});679 try self.last_atom_and_free_list_table.putNoClobber(gpa, self.zig_text_section_index.?, .{});
702 }680 }
703681
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 if (self.zig_data_rel_ro_section_index == null) {682 if (self.zig_data_rel_ro_section_index == null) {
726 self.zig_data_rel_ro_section_index = try self.addSection(.{683 self.zig_data_rel_ro_section_index = try self.addSection(.{
727 .name = try self.insertShString(".data.rel.ro.zig"),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,6 +857,11 @@ pub fn growAllocSection(self: *Elf, shdr_index: u32, needed_size: u64) !void {
900 const shdr = &self.shdrs.items[shdr_index];857 const shdr = &self.shdrs.items[shdr_index];
901 const maybe_phdr = if (self.phdr_to_shdr_table.get(shdr_index)) |phndx| &self.phdrs.items[phndx] else null;858 const maybe_phdr = if (self.phdr_to_shdr_table.get(shdr_index)) |phndx| &self.phdrs.items[phndx] else null;
902 const is_zerofill = shdr.sh_type == elf.SHT_NOBITS;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 });
903865
904 if (needed_size > self.allocatedSize(shdr.sh_offset) and !is_zerofill) {866 if (needed_size > self.allocatedSize(shdr.sh_offset) and !is_zerofill) {
905 const existing_size = shdr.sh_size;867 const existing_size = shdr.sh_size;
...@@ -3156,8 +3118,8 @@ fn initSyntheticSections(self: *Elf) !void {...@@ -3156,8 +3118,8 @@ fn initSyntheticSections(self: *Elf) !void {
3156 });3118 });
31573119
3158 const needs_rela_dyn = blk: {3120 const needs_rela_dyn = blk: {
3159 if (self.got.flags.needs_rela or self.got.flags.needs_tlsld or3121 if (self.got.flags.needs_rela or self.got.flags.needs_tlsld or self.copy_rel.symbols.items.len > 0)
3160 self.zig_got.flags.needs_rela or self.copy_rel.symbols.items.len > 0) break :blk true;3122 break :blk true;
3161 if (self.zigObjectPtr()) |zig_object| {3123 if (self.zigObjectPtr()) |zig_object| {
3162 if (zig_object.num_dynrelocs > 0) break :blk true;3124 if (zig_object.num_dynrelocs > 0) break :blk true;
3163 }3125 }
...@@ -3562,7 +3524,6 @@ fn sortPhdrs(self: *Elf) error{OutOfMemory}!void {...@@ -3562,7 +3524,6 @@ fn sortPhdrs(self: *Elf) error{OutOfMemory}!void {
35623524
3563 for (&[_]*?u16{3525 for (&[_]*?u16{
3564 &self.phdr_zig_load_re_index,3526 &self.phdr_zig_load_re_index,
3565 &self.phdr_zig_got_index,
3566 &self.phdr_zig_load_ro_index,3527 &self.phdr_zig_load_ro_index,
3567 &self.phdr_zig_load_zerofill_index,3528 &self.phdr_zig_load_zerofill_index,
3568 &self.phdr_table_index,3529 &self.phdr_table_index,
...@@ -3694,7 +3655,6 @@ fn resetShdrIndexes(self: *Elf, backlinks: []const u32) !void {...@@ -3694,7 +3655,6 @@ fn resetShdrIndexes(self: *Elf, backlinks: []const u32) !void {
3694 &self.versym_section_index,3655 &self.versym_section_index,
3695 &self.verneed_section_index,3656 &self.verneed_section_index,
3696 &self.zig_text_section_index,3657 &self.zig_text_section_index,
3697 &self.zig_got_section_index,
3698 &self.zig_data_rel_ro_section_index,3658 &self.zig_data_rel_ro_section_index,
3699 &self.zig_data_section_index,3659 &self.zig_data_section_index,
3700 &self.zig_bss_section_index,3660 &self.zig_bss_section_index,
...@@ -3893,7 +3853,7 @@ fn updateSectionSizes(self: *Elf) !void {...@@ -3893,7 +3853,7 @@ fn updateSectionSizes(self: *Elf) !void {
3893 }3853 }
38943854
3895 if (self.rela_dyn_section_index) |shndx| {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 if (self.zigObjectPtr()) |zig_object| {3857 if (self.zigObjectPtr()) |zig_object| {
3898 num += zig_object.num_dynrelocs;3858 num += zig_object.num_dynrelocs;
3899 }3859 }
...@@ -4431,15 +4391,6 @@ pub fn updateSymtabSize(self: *Elf) !void {...@@ -4431,15 +4391,6 @@ pub fn updateSymtabSize(self: *Elf) !void {
4431 strsize += ctx.strsize;4391 strsize += ctx.strsize;
4432 }4392 }
44334393
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 if (self.got_section_index) |_| {4394 if (self.got_section_index) |_| {
4444 self.got.output_symtab_ctx.ilocal = nlocals + 1;4395 self.got.output_symtab_ctx.ilocal = nlocals + 1;
4445 self.got.updateSymtabSize(self);4396 self.got.updateSymtabSize(self);
...@@ -4576,9 +4527,6 @@ fn writeSyntheticSections(self: *Elf) !void {...@@ -4576,9 +4527,6 @@ fn writeSyntheticSections(self: *Elf) !void {
4576 const shdr = self.shdrs.items[shndx];4527 const shdr = self.shdrs.items[shndx];
4577 try self.got.addRela(self);4528 try self.got.addRela(self);
4578 try self.copy_rel.addRela(self);4529 try self.copy_rel.addRela(self);
4579 if (self.zigObjectPtr()) |_| {
4580 try self.zig_got.addRela(self);
4581 }
4582 self.sortRelaDyn();4530 self.sortRelaDyn();
4583 try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.rela_dyn.items), shdr.sh_offset);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,10 +4622,6 @@ pub fn writeSymtab(self: *Elf) !void {
4674 obj.asFile().writeSymtab(self);4622 obj.asFile().writeSymtab(self);
4675 }4623 }
46764624
4677 if (self.zig_got_section_index) |_| {
4678 self.zig_got.writeSymtab(self);
4679 }
4680
4681 if (self.got_section_index) |_| {4625 if (self.got_section_index) |_| {
4682 self.got.writeSymtab(self);4626 self.got.writeSymtab(self);
4683 }4627 }
...@@ -5085,7 +5029,6 @@ pub fn isZigSection(self: Elf, shndx: u32) bool {...@@ -5085,7 +5029,6 @@ pub fn isZigSection(self: Elf, shndx: u32) bool {
5085 self.zig_data_rel_ro_section_index,5029 self.zig_data_rel_ro_section_index,
5086 self.zig_data_section_index,5030 self.zig_data_section_index,
5087 self.zig_bss_section_index,5031 self.zig_bss_section_index,
5088 self.zig_got_section_index,
5089 }) |maybe_index| {5032 }) |maybe_index| {
5090 if (maybe_index) |index| {5033 if (maybe_index) |index| {
5091 if (index == shndx) return true;5034 if (index == shndx) return true;
...@@ -5657,10 +5600,11 @@ fn fmtDumpState(...@@ -5657,10 +5600,11 @@ fn fmtDumpState(
56575600
5658 if (self.zigObjectPtr()) |zig_object| {5601 if (self.zigObjectPtr()) |zig_object| {
5659 try writer.print("zig_object({d}) : {s}\n", .{ zig_object.index, zig_object.path });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 zig_object.fmtAtoms(self),5604 zig_object.fmtAtoms(self),
5662 zig_object.fmtSymtab(self),5605 zig_object.fmtSymtab(self),
5663 });5606 });
5607 try writer.writeByte('\n');
5664 }5608 }
56655609
5666 for (self.objects.items) |index| {5610 for (self.objects.items) |index| {
...@@ -5700,7 +5644,6 @@ fn fmtDumpState(...@@ -5700,7 +5644,6 @@ fn fmtDumpState(
5700 }5644 }
5701 }5645 }
57025646
5703 try writer.print("{}\n", .{self.zig_got.fmt(self)});
5704 try writer.print("{}\n", .{self.got.fmt(self)});5647 try writer.print("{}\n", .{self.got.fmt(self)});
5705 try writer.print("{}\n", .{self.plt.fmt(self)});5648 try writer.print("{}\n", .{self.plt.fmt(self)});
57065649
...@@ -5991,41 +5934,6 @@ const RelaSection = struct {...@@ -5991,41 +5934,6 @@ const RelaSection = struct {
5991};5934};
5992const RelaSectionTable = std.AutoArrayHashMapUnmanaged(u32, RelaSection);5935const RelaSectionTable = std.AutoArrayHashMapUnmanaged(u32, RelaSection);
59935936
5994pub const R_ZIG_GOT32: u32 = 0xff00;
5995pub const R_ZIG_GOTPCREL: u32 = 0xff01;
5996pub const R_ZIG_GOT_HI20: u32 = 0xff02;
5997pub const R_ZIG_GOT_LO12: u32 = 0xff03;
5998pub const R_GOT_HI20_STATIC: u32 = 0xff04;
5999pub const R_GOT_LO12_I_STATIC: u32 = 0xff05;
6000
6001// Comptime asserts that no Zig relocs overlap with another ISA's reloc number
6002comptime {
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
6029fn defaultEntrySymbolName(cpu_arch: std.Target.Cpu.Arch) []const u8 {5937fn defaultEntrySymbolName(cpu_arch: std.Target.Cpu.Arch) []const u8 {
6030 return switch (cpu_arch) {5938 return switch (cpu_arch) {
6031 .mips, .mipsel, .mips64, .mips64el => "__start",5939 .mips, .mipsel, .mips64, .mips64el => "__start",
...@@ -6095,6 +6003,5 @@ const StringTable = @import("StringTable.zig");...@@ -6095,6 +6003,5 @@ const StringTable = @import("StringTable.zig");
6095const Thunk = thunks.Thunk;6003const Thunk = thunks.Thunk;
6096const Value = @import("../Value.zig");6004const Value = @import("../Value.zig");
6097const VerneedSection = synthetic_sections.VerneedSection;6005const VerneedSection = synthetic_sections.VerneedSection;
6098const ZigGotSection = synthetic_sections.ZigGotSection;
6099const ZigObject = @import("Elf/ZigObject.zig");6006const ZigObject = @import("Elf/ZigObject.zig");
6100const riscv = @import("riscv.zig");6007const 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,12 +746,10 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) RelocError!voi
746 const P = self.address(elf_file) + @as(i64, @intCast(rel.r_offset));746 const P = self.address(elf_file) + @as(i64, @intCast(rel.r_offset));
747 // Addend from the relocation.747 // Addend from the relocation.
748 const A = rel.r_addend;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 const S = target.address(.{}, elf_file);750 const S = target.address(.{}, elf_file);
751 // Address of the global offset table.751 // Address of the global offset table.
752 const GOT = elf_file.gotAddress();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 // Relative offset to the start of the global offset table.753 // Relative offset to the start of the global offset table.
756 const G = target.gotAddress(elf_file) - GOT;754 const G = target.gotAddress(elf_file) - GOT;
757 // // Address of the thread pointer.755 // // Address of the thread pointer.
...@@ -759,19 +757,18 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) RelocError!voi...@@ -759,19 +757,18 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) RelocError!voi
759 // Address of the dynamic thread pointer.757 // Address of the dynamic thread pointer.
760 const DTP = elf_file.dtpAddress();758 const DTP = elf_file.dtpAddress();
761759
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 relocation.fmtRelocType(rel.r_type(), cpu_arch),761 relocation.fmtRelocType(rel.r_type(), cpu_arch),
764 r_offset,762 r_offset,
765 P,763 P,
766 S + A,764 S + A,
767 G + GOT + A,765 G + GOT + A,
768 ZIG_GOT + A,
769 target.name(elf_file),766 target.name(elf_file),
770 });767 });
771768
772 try stream.seekTo(r_offset);769 try stream.seekTo(r_offset);
773770
774 const args = ResolveArgs{ P, A, S, GOT, G, TP, DTP, ZIG_GOT };771 const args = ResolveArgs{ P, A, S, GOT, G, TP, DTP };
775772
776 switch (cpu_arch) {773 switch (cpu_arch) {
777 .x86_64 => x86_64.resolveRelocAlloc(self, elf_file, rel, target, args, &it, code, &stream) catch |err| switch (err) {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,7 +953,7 @@ pub fn resolveRelocsNonAlloc(self: Atom, elf_file: *Elf, code: []u8, undefs: any
956 // Address of the dynamic thread pointer.953 // Address of the dynamic thread pointer.
957 const DTP = elf_file.dtpAddress();954 const DTP = elf_file.dtpAddress();
958955
959 const args = ResolveArgs{ P, A, S, GOT, 0, 0, DTP, 0 };956 const args = ResolveArgs{ P, A, S, GOT, 0, 0, DTP };
960957
961 relocs_log.debug(" {}: {x}: [{x} => {x}] ({s})", .{958 relocs_log.debug(" {}: {x}: [{x} => {x}] ({s})", .{
962 relocation.fmtRelocType(rel.r_type(), cpu_arch),959 relocation.fmtRelocType(rel.r_type(), cpu_arch),
...@@ -1025,7 +1022,7 @@ pub fn format(...@@ -1025,7 +1022,7 @@ pub fn format(
1025 _ = unused_fmt_string;1022 _ = unused_fmt_string;
1026 _ = options;1023 _ = options;
1027 _ = writer;1024 _ = writer;
1028 @compileError("do not format symbols directly");1025 @compileError("do not format Atom directly");
1029}1026}
10301027
1031pub fn fmt(atom: Atom, elf_file: *Elf) std.fmt.Formatter(format2) {1028pub fn fmt(atom: Atom, elf_file: *Elf) std.fmt.Formatter(format2) {
...@@ -1051,8 +1048,8 @@ fn format2(...@@ -1051,8 +1048,8 @@ fn format2(
1051 const atom = ctx.atom;1048 const atom = ctx.atom;
1052 const elf_file = ctx.elf_file;1049 const elf_file = ctx.elf_file;
1053 try writer.print("atom({d}) : {s} : @{x} : shdr({d}) : align({x}) : size({x})", .{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),1051 atom.atom_index, atom.name(elf_file), atom.address(elf_file),
1055 atom.output_section_index, atom.alignment, atom.size,1052 atom.output_section_index, atom.alignment.toByteUnits() orelse 0, atom.size,
1056 });1053 });
1057 if (atom.fdes(elf_file).len > 0) {1054 if (atom.fdes(elf_file).len > 0) {
1058 try writer.writeAll(" : fdes{ ");1055 try writer.writeAll(" : fdes{ ");
...@@ -1180,16 +1177,7 @@ const x86_64 = struct {...@@ -1180,16 +1177,7 @@ const x86_64 = struct {
1180 .TLSDESC_CALL,1177 .TLSDESC_CALL,
1181 => {},1178 => {},
11821179
1183 else => |x| switch (@intFromEnum(x)) {1180 else => try atom.reportUnhandledRelocError(rel, elf_file),
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 },
1193 }1181 }
1194 }1182 }
11951183
...@@ -1209,7 +1197,7 @@ const x86_64 = struct {...@@ -1209,7 +1197,7 @@ const x86_64 = struct {
12091197
1210 const cwriter = stream.writer();1198 const cwriter = stream.writer();
12111199
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;
12131201
1214 switch (r_type) {1202 switch (r_type) {
1215 .NONE => unreachable,1203 .NONE => unreachable,
...@@ -1224,9 +1212,8 @@ const x86_64 = struct {...@@ -1224,9 +1212,8 @@ const x86_64 = struct {
1224 );1212 );
1225 },1213 },
12261214
1227 .PLT32,1215 .PLT32 => try cwriter.writeInt(i32, @as(i32, @intCast(S + A - P)), .little),
1228 .PC32,1216 .PC32 => try cwriter.writeInt(i32, @as(i32, @intCast(S + A - P)), .little),
1229 => try cwriter.writeInt(i32, @as(i32, @intCast(S + A - P)), .little),
12301217
1231 .GOTPCREL => try cwriter.writeInt(i32, @as(i32, @intCast(G + GOT + A - P)), .little),1218 .GOTPCREL => try cwriter.writeInt(i32, @as(i32, @intCast(G + GOT + A - P)), .little),
1232 .GOTPC32 => try cwriter.writeInt(i32, @as(i32, @intCast(GOT + A - P)), .little),1219 .GOTPC32 => try cwriter.writeInt(i32, @as(i32, @intCast(GOT + A - P)), .little),
...@@ -1327,15 +1314,9 @@ const x86_64 = struct {...@@ -1327,15 +1314,9 @@ const x86_64 = struct {
1327 }1314 }
1328 },1315 },
13291316
1330 .GOT32 => try cwriter.writeInt(i32, @as(i32, @intCast(G + GOT + A)), .little),1317 .GOT32 => try cwriter.writeInt(i32, @as(i32, @intCast(G + 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),
13361318
1337 else => try atom.reportUnhandledRelocError(rel, elf_file),1319 else => try atom.reportUnhandledRelocError(rel, elf_file),
1338 },
1339 }1320 }
1340 }1321 }
13411322
...@@ -1355,7 +1336,7 @@ const x86_64 = struct {...@@ -1355,7 +1336,7 @@ const x86_64 = struct {
1355 const r_type: elf.R_X86_64 = @enumFromInt(rel.r_type());1336 const r_type: elf.R_X86_64 = @enumFromInt(rel.r_type());
1356 const cwriter = stream.writer();1337 const cwriter = stream.writer();
13571338
1358 _, const A, const S, const GOT, _, _, const DTP, _ = args;1339 _, const A, const S, const GOT, _, _, const DTP = args;
13591340
1360 switch (r_type) {1341 switch (r_type) {
1361 .NONE => unreachable,1342 .NONE => unreachable,
...@@ -1629,7 +1610,7 @@ const x86_64 = struct {...@@ -1629,7 +1610,7 @@ const x86_64 = struct {
1629 const bits = @import("../../arch/x86_64/bits.zig");1610 const bits = @import("../../arch/x86_64/bits.zig");
1630 const encoder = @import("../../arch/x86_64/encoder.zig");1611 const encoder = @import("../../arch/x86_64/encoder.zig");
1631 const Disassembler = @import("../../arch/x86_64/Disassembler.zig");1612 const Disassembler = @import("../../arch/x86_64/Disassembler.zig");
1632 const Immediate = bits.Immediate;1613 const Immediate = Instruction.Immediate;
1633 const Instruction = encoder.Instruction;1614 const Instruction = encoder.Instruction;
1634};1615};
16351616
...@@ -1738,9 +1719,8 @@ const aarch64 = struct {...@@ -1738,9 +1719,8 @@ const aarch64 = struct {
1738 const code = code_buffer[r_offset..][0..4];1719 const code = code_buffer[r_offset..][0..4];
1739 const file_ptr = atom.file(elf_file).?;1720 const file_ptr = atom.file(elf_file).?;
17401721
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 _ = DTP;1723 _ = DTP;
1743 _ = ZIG_GOT;
17441724
1745 switch (r_type) {1725 switch (r_type) {
1746 .NONE => unreachable,1726 .NONE => unreachable,
...@@ -1942,7 +1922,7 @@ const aarch64 = struct {...@@ -1942,7 +1922,7 @@ const aarch64 = struct {
1942 const r_type: elf.R_AARCH64 = @enumFromInt(rel.r_type());1922 const r_type: elf.R_AARCH64 = @enumFromInt(rel.r_type());
1943 const cwriter = stream.writer();1923 const cwriter = stream.writer();
19441924
1945 _, const A, const S, _, _, _, _, _ = args;1925 _, const A, const S, _, _, _, _ = args;
19461926
1947 switch (r_type) {1927 switch (r_type) {
1948 .NONE => unreachable,1928 .NONE => unreachable,
...@@ -1998,19 +1978,7 @@ const riscv = struct {...@@ -1998,19 +1978,7 @@ const riscv = struct {
1998 .SUB32,1978 .SUB32,
1999 => {},1979 => {},
20001980
2001 else => |x| switch (@intFromEnum(x)) {1981 else => try atom.reportUnhandledRelocError(rel, elf_file),
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 },
2014 }1982 }
2015 }1983 }
20161984
...@@ -2028,7 +1996,7 @@ const riscv = struct {...@@ -2028,7 +1996,7 @@ const riscv = struct {
2028 const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow;1996 const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow;
2029 const cwriter = stream.writer();1997 const cwriter = stream.writer();
20301998
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 _ = TP;2000 _ = TP;
2033 _ = DTP;2001 _ = DTP;
20342002
...@@ -2147,34 +2115,7 @@ const riscv = struct {...@@ -2147,34 +2115,7 @@ const riscv = struct {
2147 // TODO: annotates an ADD instruction that can be removed when TPREL is relaxed2115 // TODO: annotates an ADD instruction that can be removed when TPREL is relaxed
2148 },2116 },
21492117
2150 else => |x| switch (@intFromEnum(x)) {2118 else => try atom.reportUnhandledRelocError(rel, elf_file),
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 },
2178 }2119 }
2179 }2120 }
21802121
...@@ -2194,7 +2135,7 @@ const riscv = struct {...@@ -2194,7 +2135,7 @@ const riscv = struct {
2194 const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow;2135 const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow;
2195 const cwriter = stream.writer();2136 const cwriter = stream.writer();
21962137
2197 _, const A, const S, const GOT, _, _, const DTP, _ = args;2138 _, const A, const S, const GOT, _, _, const DTP = args;
2198 _ = GOT;2139 _ = GOT;
2199 _ = DTP;2140 _ = DTP;
22002141
...@@ -2230,7 +2171,7 @@ const riscv = struct {...@@ -2230,7 +2171,7 @@ const riscv = struct {
2230 const riscv_util = @import("../riscv.zig");2171 const riscv_util = @import("../riscv.zig");
2231};2172};
22322173
2233const ResolveArgs = struct { i64, i64, i64, i64, i64, i64, i64, i64 };2174const ResolveArgs = struct { i64, i64, i64, i64, i64, i64, i64 };
22342175
2235const RelocError = error{2176const RelocError = error{
2236 Overflow,2177 Overflow,
src/link/Elf/Symbol.zig+22-30
...@@ -101,7 +101,7 @@ pub fn symbolRank(symbol: Symbol, elf_file: *Elf) u32 {...@@ -101,7 +101,7 @@ pub fn symbolRank(symbol: Symbol, elf_file: *Elf) u32 {
101 return file_ptr.symbolRank(sym, in_archive);101 return file_ptr.symbolRank(sym, in_archive);
102}102}
103103
104pub fn address(symbol: Symbol, opts: struct { plt: bool = true }, elf_file: *Elf) i64 {104pub fn address(symbol: Symbol, opts: struct { plt: bool = true, trampoline: bool = true }, elf_file: *Elf) i64 {
105 if (symbol.mergeSubsection(elf_file)) |msub| {105 if (symbol.mergeSubsection(elf_file)) |msub| {
106 if (!msub.alive) return 0;106 if (!msub.alive) return 0;
107 return msub.address(elf_file) + symbol.value;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,6 +109,9 @@ pub fn address(symbol: Symbol, opts: struct { plt: bool = true }, elf_file: *Elf
109 if (symbol.flags.has_copy_rel) {109 if (symbol.flags.has_copy_rel) {
110 return symbol.copyRelAddress(elf_file);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 if (symbol.flags.has_plt and opts.plt) {115 if (symbol.flags.has_plt and opts.plt) {
113 if (!symbol.flags.is_canonical and symbol.flags.has_got) {116 if (!symbol.flags.is_canonical and symbol.flags.has_got) {
114 // We have a non-lazy bound function pointer, use that!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,23 +220,11 @@ pub fn tlsDescAddress(symbol: Symbol, elf_file: *Elf) i64 {
217 return entry.address(elf_file);220 return entry.address(elf_file);
218}221}
219222
220const GetOrCreateZigGotEntryResult = struct {223pub fn trampolineAddress(symbol: Symbol, elf_file: *Elf) i64 {
221 found_existing: bool,224 if (!symbol.flags.has_trampoline) return 0;
222 index: ZigGotSection.Index,225 const zo = elf_file.zigObjectPtr().?;
223};226 const index = symbol.extra(elf_file).trampoline;
224227 return zo.symbol(index).address(.{}, elf_file);
225pub 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
233pub 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);
237}228}
238229
239pub fn dsoAlignment(symbol: Symbol, elf_file: *Elf) !u64 {230pub fn dsoAlignment(symbol: Symbol, elf_file: *Elf) !u64 {
...@@ -259,7 +250,7 @@ const AddExtraOpts = struct {...@@ -259,7 +250,7 @@ const AddExtraOpts = struct {
259 tlsgd: ?u32 = null,250 tlsgd: ?u32 = null,
260 gottp: ?u32 = null,251 gottp: ?u32 = null,
261 tlsdesc: ?u32 = null,252 tlsdesc: ?u32 = null,
262 zig_got: ?u32 = null,253 trampoline: ?u32 = null,
263};254};
264255
265pub fn addExtra(symbol: *Symbol, opts: AddExtraOpts, elf_file: *Elf) void {256pub 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,7 +303,7 @@ pub fn setOutputSym(symbol: Symbol, elf_file: *Elf, out: *elf.Elf64_Sym) void {
312 const shdr = elf_file.shdrs.items[st_shndx];303 const shdr = elf_file.shdrs.items[st_shndx];
313 if (shdr.sh_flags & elf.SHF_TLS != 0 and file_ptr != .linker_defined)304 if (shdr.sh_flags & elf.SHF_TLS != 0 and file_ptr != .linker_defined)
314 break :blk symbol.address(.{ .plt = false }, elf_file) - elf_file.tlsAddress();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 out.st_info = (st_bind << 4) | st_type;308 out.st_info = (st_bind << 4) | st_type;
318 out.st_other = esym.st_other;309 out.st_other = esym.st_other;
...@@ -331,7 +322,7 @@ pub fn format(...@@ -331,7 +322,7 @@ pub fn format(
331 _ = unused_fmt_string;322 _ = unused_fmt_string;
332 _ = options;323 _ = options;
333 _ = writer;324 _ = writer;
334 @compileError("do not format symbols directly");325 @compileError("do not format Symbol directly");
335}326}
336327
337const FormatContext = struct {328const FormatContext = struct {
...@@ -388,7 +379,7 @@ fn format2(...@@ -388,7 +379,7 @@ fn format2(
388 try writer.print("%{d} : {s} : @{x}", .{379 try writer.print("%{d} : {s} : @{x}", .{
389 symbol.esym_index,380 symbol.esym_index,
390 symbol.fmtName(elf_file),381 symbol.fmtName(elf_file),
391 symbol.address(.{}, elf_file),382 symbol.address(.{ .plt = false, .trampoline = false }, elf_file),
392 });383 });
393 if (symbol.file(elf_file)) |file_ptr| {384 if (symbol.file(elf_file)) |file_ptr| {
394 if (symbol.isAbs(elf_file)) {385 if (symbol.isAbs(elf_file)) {
...@@ -456,17 +447,18 @@ pub const Flags = packed struct {...@@ -456,17 +447,18 @@ pub const Flags = packed struct {
456 needs_tlsdesc: bool = false,447 needs_tlsdesc: bool = false,
457 has_tlsdesc: bool = false,448 has_tlsdesc: bool = false,
458449
459 /// Whether the symbol contains .zig.got indirection.450 /// Whether the symbol is a merge subsection.
460 needs_zig_got: bool = false,451 merge_subsection: bool = false,
461 has_zig_got: bool = false,452
453 /// ZigObject specific flags
454 /// Whether the symbol has a trampoline.
455 has_trampoline: bool = false,
462456
463 /// Whether the symbol is a TLS variable.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 is_tls: bool = false,458 is_tls: bool = false,
467459
468 /// Whether the symbol is a merge subsection.460 /// Whether the symbol is an extern pointer (as opposed to function).
469 merge_subsection: bool = false,461 is_extern_ptr: bool = false,
470};462};
471463
472pub const Extra = struct {464pub const Extra = struct {
...@@ -479,8 +471,8 @@ pub const Extra = struct {...@@ -479,8 +471,8 @@ pub const Extra = struct {
479 tlsgd: u32 = 0,471 tlsgd: u32 = 0,
480 gottp: u32 = 0,472 gottp: u32 = 0,
481 tlsdesc: u32 = 0,473 tlsdesc: u32 = 0,
482 zig_got: u32 = 0,
483 merge_section: u32 = 0,474 merge_section: u32 = 0,
475 trampoline: u32 = 0,
484};476};
485477
486pub const Index = u32;478pub const Index = u32;
src/link/Elf/ZigObject.zig+180-55
...@@ -102,23 +102,17 @@ pub fn deinit(self: *ZigObject, allocator: Allocator) void {...@@ -102,23 +102,17 @@ pub fn deinit(self: *ZigObject, allocator: Allocator) void {
102 }102 }
103 self.relocs.deinit(allocator);103 self.relocs.deinit(allocator);
104104
105 {105 for (self.navs.values()) |*meta| {
106 var it = self.navs.iterator();106 meta.exports.deinit(allocator);
107 while (it.next()) |entry| {
108 entry.value_ptr.exports.deinit(allocator);
109 }
110 self.navs.deinit(allocator);
111 }107 }
108 self.navs.deinit(allocator);
112109
113 self.lazy_syms.deinit(allocator);110 self.lazy_syms.deinit(allocator);
114111
115 {112 for (self.uavs.values()) |*meta| {
116 var it = self.uavs.iterator();113 meta.exports.deinit(allocator);
117 while (it.next()) |entry| {
118 entry.value_ptr.exports.deinit(allocator);
119 }
120 self.uavs.deinit(allocator);
121 }114 }
115 self.uavs.deinit(allocator);
122116
123 for (self.tls_variables.values()) |*tlv| {117 for (self.tls_variables.values()) |*tlv| {
124 tlv.deinit(allocator);118 tlv.deinit(allocator);
...@@ -161,6 +155,16 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi...@@ -161,6 +155,16 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi
161 if (metadata.rodata_state != .unused) metadata.rodata_state = .flushed;155 if (metadata.rodata_state != .unused) metadata.rodata_state = .flushed;
162 }156 }
163157
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 if (self.dwarf) |*dw| {168 if (self.dwarf) |*dw| {
165 const pt: Zcu.PerThread = .{ .zcu = elf_file.base.comp.module.?, .tid = tid };169 const pt: Zcu.PerThread = .{ .zcu = elf_file.base.comp.module.?, .tid = tid };
166 try dw.flushModule(pt);170 try dw.flushModule(pt);
...@@ -698,6 +702,7 @@ pub fn lowerUav(...@@ -698,6 +702,7 @@ pub fn lowerUav(
698 else => explicit_alignment,702 else => explicit_alignment,
699 };703 };
700 if (self.uavs.get(uav)) |metadata| {704 if (self.uavs.get(uav)) |metadata| {
705 assert(metadata.allocated);
701 const sym = self.symbol(metadata.symbol_index);706 const sym = self.symbol(metadata.symbol_index);
702 const existing_alignment = sym.atom(elf_file).?.alignment;707 const existing_alignment = sym.atom(elf_file).?.alignment;
703 if (uav_alignment.order(existing_alignment).compare(.lte))708 if (uav_alignment.order(existing_alignment).compare(.lte))
...@@ -729,7 +734,7 @@ pub fn lowerUav(...@@ -729,7 +734,7 @@ pub fn lowerUav(
729 .ok => |sym_index| sym_index,734 .ok => |sym_index| sym_index,
730 .fail => |em| return .{ .fail = em },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 return .{ .mcv = .{ .load_symbol = sym_index } };738 return .{ .mcv = .{ .load_symbol = sym_index } };
734}739}
735740
...@@ -747,13 +752,7 @@ pub fn getOrCreateMetadataForLazySymbol(...@@ -747,13 +752,7 @@ pub fn getOrCreateMetadataForLazySymbol(
747 .const_data => .{ &gop.value_ptr.rodata_symbol_index, &gop.value_ptr.rodata_state },752 .const_data => .{ &gop.value_ptr.rodata_symbol_index, &gop.value_ptr.rodata_state },
748 };753 };
749 switch (state_ptr.*) {754 switch (state_ptr.*) {
750 .unused => {755 .unused => symbol_index_ptr.* = try self.newSymbolWithAtom(pt.zcu.gpa, 0),
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 },
757 .pending_flush => return symbol_index_ptr.*,756 .pending_flush => return symbol_index_ptr.*,
758 .flushed => {},757 .flushed => {},
759 }758 }
...@@ -807,9 +806,6 @@ pub fn getOrCreateMetadataForNav(...@@ -807,9 +806,6 @@ pub fn getOrCreateMetadataForNav(
807 sym.flags.is_tls = true;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 gop.value_ptr.* = .{ .symbol_index = symbol_index };809 gop.value_ptr.* = .{ .symbol_index = symbol_index };
814 }810 }
815 return gop.value_ptr.symbol_index;811 return gop.value_ptr.symbol_index;
...@@ -820,9 +816,9 @@ fn getNavShdrIndex(...@@ -820,9 +816,9 @@ fn getNavShdrIndex(
820 elf_file: *Elf,816 elf_file: *Elf,
821 zcu: *Zcu,817 zcu: *Zcu,
822 nav_index: InternPool.Nav.Index,818 nav_index: InternPool.Nav.Index,
819 sym_index: Symbol.Index,
823 code: []const u8,820 code: []const u8,
824) error{OutOfMemory}!u32 {821) error{OutOfMemory}!u32 {
825 _ = self;
826 const ip = &zcu.intern_pool;822 const ip = &zcu.intern_pool;
827 const any_non_single_threaded = elf_file.base.comp.config.any_non_single_threaded;823 const any_non_single_threaded = elf_file.base.comp.config.any_non_single_threaded;
828 const nav_val = zcu.navValue(nav_index);824 const nav_val = zcu.navValue(nav_index);
...@@ -832,10 +828,12 @@ fn getNavShdrIndex(...@@ -832,10 +828,12 @@ fn getNavShdrIndex(
832 .@"extern" => |@"extern"| .{ @"extern".is_const, @"extern".is_threadlocal, .none },828 .@"extern" => |@"extern"| .{ @"extern".is_const, @"extern".is_threadlocal, .none },
833 else => .{ true, false, nav_val.toIntern() },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 if (any_non_single_threaded and is_threadlocal) {832 if (any_non_single_threaded and is_threadlocal) {
836 for (code) |byte| {833 const is_bss = !has_relocs and for (code) |byte| {
837 if (byte != 0) break;834 if (byte != 0) break false;
838 } else return elf_file.sectionByName(".tbss") orelse try elf_file.addSection(.{835 } else true;
836 if (is_bss) return elf_file.sectionByName(".tbss") orelse try elf_file.addSection(.{
839 .type = elf.SHT_NOBITS,837 .type = elf.SHT_NOBITS,
840 .flags = elf.SHF_ALLOC | elf.SHF_WRITE | elf.SHF_TLS,838 .flags = elf.SHF_ALLOC | elf.SHF_WRITE | elf.SHF_TLS,
841 .name = try elf_file.insertShString(".tbss"),839 .name = try elf_file.insertShString(".tbss"),
...@@ -854,9 +852,10 @@ fn getNavShdrIndex(...@@ -854,9 +852,10 @@ fn getNavShdrIndex(
854 .Debug, .ReleaseSafe => elf_file.zig_data_section_index.?,852 .Debug, .ReleaseSafe => elf_file.zig_data_section_index.?,
855 .ReleaseFast, .ReleaseSmall => elf_file.zig_bss_section_index.?,853 .ReleaseFast, .ReleaseSmall => elf_file.zig_bss_section_index.?,
856 };854 };
857 for (code) |byte| {855 const is_bss = !has_relocs and for (code) |byte| {
858 if (byte != 0) break;856 if (byte != 0) break false;
859 } else return elf_file.zig_bss_section_index.?;857 } else true;
858 if (is_bss) return elf_file.zig_bss_section_index.?;
860 return elf_file.zig_data_section_index.?;859 return elf_file.zig_data_section_index.?;
861}860}
862861
...@@ -909,13 +908,6 @@ fn updateNavCode(...@@ -909,13 +908,6 @@ fn updateNavCode(
909 if (old_vaddr != atom_ptr.value) {908 if (old_vaddr != atom_ptr.value) {
910 sym.value = 0;909 sym.value = 0;
911 esym.st_value = 0;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 } else if (code.len < old_size) {912 } else if (code.len < old_size) {
921 atom_ptr.shrink(elf_file);913 atom_ptr.shrink(elf_file);
...@@ -925,15 +917,11 @@ fn updateNavCode(...@@ -925,15 +917,11 @@ fn updateNavCode(
925 errdefer self.freeNavMetadata(elf_file, sym_index);917 errdefer self.freeNavMetadata(elf_file, sym_index);
926918
927 sym.value = 0;919 sym.value = 0;
928 sym.flags.needs_zig_got = true;
929 esym.st_value = 0;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 }
936922
923 self.navs.getPtr(nav_index).?.allocated = true;
924
937 if (elf_file.base.child_pid) |pid| {925 if (elf_file.base.child_pid) |pid| {
938 switch (builtin.os.tag) {926 switch (builtin.os.tag) {
939 .linux => {927 .linux => {
...@@ -959,6 +947,7 @@ fn updateNavCode(...@@ -959,6 +947,7 @@ fn updateNavCode(
959 if (shdr.sh_type != elf.SHT_NOBITS) {947 if (shdr.sh_type != elf.SHT_NOBITS) {
960 const file_offset = shdr.sh_offset + @as(u64, @intCast(atom_ptr.value));948 const file_offset = shdr.sh_offset + @as(u64, @intCast(atom_ptr.value));
961 try elf_file.base.file.?.pwriteAll(code, file_offset);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}
964953
...@@ -1001,6 +990,8 @@ fn updateTlv(...@@ -1001,6 +990,8 @@ fn updateTlv(
1001 atom_ptr.alignment = required_alignment;990 atom_ptr.alignment = required_alignment;
1002 atom_ptr.size = code.len;991 atom_ptr.size = code.len;
1003992
993 self.navs.getPtr(nav_index).?.allocated = true;
994
1004 {995 {
1005 const gop = try self.tls_variables.getOrPut(gpa, atom_ptr.atom_index);996 const gop = try self.tls_variables.getOrPut(gpa, atom_ptr.atom_index);
1006 assert(!gop.found_existing); // TODO incremental updates997 assert(!gop.found_existing); // TODO incremental updates
...@@ -1065,8 +1056,21 @@ pub fn updateFunc(...@@ -1065,8 +1056,21 @@ pub fn updateFunc(
1065 },1056 },
1066 };1057 };
10671058
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 try self.updateNavCode(elf_file, pt, func.owner_nav, sym_index, shndx, code, elf.STT_FUNC);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 };
10701074
1071 if (dwarf_state) |*ds| {1075 if (dwarf_state) |*ds| {
1072 const sym = self.symbol(sym_index);1076 const sym = self.symbol(sym_index);
...@@ -1080,6 +1084,41 @@ pub fn updateFunc(...@@ -1080,6 +1084,41 @@ pub fn updateFunc(
1080 }1084 }
10811085
1082 // Exports will be updated by `Zcu.processExports` after the update.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}
10841123
1085pub fn updateNav(1124pub fn updateNav(
...@@ -1102,13 +1141,12 @@ pub fn updateNav(...@@ -1102,13 +1141,12 @@ pub fn updateNav(
1102 .variable => |variable| Value.fromInterned(variable.init),1141 .variable => |variable| Value.fromInterned(variable.init),
1103 .@"extern" => |@"extern"| {1142 .@"extern" => |@"extern"| {
1104 if (ip.isFunctionType(@"extern".ty)) return;1143 if (ip.isFunctionType(@"extern".ty)) return;
1105 // Extern variable gets a .got entry only.
1106 const sym_index = try self.getGlobalSymbol(1144 const sym_index = try self.getGlobalSymbol(
1107 elf_file,1145 elf_file,
1108 nav.name.toSlice(ip),1146 nav.name.toSlice(ip),
1109 @"extern".lib_name.toSlice(ip),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 return;1150 return;
1113 },1151 },
1114 else => nav_val,1152 else => nav_val,
...@@ -1142,7 +1180,12 @@ pub fn updateNav(...@@ -1142,7 +1180,12 @@ pub fn updateNav(
1142 },1180 },
1143 };1181 };
11441182
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 if (elf_file.shdrs.items[shndx].sh_flags & elf.SHF_TLS != 0)1189 if (elf_file.shdrs.items[shndx].sh_flags & elf.SHF_TLS != 0)
1147 try self.updateTlv(elf_file, pt, nav_index, sym_index, shndx, code)1190 try self.updateTlv(elf_file, pt, nav_index, sym_index, shndx, code)
1148 else1191 else
...@@ -1225,14 +1268,8 @@ fn updateLazySymbol(...@@ -1225,14 +1268,8 @@ fn updateLazySymbol(
1225 errdefer self.freeNavMetadata(elf_file, symbol_index);1268 errdefer self.freeNavMetadata(elf_file, symbol_index);
12261269
1227 local_sym.value = 0;1270 local_sym.value = 0;
1228 local_sym.flags.needs_zig_got = true;
1229 local_esym.st_value = 0;1271 local_esym.st_value = 0;
12301272
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 const shdr = elf_file.shdrs.items[output_section_index];1273 const shdr = elf_file.shdrs.items[output_section_index];
1237 const file_offset = shdr.sh_offset + @as(u64, @intCast(atom_ptr.value));1274 const file_offset = shdr.sh_offset + @as(u64, @intCast(atom_ptr.value));
1238 try elf_file.base.file.?.pwriteAll(code, file_offset);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,6 +1477,52 @@ pub fn getGlobalSymbol(self: *ZigObject, elf_file: *Elf, name: []const u8, lib_n
1440 return lookup_gop.value_ptr.*;1477 return lookup_gop.value_ptr.*;
1441}1478}
14421479
1480const max_trampoline_len = 12;
1481
1482fn 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
1491fn 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
1443pub fn asFile(self: *ZigObject) File {1526pub fn asFile(self: *ZigObject) File {
1444 return .{ .zig_object = self };1527 return .{ .zig_object = self };
1445}1528}
...@@ -1662,6 +1745,8 @@ const AvMetadata = struct {...@@ -1662,6 +1745,8 @@ const AvMetadata = struct {
1662 symbol_index: Symbol.Index,1745 symbol_index: Symbol.Index,
1663 /// A list of all exports aliases of this Av.1746 /// A list of all exports aliases of this Av.
1664 exports: std.ArrayListUnmanaged(Symbol.Index) = .{},1747 exports: std.ArrayListUnmanaged(Symbol.Index) = .{},
1748 /// Set to true if the AV has been initialized and allocated.
1749 allocated: bool = false,
16651750
1666 fn @"export"(m: AvMetadata, zig_object: *ZigObject, name: []const u8) ?*u32 {1751 fn @"export"(m: AvMetadata, zig_object: *ZigObject, name: []const u8) ?*u32 {
1667 for (m.exports.items) |*exp| {1752 for (m.exports.items) |*exp| {
...@@ -1672,6 +1757,32 @@ const AvMetadata = struct {...@@ -1672,6 +1757,32 @@ const AvMetadata = struct {
1672 }1757 }
1673};1758};
16741759
1760fn 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
1773fn 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
1675const TlsVariable = struct {1786const TlsVariable = struct {
1676 symbol_index: Symbol.Index,1787 symbol_index: Symbol.Index,
1677 code: []const u8 = &[0]u8{},1788 code: []const u8 = &[0]u8{},
...@@ -1682,12 +1793,26 @@ const TlsVariable = struct {...@@ -1682,12 +1793,26 @@ const TlsVariable = struct {
1682};1793};
16831794
1684const AtomList = std.ArrayListUnmanaged(Atom.Index);1795const AtomList = std.ArrayListUnmanaged(Atom.Index);
1685const NavTable = std.AutoHashMapUnmanaged(InternPool.Nav.Index, AvMetadata);1796const NavTable = std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, AvMetadata);
1686const UavTable = std.AutoHashMapUnmanaged(InternPool.Index, AvMetadata);1797const UavTable = std.AutoArrayHashMapUnmanaged(InternPool.Index, AvMetadata);
1687const LazySymbolTable = std.AutoArrayHashMapUnmanaged(InternPool.Index, LazySymbolMetadata);1798const LazySymbolTable = std.AutoArrayHashMapUnmanaged(InternPool.Index, LazySymbolMetadata);
1688const TlsTable = std.AutoArrayHashMapUnmanaged(Atom.Index, TlsVariable);1799const TlsTable = std.AutoArrayHashMapUnmanaged(Atom.Index, TlsVariable);
16891800
1801const 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
1690const assert = std.debug.assert;1814const assert = std.debug.assert;
1815const build_options = @import("build_options");
1691const builtin = @import("builtin");1816const builtin = @import("builtin");
1692const codegen = @import("../../codegen.zig");1817const codegen = @import("../../codegen.zig");
1693const elf = std.elf;1818const elf = std.elf;
src/link/Elf/relocation.zig+5-13
...@@ -112,19 +112,11 @@ fn formatRelocType(...@@ -112,19 +112,11 @@ fn formatRelocType(
112 _ = unused_fmt_string;112 _ = unused_fmt_string;
113 _ = options;113 _ = options;
114 const r_type = ctx.r_type;114 const r_type = ctx.r_type;
115 switch (r_type) {115 switch (ctx.cpu_arch) {
116 Elf.R_ZIG_GOT32 => try writer.writeAll("R_ZIG_GOT32"),116 .x86_64 => try writer.print("R_X86_64_{s}", .{@tagName(@as(elf.R_X86_64, @enumFromInt(r_type)))}),
117 Elf.R_ZIG_GOTPCREL => try writer.writeAll("R_ZIG_GOTPCREL"),117 .aarch64 => try writer.print("R_AARCH64_{s}", .{@tagName(@as(elf.R_AARCH64, @enumFromInt(r_type)))}),
118 Elf.R_ZIG_GOT_HI20 => try writer.writeAll("R_ZIG_GOT_HI20"),118 .riscv64 => try writer.print("R_RISCV_{s}", .{@tagName(@as(elf.R_RISCV, @enumFromInt(r_type)))}),
119 Elf.R_ZIG_GOT_LO12 => try writer.writeAll("R_ZIG_GOT_LO12"),119 else => unreachable,
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 },
128 }120 }
129}121}
130122
src/link/Elf/synthetic_sections.zig-209
...@@ -223,215 +223,6 @@ pub const DynamicSection = struct {...@@ -223,215 +223,6 @@ pub const DynamicSection = struct {
223 }223 }
224};224};
225225
226pub 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
435pub const GotSection = struct {226pub const GotSection = struct {
436 entries: std.ArrayListUnmanaged(Entry) = .{},227 entries: std.ArrayListUnmanaged(Entry) = .{},
437 output_symtab_ctx: Elf.SymtabCtx = .{},228 output_symtab_ctx: Elf.SymtabCtx = .{},
test/behavior/basic.zig-1
...@@ -733,7 +733,6 @@ test "extern variable with non-pointer opaque type" {...@@ -733,7 +733,6 @@ test "extern variable with non-pointer opaque type" {
733 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO733 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
734 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;734 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
735 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO735 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
736 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
737736
738 @export(var_to_export, .{ .name = "opaque_extern_var" });737 @export(var_to_export, .{ .name = "opaque_extern_var" });
739 try expect(@as(*align(1) u32, @ptrCast(&opaque_extern_var)).* == 42);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,7 +48,6 @@ test "exporting using field access" {
48test "exporting comptime-known value" {48test "exporting comptime-known value" {
49 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;49 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
50 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;50 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
51 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
52 if (builtin.zig_backend == .stage2_x86_64 and51 if (builtin.zig_backend == .stage2_x86_64 and
53 (builtin.target.ofmt != .elf and52 (builtin.target.ofmt != .elf and
54 builtin.target.ofmt != .macho and53 builtin.target.ofmt != .macho and
...@@ -68,7 +67,6 @@ test "exporting comptime-known value" {...@@ -68,7 +67,6 @@ test "exporting comptime-known value" {
68test "exporting comptime var" {67test "exporting comptime var" {
69 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;68 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
70 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;69 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
71 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
72 if (builtin.zig_backend == .stage2_x86_64 and70 if (builtin.zig_backend == .stage2_x86_64 and
73 (builtin.target.ofmt != .elf and71 (builtin.target.ofmt != .elf and
74 builtin.target.ofmt != .macho and72 builtin.target.ofmt != .macho and
test/behavior/extern.zig-1
...@@ -7,7 +7,6 @@ test "anyopaque extern symbol" {...@@ -7,7 +7,6 @@ test "anyopaque extern symbol" {
7 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;7 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
8 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;8 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
9 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;9 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
10 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1110
12 const a = @extern(*anyopaque, .{ .name = "a_mystery_symbol" });11 const a = @extern(*anyopaque, .{ .name = "a_mystery_symbol" });
13 const b: *i32 = @alignCast(@ptrCast(a));12 const b: *i32 = @alignCast(@ptrCast(a));
test/behavior/fn.zig-1
...@@ -429,7 +429,6 @@ test "implicit cast function to function ptr" {...@@ -429,7 +429,6 @@ test "implicit cast function to function ptr" {
429 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO429 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
430 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;430 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
431 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;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;
433432
434 const S1 = struct {433 const S1 = struct {
435 export fn someFunctionThatReturnsAValue() c_int {434 export fn someFunctionThatReturnsAValue() c_int {
test/behavior/pointers.zig-1
...@@ -45,7 +45,6 @@ test "pointer-integer arithmetic" {...@@ -45,7 +45,6 @@ test "pointer-integer arithmetic" {
4545
46test "pointer subtraction" {46test "pointer subtraction" {
47 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO47 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
48 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
4948
50 {49 {
51 const a: *u8 = @ptrFromInt(100);50 const a: *u8 = @ptrFromInt(100);
test/link/elf.zig+20-4
...@@ -1773,25 +1773,41 @@ fn testImportingDataDynamic(b: *Build, opts: Options) *Step {...@@ -1773,25 +1773,41 @@ fn testImportingDataDynamic(b: *Build, opts: Options) *Step {
1773 .use_llvm = true,1773 .use_llvm = true,
1774 }, .{1774 }, .{
1775 .name = "a",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();
17781783
1779 const main = addExecutable(b, opts, .{1784 const main = addExecutable(b, opts, .{
1780 .name = "main",1785 .name = "main",
1781 .zig_source_bytes =1786 .zig_source_bytes =
1787 \\const std = @import("std");
1782 \\extern var foo: i32;1788 \\extern var foo: i32;
1789 \\extern fn printFoo() void;
1783 \\pub fn main() void {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 .strip = true, // TODO temp hack1798 .strip = true, // TODO temp hack
1788 });1799 });
1789 main.pie = true;1800 main.pie = true;
1790 main.linkLibrary(dso);1801 main.linkLibrary(dso);
1791 main.linkLibC();
17921802
1793 const run = addRunArtifact(main);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 test_step.dependOn(&run.step);1811 test_step.dependOn(&run.step);
17961812
1797 return test_step;1813 return test_step;