authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2024-08-28 18:25:14+01:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2024-08-29 23:43:52+01:00
logc62487da76b08a0dfb69fbf76501250ca065c140
tree1ef46d45f3ff9edaade3805d9ab5a9910cb8571b
parentba8d3f69ca65738f27deea43e795f5e787a061f2
signaturelock-open Commit is signed but in an unrecognized format.

compiler: avoid field/decl name conflicts

Most of the required renames here are net wins for readaibility, I'd say. The ones in `arch` are a little more verbose, but I think better. I didn't bother renaming the non-conflicting functions in `arch/arm/bits.zig` and `arch/aarch64/bits.zig`, since these backends are pretty bit-rotted anyway AIUI.

19 files changed, 604 insertions(+), 623 deletions(-)

CMakeLists.txt+2-2
...@@ -613,7 +613,7 @@ set(ZIG_STAGE2_SOURCES...@@ -613,7 +613,7 @@ set(ZIG_STAGE2_SOURCES
613 src/link/Elf/relocatable.zig613 src/link/Elf/relocatable.zig
614 src/link/Elf/relocation.zig614 src/link/Elf/relocation.zig
615 src/link/Elf/synthetic_sections.zig615 src/link/Elf/synthetic_sections.zig
616 src/link/Elf/thunks.zig616 src/link/Elf/Thunk.zig
617 src/link/MachO.zig617 src/link/MachO.zig
618 src/link/MachO/Archive.zig618 src/link/MachO/Archive.zig
619 src/link/MachO/Atom.zig619 src/link/MachO/Atom.zig
...@@ -638,7 +638,7 @@ set(ZIG_STAGE2_SOURCES...@@ -638,7 +638,7 @@ set(ZIG_STAGE2_SOURCES
638 src/link/MachO/load_commands.zig638 src/link/MachO/load_commands.zig
639 src/link/MachO/relocatable.zig639 src/link/MachO/relocatable.zig
640 src/link/MachO/synthetic.zig640 src/link/MachO/synthetic.zig
641 src/link/MachO/thunks.zig641 src/link/MachO/Thunk.zig
642 src/link/MachO/uuid.zig642 src/link/MachO/uuid.zig
643 src/link/NvPtx.zig643 src/link/NvPtx.zig
644 src/link/Plan9.zig644 src/link/Plan9.zig
src/arch/aarch64/bits.zig+4-4
...@@ -1069,7 +1069,7 @@ pub const Instruction = union(enum) {...@@ -1069,7 +1069,7 @@ pub const Instruction = union(enum) {
1069 };1069 };
1070 }1070 }
10711071
1072 fn bitfield(1072 fn initBitfield(
1073 opc: u2,1073 opc: u2,
1074 n: u1,1074 n: u1,
1075 rd: Register,1075 rd: Register,
...@@ -1579,7 +1579,7 @@ pub const Instruction = union(enum) {...@@ -1579,7 +1579,7 @@ pub const Instruction = union(enum) {
1579 64 => 0b1,1579 64 => 0b1,
1580 else => unreachable, // unexpected register size1580 else => unreachable, // unexpected register size
1581 };1581 };
1582 return bitfield(0b00, n, rd, rn, immr, imms);1582 return initBitfield(0b00, n, rd, rn, immr, imms);
1583 }1583 }
15841584
1585 pub fn bfm(rd: Register, rn: Register, immr: u6, imms: u6) Instruction {1585 pub fn bfm(rd: Register, rn: Register, immr: u6, imms: u6) Instruction {
...@@ -1588,7 +1588,7 @@ pub const Instruction = union(enum) {...@@ -1588,7 +1588,7 @@ pub const Instruction = union(enum) {
1588 64 => 0b1,1588 64 => 0b1,
1589 else => unreachable, // unexpected register size1589 else => unreachable, // unexpected register size
1590 };1590 };
1591 return bitfield(0b01, n, rd, rn, immr, imms);1591 return initBitfield(0b01, n, rd, rn, immr, imms);
1592 }1592 }
15931593
1594 pub fn ubfm(rd: Register, rn: Register, immr: u6, imms: u6) Instruction {1594 pub fn ubfm(rd: Register, rn: Register, immr: u6, imms: u6) Instruction {
...@@ -1597,7 +1597,7 @@ pub const Instruction = union(enum) {...@@ -1597,7 +1597,7 @@ pub const Instruction = union(enum) {
1597 64 => 0b1,1597 64 => 0b1,
1598 else => unreachable, // unexpected register size1598 else => unreachable, // unexpected register size
1599 };1599 };
1600 return bitfield(0b10, n, rd, rn, immr, imms);1600 return initBitfield(0b10, n, rd, rn, immr, imms);
1601 }1601 }
16021602
1603 pub fn asrImmediate(rd: Register, rn: Register, shift: u6) Instruction {1603 pub fn asrImmediate(rd: Register, rn: Register, shift: u6) Instruction {
src/arch/arm/bits.zig+10-10
...@@ -662,7 +662,7 @@ pub const Instruction = union(enum) {...@@ -662,7 +662,7 @@ pub const Instruction = union(enum) {
662 };662 };
663 }663 }
664664
665 fn multiply(665 fn initMultiply(
666 cond: Condition,666 cond: Condition,
667 set_cond: u1,667 set_cond: u1,
668 rd: Register,668 rd: Register,
...@@ -864,7 +864,7 @@ pub const Instruction = union(enum) {...@@ -864,7 +864,7 @@ pub const Instruction = union(enum) {
864 };864 };
865 }865 }
866866
867 fn branch(cond: Condition, offset: i26, link: u1) Instruction {867 fn initBranch(cond: Condition, offset: i26, link: u1) Instruction {
868 return Instruction{868 return Instruction{
869 .branch = .{869 .branch = .{
870 .cond = @intFromEnum(cond),870 .cond = @intFromEnum(cond),
...@@ -900,7 +900,7 @@ pub const Instruction = union(enum) {...@@ -900,7 +900,7 @@ pub const Instruction = union(enum) {
900 };900 };
901 }901 }
902902
903 fn breakpoint(imm: u16) Instruction {903 fn initBreakpoint(imm: u16) Instruction {
904 return Instruction{904 return Instruction{
905 .breakpoint = .{905 .breakpoint = .{
906 .imm12 = @as(u12, @truncate(imm >> 4)),906 .imm12 = @as(u12, @truncate(imm >> 4)),
...@@ -1087,19 +1087,19 @@ pub const Instruction = union(enum) {...@@ -1087,19 +1087,19 @@ pub const Instruction = union(enum) {
1087 // Multiply1087 // Multiply
10881088
1089 pub fn mul(cond: Condition, rd: Register, rn: Register, rm: Register) Instruction {1089 pub fn mul(cond: Condition, rd: Register, rn: Register, rm: Register) Instruction {
1090 return multiply(cond, 0, rd, rn, rm, null);1090 return initMultiply(cond, 0, rd, rn, rm, null);
1091 }1091 }
10921092
1093 pub fn muls(cond: Condition, rd: Register, rn: Register, rm: Register) Instruction {1093 pub fn muls(cond: Condition, rd: Register, rn: Register, rm: Register) Instruction {
1094 return multiply(cond, 1, rd, rn, rm, null);1094 return initMultiply(cond, 1, rd, rn, rm, null);
1095 }1095 }
10961096
1097 pub fn mla(cond: Condition, rd: Register, rn: Register, rm: Register, ra: Register) Instruction {1097 pub fn mla(cond: Condition, rd: Register, rn: Register, rm: Register, ra: Register) Instruction {
1098 return multiply(cond, 0, rd, rn, rm, ra);1098 return initMultiply(cond, 0, rd, rn, rm, ra);
1099 }1099 }
11001100
1101 pub fn mlas(cond: Condition, rd: Register, rn: Register, rm: Register, ra: Register) Instruction {1101 pub fn mlas(cond: Condition, rd: Register, rn: Register, rm: Register, ra: Register) Instruction {
1102 return multiply(cond, 1, rd, rn, rm, ra);1102 return initMultiply(cond, 1, rd, rn, rm, ra);
1103 }1103 }
11041104
1105 // Multiply long1105 // Multiply long
...@@ -1261,11 +1261,11 @@ pub const Instruction = union(enum) {...@@ -1261,11 +1261,11 @@ pub const Instruction = union(enum) {
1261 // Branch1261 // Branch
12621262
1263 pub fn b(cond: Condition, offset: i26) Instruction {1263 pub fn b(cond: Condition, offset: i26) Instruction {
1264 return branch(cond, offset, 0);1264 return initBranch(cond, offset, 0);
1265 }1265 }
12661266
1267 pub fn bl(cond: Condition, offset: i26) Instruction {1267 pub fn bl(cond: Condition, offset: i26) Instruction {
1268 return branch(cond, offset, 1);1268 return initBranch(cond, offset, 1);
1269 }1269 }
12701270
1271 // Branch and exchange1271 // Branch and exchange
...@@ -1289,7 +1289,7 @@ pub const Instruction = union(enum) {...@@ -1289,7 +1289,7 @@ pub const Instruction = union(enum) {
1289 // Breakpoint1289 // Breakpoint
12901290
1291 pub fn bkpt(imm: u16) Instruction {1291 pub fn bkpt(imm: u16) Instruction {
1292 return breakpoint(imm);1292 return initBreakpoint(imm);
1293 }1293 }
12941294
1295 // Aliases1295 // Aliases
src/arch/x86_64/CodeGen.zig+1-1
...@@ -15563,7 +15563,7 @@ fn genLazySymbolRef(...@@ -15563,7 +15563,7 @@ fn genLazySymbolRef(
15563 .mov => try self.asmRegisterMemory(15563 .mov => try self.asmRegisterMemory(
15564 .{ ._, tag },15564 .{ ._, tag },
15565 reg.to64(),15565 reg.to64(),
15566 Memory.sib(.qword, .{ .base = .{ .reg = reg.to64() } }),15566 Memory.initSib(.qword, .{ .base = .{ .reg = reg.to64() } }),
15567 ),15567 ),
15568 else => unreachable,15568 else => unreachable,
15569 }15569 }
src/arch/x86_64/Disassembler.zig+8-8
...@@ -95,7 +95,7 @@ pub fn next(dis: *Disassembler) Error!?Instruction {...@@ -95,7 +95,7 @@ pub fn next(dis: *Disassembler) Error!?Instruction {
9595
96 if (modrm.rip()) {96 if (modrm.rip()) {
97 return inst(act_enc, .{97 return inst(act_enc, .{
98 .op1 = .{ .mem = Memory.rip(Memory.PtrSize.fromBitSize(act_enc.data.ops[0].memBitSize()), disp) },98 .op1 = .{ .mem = Memory.initRip(Memory.PtrSize.fromBitSize(act_enc.data.ops[0].memBitSize()), disp) },
99 .op2 = op2,99 .op2 = op2,
100 });100 });
101 }101 }
...@@ -106,7 +106,7 @@ pub fn next(dis: *Disassembler) Error!?Instruction {...@@ -106,7 +106,7 @@ pub fn next(dis: *Disassembler) Error!?Instruction {
106 else106 else
107 parseGpRegister(modrm.op2, prefixes.rex.b, prefixes.rex, 64);107 parseGpRegister(modrm.op2, prefixes.rex.b, prefixes.rex, 64);
108 return inst(act_enc, .{108 return inst(act_enc, .{
109 .op1 = .{ .mem = Memory.sib(Memory.PtrSize.fromBitSize(act_enc.data.ops[0].memBitSize()), .{109 .op1 = .{ .mem = Memory.initSib(Memory.PtrSize.fromBitSize(act_enc.data.ops[0].memBitSize()), .{
110 .base = if (base) |base_reg| .{ .reg = base_reg } else .none,110 .base = if (base) |base_reg| .{ .reg = base_reg } else .none,
111 .scale_index = scale_index,111 .scale_index = scale_index,
112 .disp = disp,112 .disp = disp,
...@@ -119,14 +119,14 @@ pub fn next(dis: *Disassembler) Error!?Instruction {...@@ -119,14 +119,14 @@ pub fn next(dis: *Disassembler) Error!?Instruction {
119 const offset = try dis.parseOffset();119 const offset = try dis.parseOffset();
120 return inst(enc, .{120 return inst(enc, .{
121 .op1 = .{ .reg = Register.rax.toBitSize(enc.data.ops[0].regBitSize()) },121 .op1 = .{ .reg = Register.rax.toBitSize(enc.data.ops[0].regBitSize()) },
122 .op2 = .{ .mem = Memory.moffs(seg, offset) },122 .op2 = .{ .mem = Memory.initMoffs(seg, offset) },
123 });123 });
124 },124 },
125 .td => {125 .td => {
126 const seg = segmentRegister(prefixes.legacy);126 const seg = segmentRegister(prefixes.legacy);
127 const offset = try dis.parseOffset();127 const offset = try dis.parseOffset();
128 return inst(enc, .{128 return inst(enc, .{
129 .op1 = .{ .mem = Memory.moffs(seg, offset) },129 .op1 = .{ .mem = Memory.initMoffs(seg, offset) },
130 .op2 = .{ .reg = Register.rax.toBitSize(enc.data.ops[1].regBitSize()) },130 .op2 = .{ .reg = Register.rax.toBitSize(enc.data.ops[1].regBitSize()) },
131 });131 });
132 },132 },
...@@ -153,7 +153,7 @@ pub fn next(dis: *Disassembler) Error!?Instruction {...@@ -153,7 +153,7 @@ pub fn next(dis: *Disassembler) Error!?Instruction {
153153
154 if (modrm.rip()) {154 if (modrm.rip()) {
155 return inst(enc, .{155 return inst(enc, .{
156 .op1 = .{ .mem = Memory.rip(Memory.PtrSize.fromBitSize(dst_bit_size), disp) },156 .op1 = .{ .mem = Memory.initRip(Memory.PtrSize.fromBitSize(dst_bit_size), disp) },
157 .op2 = .{ .reg = parseGpRegister(modrm.op1, prefixes.rex.r, prefixes.rex, src_bit_size) },157 .op2 = .{ .reg = parseGpRegister(modrm.op1, prefixes.rex.r, prefixes.rex, src_bit_size) },
158 .op3 = op3,158 .op3 = op3,
159 });159 });
...@@ -165,7 +165,7 @@ pub fn next(dis: *Disassembler) Error!?Instruction {...@@ -165,7 +165,7 @@ pub fn next(dis: *Disassembler) Error!?Instruction {
165 else165 else
166 parseGpRegister(modrm.op2, prefixes.rex.b, prefixes.rex, 64);166 parseGpRegister(modrm.op2, prefixes.rex.b, prefixes.rex, 64);
167 return inst(enc, .{167 return inst(enc, .{
168 .op1 = .{ .mem = Memory.sib(Memory.PtrSize.fromBitSize(dst_bit_size), .{168 .op1 = .{ .mem = Memory.initSib(Memory.PtrSize.fromBitSize(dst_bit_size), .{
169 .base = if (base) |base_reg| .{ .reg = base_reg } else .none,169 .base = if (base) |base_reg| .{ .reg = base_reg } else .none,
170 .scale_index = scale_index,170 .scale_index = scale_index,
171 .disp = disp,171 .disp = disp,
...@@ -203,7 +203,7 @@ pub fn next(dis: *Disassembler) Error!?Instruction {...@@ -203,7 +203,7 @@ pub fn next(dis: *Disassembler) Error!?Instruction {
203 if (modrm.rip()) {203 if (modrm.rip()) {
204 return inst(enc, .{204 return inst(enc, .{
205 .op1 = .{ .reg = parseGpRegister(modrm.op1, prefixes.rex.r, prefixes.rex, dst_bit_size) },205 .op1 = .{ .reg = parseGpRegister(modrm.op1, prefixes.rex.r, prefixes.rex, dst_bit_size) },
206 .op2 = .{ .mem = Memory.rip(Memory.PtrSize.fromBitSize(src_bit_size), disp) },206 .op2 = .{ .mem = Memory.initRip(Memory.PtrSize.fromBitSize(src_bit_size), disp) },
207 .op3 = op3,207 .op3 = op3,
208 });208 });
209 }209 }
...@@ -215,7 +215,7 @@ pub fn next(dis: *Disassembler) Error!?Instruction {...@@ -215,7 +215,7 @@ pub fn next(dis: *Disassembler) Error!?Instruction {
215 parseGpRegister(modrm.op2, prefixes.rex.b, prefixes.rex, 64);215 parseGpRegister(modrm.op2, prefixes.rex.b, prefixes.rex, 64);
216 return inst(enc, .{216 return inst(enc, .{
217 .op1 = .{ .reg = parseGpRegister(modrm.op1, prefixes.rex.r, prefixes.rex, dst_bit_size) },217 .op1 = .{ .reg = parseGpRegister(modrm.op1, prefixes.rex.r, prefixes.rex, dst_bit_size) },
218 .op2 = .{ .mem = Memory.sib(Memory.PtrSize.fromBitSize(src_bit_size), .{218 .op2 = .{ .mem = Memory.initSib(Memory.PtrSize.fromBitSize(src_bit_size), .{
219 .base = if (base) |base_reg| .{ .reg = base_reg } else .none,219 .base = if (base) |base_reg| .{ .reg = base_reg } else .none,
220 .scale_index = scale_index,220 .scale_index = scale_index,
221 .disp = disp,221 .disp = disp,
src/arch/x86_64/Lower.zig+21-21
...@@ -200,13 +200,13 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {...@@ -200,13 +200,13 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
200 });200 });
201 try lower.emit(.none, .lea, &.{201 try lower.emit(.none, .lea, &.{
202 .{ .reg = inst.data.ri.r1 },202 .{ .reg = inst.data.ri.r1 },
203 .{ .mem = Memory.sib(.qword, .{203 .{ .mem = Memory.initSib(.qword, .{
204 .base = .{ .reg = inst.data.ri.r1 },204 .base = .{ .reg = inst.data.ri.r1 },
205 .disp = -page_size,205 .disp = -page_size,
206 }) },206 }) },
207 });207 });
208 try lower.emit(.none, .@"test", &.{208 try lower.emit(.none, .@"test", &.{
209 .{ .mem = Memory.sib(.dword, .{209 .{ .mem = Memory.initSib(.dword, .{
210 .base = .{ .reg = inst.data.ri.r1 },210 .base = .{ .reg = inst.data.ri.r1 },
211 }) },211 }) },
212 .{ .reg = inst.data.ri.r1.to32() },212 .{ .reg = inst.data.ri.r1.to32() },
...@@ -220,7 +220,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {...@@ -220,7 +220,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
220 var offset = page_size;220 var offset = page_size;
221 while (offset < @as(i32, @bitCast(inst.data.ri.i))) : (offset += page_size) {221 while (offset < @as(i32, @bitCast(inst.data.ri.i))) : (offset += page_size) {
222 try lower.emit(.none, .@"test", &.{222 try lower.emit(.none, .@"test", &.{
223 .{ .mem = Memory.sib(.dword, .{223 .{ .mem = Memory.initSib(.dword, .{
224 .base = .{ .reg = inst.data.ri.r1 },224 .base = .{ .reg = inst.data.ri.r1 },
225 .disp = -offset,225 .disp = -offset,
226 }) },226 }) },
...@@ -246,7 +246,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {...@@ -246,7 +246,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
246 },246 },
247 .pseudo_probe_adjust_loop_rr => {247 .pseudo_probe_adjust_loop_rr => {
248 try lower.emit(.none, .@"test", &.{248 try lower.emit(.none, .@"test", &.{
249 .{ .mem = Memory.sib(.dword, .{249 .{ .mem = Memory.initSib(.dword, .{
250 .base = .{ .reg = inst.data.rr.r1 },250 .base = .{ .reg = inst.data.rr.r1 },
251 .scale_index = .{ .scale = 1, .index = inst.data.rr.r2 },251 .scale_index = .{ .scale = 1, .index = inst.data.rr.r2 },
252 .disp = -page_size,252 .disp = -page_size,
...@@ -417,7 +417,7 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand)...@@ -417,7 +417,7 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand)
417 lower.result_insts[lower.result_insts_len] =417 lower.result_insts[lower.result_insts_len] =
418 try Instruction.new(.none, .lea, &[_]Operand{418 try Instruction.new(.none, .lea, &[_]Operand{
419 .{ .reg = .rdi },419 .{ .reg = .rdi },
420 .{ .mem = Memory.rip(mem_op.sib.ptr_size, 0) },420 .{ .mem = Memory.initRip(mem_op.sib.ptr_size, 0) },
421 });421 });
422 lower.result_insts_len += 1;422 lower.result_insts_len += 1;
423 _ = lower.reloc(.{423 _ = lower.reloc(.{
...@@ -430,7 +430,7 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand)...@@ -430,7 +430,7 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand)
430 lower.result_insts_len += 1;430 lower.result_insts_len += 1;
431 _ = lower.reloc(.{ .linker_dtpoff = sym_index }, 0);431 _ = lower.reloc(.{ .linker_dtpoff = sym_index }, 0);
432 emit_mnemonic = .lea;432 emit_mnemonic = .lea;
433 break :op .{ .mem = Memory.sib(mem_op.sib.ptr_size, .{433 break :op .{ .mem = Memory.initSib(mem_op.sib.ptr_size, .{
434 .base = .{ .reg = .rax },434 .base = .{ .reg = .rax },
435 .disp = std.math.minInt(i32),435 .disp = std.math.minInt(i32),
436 }) };436 }) };
...@@ -439,12 +439,12 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand)...@@ -439,12 +439,12 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand)
439 lower.result_insts[lower.result_insts_len] =439 lower.result_insts[lower.result_insts_len] =
440 try Instruction.new(.none, .mov, &[_]Operand{440 try Instruction.new(.none, .mov, &[_]Operand{
441 .{ .reg = .rax },441 .{ .reg = .rax },
442 .{ .mem = Memory.sib(.qword, .{ .base = .{ .reg = .fs } }) },442 .{ .mem = Memory.initSib(.qword, .{ .base = .{ .reg = .fs } }) },
443 });443 });
444 lower.result_insts_len += 1;444 lower.result_insts_len += 1;
445 _ = lower.reloc(.{ .linker_reloc = sym_index }, 0);445 _ = lower.reloc(.{ .linker_reloc = sym_index }, 0);
446 emit_mnemonic = .lea;446 emit_mnemonic = .lea;
447 break :op .{ .mem = Memory.sib(mem_op.sib.ptr_size, .{447 break :op .{ .mem = Memory.initSib(mem_op.sib.ptr_size, .{
448 .base = .{ .reg = .rax },448 .base = .{ .reg = .rax },
449 .disp = std.math.minInt(i32),449 .disp = std.math.minInt(i32),
450 }) };450 }) };
...@@ -455,7 +455,7 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand)...@@ -455,7 +455,7 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand)
455 if (lower.pic) switch (mnemonic) {455 if (lower.pic) switch (mnemonic) {
456 .lea => {456 .lea => {
457 if (elf_sym.flags.is_extern_ptr) emit_mnemonic = .mov;457 if (elf_sym.flags.is_extern_ptr) emit_mnemonic = .mov;
458 break :op .{ .mem = Memory.rip(mem_op.sib.ptr_size, 0) };458 break :op .{ .mem = Memory.initRip(mem_op.sib.ptr_size, 0) };
459 },459 },
460 .mov => {460 .mov => {
461 if (elf_sym.flags.is_extern_ptr) {461 if (elf_sym.flags.is_extern_ptr) {
...@@ -463,25 +463,25 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand)...@@ -463,25 +463,25 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand)
463 lower.result_insts[lower.result_insts_len] =463 lower.result_insts[lower.result_insts_len] =
464 try Instruction.new(.none, .mov, &[_]Operand{464 try Instruction.new(.none, .mov, &[_]Operand{
465 .{ .reg = reg.to64() },465 .{ .reg = reg.to64() },
466 .{ .mem = Memory.rip(.qword, 0) },466 .{ .mem = Memory.initRip(.qword, 0) },
467 });467 });
468 lower.result_insts_len += 1;468 lower.result_insts_len += 1;
469 break :op .{ .mem = Memory.sib(mem_op.sib.ptr_size, .{ .base = .{469 break :op .{ .mem = Memory.initSib(mem_op.sib.ptr_size, .{ .base = .{
470 .reg = reg.to64(),470 .reg = reg.to64(),
471 } }) };471 } }) };
472 }472 }
473 break :op .{ .mem = Memory.rip(mem_op.sib.ptr_size, 0) };473 break :op .{ .mem = Memory.initRip(mem_op.sib.ptr_size, 0) };
474 },474 },
475 else => unreachable,475 else => unreachable,
476 } else switch (mnemonic) {476 } else switch (mnemonic) {
477 .call => break :op .{ .mem = Memory.sib(mem_op.sib.ptr_size, .{477 .call => break :op .{ .mem = Memory.initSib(mem_op.sib.ptr_size, .{
478 .base = .{ .reg = .ds },478 .base = .{ .reg = .ds },
479 }) },479 }) },
480 .lea => {480 .lea => {
481 emit_mnemonic = .mov;481 emit_mnemonic = .mov;
482 break :op .{ .imm = Immediate.s(0) };482 break :op .{ .imm = Immediate.s(0) };
483 },483 },
484 .mov => break :op .{ .mem = Memory.sib(mem_op.sib.ptr_size, .{484 .mov => break :op .{ .mem = Memory.initSib(mem_op.sib.ptr_size, .{
485 .base = .{ .reg = .ds },485 .base = .{ .reg = .ds },
486 }) },486 }) },
487 else => unreachable,487 else => unreachable,
...@@ -495,12 +495,12 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand)...@@ -495,12 +495,12 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand)
495 lower.result_insts[lower.result_insts_len] =495 lower.result_insts[lower.result_insts_len] =
496 try Instruction.new(.none, .mov, &[_]Operand{496 try Instruction.new(.none, .mov, &[_]Operand{
497 .{ .reg = .rdi },497 .{ .reg = .rdi },
498 .{ .mem = Memory.rip(mem_op.sib.ptr_size, 0) },498 .{ .mem = Memory.initRip(mem_op.sib.ptr_size, 0) },
499 });499 });
500 lower.result_insts_len += 1;500 lower.result_insts_len += 1;
501 lower.result_insts[lower.result_insts_len] =501 lower.result_insts[lower.result_insts_len] =
502 try Instruction.new(.none, .call, &[_]Operand{502 try Instruction.new(.none, .call, &[_]Operand{
503 .{ .mem = Memory.sib(.qword, .{ .base = .{ .reg = .rdi } }) },503 .{ .mem = Memory.initSib(.qword, .{ .base = .{ .reg = .rdi } }) },
504 });504 });
505 lower.result_insts_len += 1;505 lower.result_insts_len += 1;
506 emit_mnemonic = .mov;506 emit_mnemonic = .mov;
...@@ -511,7 +511,7 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand)...@@ -511,7 +511,7 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand)
511 break :op switch (mnemonic) {511 break :op switch (mnemonic) {
512 .lea => {512 .lea => {
513 if (macho_sym.flags.is_extern_ptr) emit_mnemonic = .mov;513 if (macho_sym.flags.is_extern_ptr) emit_mnemonic = .mov;
514 break :op .{ .mem = Memory.rip(mem_op.sib.ptr_size, 0) };514 break :op .{ .mem = Memory.initRip(mem_op.sib.ptr_size, 0) };
515 },515 },
516 .mov => {516 .mov => {
517 if (macho_sym.flags.is_extern_ptr) {517 if (macho_sym.flags.is_extern_ptr) {
...@@ -519,14 +519,14 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand)...@@ -519,14 +519,14 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand)
519 lower.result_insts[lower.result_insts_len] =519 lower.result_insts[lower.result_insts_len] =
520 try Instruction.new(.none, .mov, &[_]Operand{520 try Instruction.new(.none, .mov, &[_]Operand{
521 .{ .reg = reg.to64() },521 .{ .reg = reg.to64() },
522 .{ .mem = Memory.rip(.qword, 0) },522 .{ .mem = Memory.initRip(.qword, 0) },
523 });523 });
524 lower.result_insts_len += 1;524 lower.result_insts_len += 1;
525 break :op .{ .mem = Memory.sib(mem_op.sib.ptr_size, .{ .base = .{525 break :op .{ .mem = Memory.initSib(mem_op.sib.ptr_size, .{ .base = .{
526 .reg = reg.to64(),526 .reg = reg.to64(),
527 } }) };527 } }) };
528 }528 }
529 break :op .{ .mem = Memory.rip(mem_op.sib.ptr_size, 0) };529 break :op .{ .mem = Memory.initRip(mem_op.sib.ptr_size, 0) };
530 },530 },
531 else => unreachable,531 else => unreachable,
532 };532 };
...@@ -701,7 +701,7 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void {...@@ -701,7 +701,7 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void {
701 }, extra.off);701 }, extra.off);
702 break :ops &.{702 break :ops &.{
703 .{ .reg = reg },703 .{ .reg = reg },
704 .{ .mem = Memory.rip(Memory.PtrSize.fromBitSize(reg.bitSize()), 0) },704 .{ .mem = Memory.initRip(Memory.PtrSize.fromBitSize(reg.bitSize()), 0) },
705 };705 };
706 },706 },
707 else => return lower.fail("TODO lower {s} {s}", .{ @tagName(inst.tag), @tagName(inst.ops) }),707 else => return lower.fail("TODO lower {s} {s}", .{ @tagName(inst.tag), @tagName(inst.ops) }),
src/arch/x86_64/Mir.zig+3-3
...@@ -1234,9 +1234,9 @@ pub const Memory = struct {...@@ -1234,9 +1234,9 @@ pub const Memory = struct {
1234 .rm => {1234 .rm => {
1235 if (mem.info.base == .reg and @as(Register, @enumFromInt(mem.base)) == .rip) {1235 if (mem.info.base == .reg and @as(Register, @enumFromInt(mem.base)) == .rip) {
1236 assert(mem.info.index == .none and mem.info.scale == .@"1");1236 assert(mem.info.index == .none and mem.info.scale == .@"1");
1237 return encoder.Instruction.Memory.rip(mem.info.size, @bitCast(mem.off));1237 return encoder.Instruction.Memory.initRip(mem.info.size, @bitCast(mem.off));
1238 }1238 }
1239 return encoder.Instruction.Memory.sib(mem.info.size, .{1239 return encoder.Instruction.Memory.initSib(mem.info.size, .{
1240 .disp = @bitCast(mem.off),1240 .disp = @bitCast(mem.off),
1241 .base = switch (mem.info.base) {1241 .base = switch (mem.info.base) {
1242 .none => .none,1242 .none => .none,
...@@ -1258,7 +1258,7 @@ pub const Memory = struct {...@@ -1258,7 +1258,7 @@ pub const Memory = struct {
1258 },1258 },
1259 .off => {1259 .off => {
1260 assert(mem.info.base == .reg);1260 assert(mem.info.base == .reg);
1261 return encoder.Instruction.Memory.moffs(1261 return encoder.Instruction.Memory.initMoffs(
1262 @enumFromInt(mem.base),1262 @enumFromInt(mem.base),
1263 @as(u64, mem.extra) << 32 | mem.off,1263 @as(u64, mem.extra) << 32 | mem.off,
1264 );1264 );
src/arch/x86_64/encoder.zig+77-77
...@@ -110,12 +110,12 @@ pub const Instruction = struct {...@@ -110,12 +110,12 @@ pub const Instruction = struct {
110 offset: u64,110 offset: u64,
111 };111 };
112112
113 pub fn moffs(reg: Register, offset: u64) Memory {113 pub fn initMoffs(reg: Register, offset: u64) Memory {
114 assert(reg.class() == .segment);114 assert(reg.class() == .segment);
115 return .{ .moffs = .{ .seg = reg, .offset = offset } };115 return .{ .moffs = .{ .seg = reg, .offset = offset } };
116 }116 }
117117
118 pub fn sib(ptr_size: PtrSize, args: struct {118 pub fn initSib(ptr_size: PtrSize, args: struct {
119 disp: i32 = 0,119 disp: i32 = 0,
120 base: Base = .none,120 base: Base = .none,
121 scale_index: ?ScaleIndex = null,121 scale_index: ?ScaleIndex = null,
...@@ -129,7 +129,7 @@ pub const Instruction = struct {...@@ -129,7 +129,7 @@ pub const Instruction = struct {
129 } };129 } };
130 }130 }
131131
132 pub fn rip(ptr_size: PtrSize, displacement: i32) Memory {132 pub fn initRip(ptr_size: PtrSize, displacement: i32) Memory {
133 return .{ .rip = .{ .ptr_size = ptr_size, .disp = displacement } };133 return .{ .rip = .{ .ptr_size = ptr_size, .disp = displacement } };
134 }134 }
135135
...@@ -1266,7 +1266,7 @@ test "lower MI encoding" {...@@ -1266,7 +1266,7 @@ test "lower MI encoding" {
1266 try expectEqualHexStrings("\x49\xC7\xC4\x00\x10\x00\x00", enc.code(), "mov r12, 0x1000");1266 try expectEqualHexStrings("\x49\xC7\xC4\x00\x10\x00\x00", enc.code(), "mov r12, 0x1000");
12671267
1268 try enc.encode(.mov, &.{1268 try enc.encode(.mov, &.{
1269 .{ .mem = Instruction.Memory.sib(.byte, .{ .base = .{ .reg = .r12 } }) },1269 .{ .mem = Instruction.Memory.initSib(.byte, .{ .base = .{ .reg = .r12 } }) },
1270 .{ .imm = Instruction.Immediate.u(0x10) },1270 .{ .imm = Instruction.Immediate.u(0x10) },
1271 });1271 });
1272 try expectEqualHexStrings("\x41\xC6\x04\x24\x10", enc.code(), "mov BYTE PTR [r12], 0x10");1272 try expectEqualHexStrings("\x41\xC6\x04\x24\x10", enc.code(), "mov BYTE PTR [r12], 0x10");
...@@ -1290,13 +1290,13 @@ test "lower MI encoding" {...@@ -1290,13 +1290,13 @@ test "lower MI encoding" {
1290 try expectEqualHexStrings("\x48\xc7\xc0\x10\x00\x00\x00", enc.code(), "mov rax, 0x10");1290 try expectEqualHexStrings("\x48\xc7\xc0\x10\x00\x00\x00", enc.code(), "mov rax, 0x10");
12911291
1292 try enc.encode(.mov, &.{1292 try enc.encode(.mov, &.{
1293 .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .r11 } }) },1293 .{ .mem = Instruction.Memory.initSib(.dword, .{ .base = .{ .reg = .r11 } }) },
1294 .{ .imm = Instruction.Immediate.u(0x10) },1294 .{ .imm = Instruction.Immediate.u(0x10) },
1295 });1295 });
1296 try expectEqualHexStrings("\x41\xc7\x03\x10\x00\x00\x00", enc.code(), "mov DWORD PTR [r11], 0x10");1296 try expectEqualHexStrings("\x41\xc7\x03\x10\x00\x00\x00", enc.code(), "mov DWORD PTR [r11], 0x10");
12971297
1298 try enc.encode(.mov, &.{1298 try enc.encode(.mov, &.{
1299 .{ .mem = Instruction.Memory.rip(.qword, 0x10) },1299 .{ .mem = Instruction.Memory.initRip(.qword, 0x10) },
1300 .{ .imm = Instruction.Immediate.u(0x10) },1300 .{ .imm = Instruction.Immediate.u(0x10) },
1301 });1301 });
1302 try expectEqualHexStrings(1302 try expectEqualHexStrings(
...@@ -1306,25 +1306,25 @@ test "lower MI encoding" {...@@ -1306,25 +1306,25 @@ test "lower MI encoding" {
1306 );1306 );
13071307
1308 try enc.encode(.mov, &.{1308 try enc.encode(.mov, &.{
1309 .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .rbp }, .disp = -8 }) },1309 .{ .mem = Instruction.Memory.initSib(.qword, .{ .base = .{ .reg = .rbp }, .disp = -8 }) },
1310 .{ .imm = Instruction.Immediate.u(0x10) },1310 .{ .imm = Instruction.Immediate.u(0x10) },
1311 });1311 });
1312 try expectEqualHexStrings("\x48\xc7\x45\xf8\x10\x00\x00\x00", enc.code(), "mov QWORD PTR [rbp - 8], 0x10");1312 try expectEqualHexStrings("\x48\xc7\x45\xf8\x10\x00\x00\x00", enc.code(), "mov QWORD PTR [rbp - 8], 0x10");
13131313
1314 try enc.encode(.mov, &.{1314 try enc.encode(.mov, &.{
1315 .{ .mem = Instruction.Memory.sib(.word, .{ .base = .{ .reg = .rbp }, .disp = -2 }) },1315 .{ .mem = Instruction.Memory.initSib(.word, .{ .base = .{ .reg = .rbp }, .disp = -2 }) },
1316 .{ .imm = Instruction.Immediate.s(-16) },1316 .{ .imm = Instruction.Immediate.s(-16) },
1317 });1317 });
1318 try expectEqualHexStrings("\x66\xC7\x45\xFE\xF0\xFF", enc.code(), "mov WORD PTR [rbp - 2], -16");1318 try expectEqualHexStrings("\x66\xC7\x45\xFE\xF0\xFF", enc.code(), "mov WORD PTR [rbp - 2], -16");
13191319
1320 try enc.encode(.mov, &.{1320 try enc.encode(.mov, &.{
1321 .{ .mem = Instruction.Memory.sib(.byte, .{ .base = .{ .reg = .rbp }, .disp = -1 }) },1321 .{ .mem = Instruction.Memory.initSib(.byte, .{ .base = .{ .reg = .rbp }, .disp = -1 }) },
1322 .{ .imm = Instruction.Immediate.u(0x10) },1322 .{ .imm = Instruction.Immediate.u(0x10) },
1323 });1323 });
1324 try expectEqualHexStrings("\xC6\x45\xFF\x10", enc.code(), "mov BYTE PTR [rbp - 1], 0x10");1324 try expectEqualHexStrings("\xC6\x45\xFF\x10", enc.code(), "mov BYTE PTR [rbp - 1], 0x10");
13251325
1326 try enc.encode(.mov, &.{1326 try enc.encode(.mov, &.{
1327 .{ .mem = Instruction.Memory.sib(.qword, .{1327 .{ .mem = Instruction.Memory.initSib(.qword, .{
1328 .base = .{ .reg = .ds },1328 .base = .{ .reg = .ds },
1329 .disp = 0x10000000,1329 .disp = 0x10000000,
1330 .scale_index = .{ .scale = 2, .index = .rcx },1330 .scale_index = .{ .scale = 2, .index = .rcx },
...@@ -1338,13 +1338,13 @@ test "lower MI encoding" {...@@ -1338,13 +1338,13 @@ test "lower MI encoding" {
1338 );1338 );
13391339
1340 try enc.encode(.adc, &.{1340 try enc.encode(.adc, &.{
1341 .{ .mem = Instruction.Memory.sib(.byte, .{ .base = .{ .reg = .rbp }, .disp = -0x10 }) },1341 .{ .mem = Instruction.Memory.initSib(.byte, .{ .base = .{ .reg = .rbp }, .disp = -0x10 }) },
1342 .{ .imm = Instruction.Immediate.u(0x10) },1342 .{ .imm = Instruction.Immediate.u(0x10) },
1343 });1343 });
1344 try expectEqualHexStrings("\x80\x55\xF0\x10", enc.code(), "adc BYTE PTR [rbp - 0x10], 0x10");1344 try expectEqualHexStrings("\x80\x55\xF0\x10", enc.code(), "adc BYTE PTR [rbp - 0x10], 0x10");
13451345
1346 try enc.encode(.adc, &.{1346 try enc.encode(.adc, &.{
1347 .{ .mem = Instruction.Memory.rip(.qword, 0) },1347 .{ .mem = Instruction.Memory.initRip(.qword, 0) },
1348 .{ .imm = Instruction.Immediate.u(0x10) },1348 .{ .imm = Instruction.Immediate.u(0x10) },
1349 });1349 });
1350 try expectEqualHexStrings("\x48\x83\x15\x00\x00\x00\x00\x10", enc.code(), "adc QWORD PTR [rip], 0x10");1350 try expectEqualHexStrings("\x48\x83\x15\x00\x00\x00\x00\x10", enc.code(), "adc QWORD PTR [rip], 0x10");
...@@ -1356,7 +1356,7 @@ test "lower MI encoding" {...@@ -1356,7 +1356,7 @@ test "lower MI encoding" {
1356 try expectEqualHexStrings("\x48\x83\xD0\x10", enc.code(), "adc rax, 0x10");1356 try expectEqualHexStrings("\x48\x83\xD0\x10", enc.code(), "adc rax, 0x10");
13571357
1358 try enc.encode(.add, &.{1358 try enc.encode(.add, &.{
1359 .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .rdx }, .disp = -8 }) },1359 .{ .mem = Instruction.Memory.initSib(.dword, .{ .base = .{ .reg = .rdx }, .disp = -8 }) },
1360 .{ .imm = Instruction.Immediate.u(0x10) },1360 .{ .imm = Instruction.Immediate.u(0x10) },
1361 });1361 });
1362 try expectEqualHexStrings("\x83\x42\xF8\x10", enc.code(), "add DWORD PTR [rdx - 8], 0x10");1362 try expectEqualHexStrings("\x83\x42\xF8\x10", enc.code(), "add DWORD PTR [rdx - 8], 0x10");
...@@ -1368,13 +1368,13 @@ test "lower MI encoding" {...@@ -1368,13 +1368,13 @@ test "lower MI encoding" {
1368 try expectEqualHexStrings("\x48\x83\xC0\x10", enc.code(), "add rax, 0x10");1368 try expectEqualHexStrings("\x48\x83\xC0\x10", enc.code(), "add rax, 0x10");
13691369
1370 try enc.encode(.add, &.{1370 try enc.encode(.add, &.{
1371 .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .rbp }, .disp = -0x10 }) },1371 .{ .mem = Instruction.Memory.initSib(.qword, .{ .base = .{ .reg = .rbp }, .disp = -0x10 }) },
1372 .{ .imm = Instruction.Immediate.s(-0x10) },1372 .{ .imm = Instruction.Immediate.s(-0x10) },
1373 });1373 });
1374 try expectEqualHexStrings("\x48\x83\x45\xF0\xF0", enc.code(), "add QWORD PTR [rbp - 0x10], -0x10");1374 try expectEqualHexStrings("\x48\x83\x45\xF0\xF0", enc.code(), "add QWORD PTR [rbp - 0x10], -0x10");
13751375
1376 try enc.encode(.@"and", &.{1376 try enc.encode(.@"and", &.{
1377 .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .ds }, .disp = 0x10000000 }) },1377 .{ .mem = Instruction.Memory.initSib(.dword, .{ .base = .{ .reg = .ds }, .disp = 0x10000000 }) },
1378 .{ .imm = Instruction.Immediate.u(0x10) },1378 .{ .imm = Instruction.Immediate.u(0x10) },
1379 });1379 });
1380 try expectEqualHexStrings(1380 try expectEqualHexStrings(
...@@ -1384,7 +1384,7 @@ test "lower MI encoding" {...@@ -1384,7 +1384,7 @@ test "lower MI encoding" {
1384 );1384 );
13851385
1386 try enc.encode(.@"and", &.{1386 try enc.encode(.@"and", &.{
1387 .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .es }, .disp = 0x10000000 }) },1387 .{ .mem = Instruction.Memory.initSib(.dword, .{ .base = .{ .reg = .es }, .disp = 0x10000000 }) },
1388 .{ .imm = Instruction.Immediate.u(0x10) },1388 .{ .imm = Instruction.Immediate.u(0x10) },
1389 });1389 });
1390 try expectEqualHexStrings(1390 try expectEqualHexStrings(
...@@ -1394,7 +1394,7 @@ test "lower MI encoding" {...@@ -1394,7 +1394,7 @@ test "lower MI encoding" {
1394 );1394 );
13951395
1396 try enc.encode(.@"and", &.{1396 try enc.encode(.@"and", &.{
1397 .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .r12 }, .disp = 0x10000000 }) },1397 .{ .mem = Instruction.Memory.initSib(.dword, .{ .base = .{ .reg = .r12 }, .disp = 0x10000000 }) },
1398 .{ .imm = Instruction.Immediate.u(0x10) },1398 .{ .imm = Instruction.Immediate.u(0x10) },
1399 });1399 });
1400 try expectEqualHexStrings(1400 try expectEqualHexStrings(
...@@ -1404,7 +1404,7 @@ test "lower MI encoding" {...@@ -1404,7 +1404,7 @@ test "lower MI encoding" {
1404 );1404 );
14051405
1406 try enc.encode(.sub, &.{1406 try enc.encode(.sub, &.{
1407 .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .r11 }, .disp = 0x10000000 }) },1407 .{ .mem = Instruction.Memory.initSib(.dword, .{ .base = .{ .reg = .r11 }, .disp = 0x10000000 }) },
1408 .{ .imm = Instruction.Immediate.u(0x10) },1408 .{ .imm = Instruction.Immediate.u(0x10) },
1409 });1409 });
1410 try expectEqualHexStrings(1410 try expectEqualHexStrings(
...@@ -1419,25 +1419,25 @@ test "lower RM encoding" {...@@ -1419,25 +1419,25 @@ test "lower RM encoding" {
14191419
1420 try enc.encode(.mov, &.{1420 try enc.encode(.mov, &.{
1421 .{ .reg = .rax },1421 .{ .reg = .rax },
1422 .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .r11 } }) },1422 .{ .mem = Instruction.Memory.initSib(.qword, .{ .base = .{ .reg = .r11 } }) },
1423 });1423 });
1424 try expectEqualHexStrings("\x49\x8b\x03", enc.code(), "mov rax, QWORD PTR [r11]");1424 try expectEqualHexStrings("\x49\x8b\x03", enc.code(), "mov rax, QWORD PTR [r11]");
14251425
1426 try enc.encode(.mov, &.{1426 try enc.encode(.mov, &.{
1427 .{ .reg = .rbx },1427 .{ .reg = .rbx },
1428 .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .ds }, .disp = 0x10 }) },1428 .{ .mem = Instruction.Memory.initSib(.qword, .{ .base = .{ .reg = .ds }, .disp = 0x10 }) },
1429 });1429 });
1430 try expectEqualHexStrings("\x48\x8B\x1C\x25\x10\x00\x00\x00", enc.code(), "mov rbx, QWORD PTR ds:0x10");1430 try expectEqualHexStrings("\x48\x8B\x1C\x25\x10\x00\x00\x00", enc.code(), "mov rbx, QWORD PTR ds:0x10");
14311431
1432 try enc.encode(.mov, &.{1432 try enc.encode(.mov, &.{
1433 .{ .reg = .rax },1433 .{ .reg = .rax },
1434 .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .rbp }, .disp = -4 }) },1434 .{ .mem = Instruction.Memory.initSib(.qword, .{ .base = .{ .reg = .rbp }, .disp = -4 }) },
1435 });1435 });
1436 try expectEqualHexStrings("\x48\x8B\x45\xFC", enc.code(), "mov rax, QWORD PTR [rbp - 4]");1436 try expectEqualHexStrings("\x48\x8B\x45\xFC", enc.code(), "mov rax, QWORD PTR [rbp - 4]");
14371437
1438 try enc.encode(.mov, &.{1438 try enc.encode(.mov, &.{
1439 .{ .reg = .rax },1439 .{ .reg = .rax },
1440 .{ .mem = Instruction.Memory.sib(.qword, .{1440 .{ .mem = Instruction.Memory.initSib(.qword, .{
1441 .base = .{ .reg = .rbp },1441 .base = .{ .reg = .rbp },
1442 .scale_index = .{ .scale = 1, .index = .rcx },1442 .scale_index = .{ .scale = 1, .index = .rcx },
1443 .disp = -8,1443 .disp = -8,
...@@ -1447,7 +1447,7 @@ test "lower RM encoding" {...@@ -1447,7 +1447,7 @@ test "lower RM encoding" {
14471447
1448 try enc.encode(.mov, &.{1448 try enc.encode(.mov, &.{
1449 .{ .reg = .eax },1449 .{ .reg = .eax },
1450 .{ .mem = Instruction.Memory.sib(.dword, .{1450 .{ .mem = Instruction.Memory.initSib(.dword, .{
1451 .base = .{ .reg = .rbp },1451 .base = .{ .reg = .rbp },
1452 .scale_index = .{ .scale = 4, .index = .rdx },1452 .scale_index = .{ .scale = 4, .index = .rdx },
1453 .disp = -4,1453 .disp = -4,
...@@ -1457,7 +1457,7 @@ test "lower RM encoding" {...@@ -1457,7 +1457,7 @@ test "lower RM encoding" {
14571457
1458 try enc.encode(.mov, &.{1458 try enc.encode(.mov, &.{
1459 .{ .reg = .rax },1459 .{ .reg = .rax },
1460 .{ .mem = Instruction.Memory.sib(.qword, .{1460 .{ .mem = Instruction.Memory.initSib(.qword, .{
1461 .base = .{ .reg = .rbp },1461 .base = .{ .reg = .rbp },
1462 .scale_index = .{ .scale = 8, .index = .rcx },1462 .scale_index = .{ .scale = 8, .index = .rcx },
1463 .disp = -8,1463 .disp = -8,
...@@ -1467,7 +1467,7 @@ test "lower RM encoding" {...@@ -1467,7 +1467,7 @@ test "lower RM encoding" {
14671467
1468 try enc.encode(.mov, &.{1468 try enc.encode(.mov, &.{
1469 .{ .reg = .r8b },1469 .{ .reg = .r8b },
1470 .{ .mem = Instruction.Memory.sib(.byte, .{1470 .{ .mem = Instruction.Memory.initSib(.byte, .{
1471 .base = .{ .reg = .rsi },1471 .base = .{ .reg = .rsi },
1472 .scale_index = .{ .scale = 1, .index = .rcx },1472 .scale_index = .{ .scale = 1, .index = .rcx },
1473 .disp = -24,1473 .disp = -24,
...@@ -1483,7 +1483,7 @@ test "lower RM encoding" {...@@ -1483,7 +1483,7 @@ test "lower RM encoding" {
1483 try expectEqualHexStrings("\x48\x8C\xC8", enc.code(), "mov rax, cs");1483 try expectEqualHexStrings("\x48\x8C\xC8", enc.code(), "mov rax, cs");
14841484
1485 try enc.encode(.mov, &.{1485 try enc.encode(.mov, &.{
1486 .{ .mem = Instruction.Memory.sib(.word, .{ .base = .{ .reg = .rbp }, .disp = -16 }) },1486 .{ .mem = Instruction.Memory.initSib(.word, .{ .base = .{ .reg = .rbp }, .disp = -16 }) },
1487 .{ .reg = .fs },1487 .{ .reg = .fs },
1488 });1488 });
1489 try expectEqualHexStrings("\x8C\x65\xF0", enc.code(), "mov WORD PTR [rbp - 16], fs");1489 try expectEqualHexStrings("\x8C\x65\xF0", enc.code(), "mov WORD PTR [rbp - 16], fs");
...@@ -1514,19 +1514,19 @@ test "lower RM encoding" {...@@ -1514,19 +1514,19 @@ test "lower RM encoding" {
15141514
1515 try enc.encode(.movsx, &.{1515 try enc.encode(.movsx, &.{
1516 .{ .reg = .eax },1516 .{ .reg = .eax },
1517 .{ .mem = Instruction.Memory.sib(.word, .{ .base = .{ .reg = .rbp } }) },1517 .{ .mem = Instruction.Memory.initSib(.word, .{ .base = .{ .reg = .rbp } }) },
1518 });1518 });
1519 try expectEqualHexStrings("\x0F\xBF\x45\x00", enc.code(), "movsx eax, BYTE PTR [rbp]");1519 try expectEqualHexStrings("\x0F\xBF\x45\x00", enc.code(), "movsx eax, BYTE PTR [rbp]");
15201520
1521 try enc.encode(.movsx, &.{1521 try enc.encode(.movsx, &.{
1522 .{ .reg = .eax },1522 .{ .reg = .eax },
1523 .{ .mem = Instruction.Memory.sib(.byte, .{ .scale_index = .{ .index = .rax, .scale = 2 } }) },1523 .{ .mem = Instruction.Memory.initSib(.byte, .{ .scale_index = .{ .index = .rax, .scale = 2 } }) },
1524 });1524 });
1525 try expectEqualHexStrings("\x0F\xBE\x04\x45\x00\x00\x00\x00", enc.code(), "movsx eax, BYTE PTR [rax * 2]");1525 try expectEqualHexStrings("\x0F\xBE\x04\x45\x00\x00\x00\x00", enc.code(), "movsx eax, BYTE PTR [rax * 2]");
15261526
1527 try enc.encode(.movsx, &.{1527 try enc.encode(.movsx, &.{
1528 .{ .reg = .ax },1528 .{ .reg = .ax },
1529 .{ .mem = Instruction.Memory.rip(.byte, 0x10) },1529 .{ .mem = Instruction.Memory.initRip(.byte, 0x10) },
1530 });1530 });
1531 try expectEqualHexStrings("\x66\x0F\xBE\x05\x10\x00\x00\x00", enc.code(), "movsx ax, BYTE PTR [rip + 0x10]");1531 try expectEqualHexStrings("\x66\x0F\xBE\x05\x10\x00\x00\x00", enc.code(), "movsx ax, BYTE PTR [rip + 0x10]");
15321532
...@@ -1544,37 +1544,37 @@ test "lower RM encoding" {...@@ -1544,37 +1544,37 @@ test "lower RM encoding" {
15441544
1545 try enc.encode(.lea, &.{1545 try enc.encode(.lea, &.{
1546 .{ .reg = .rax },1546 .{ .reg = .rax },
1547 .{ .mem = Instruction.Memory.rip(.qword, 0x10) },1547 .{ .mem = Instruction.Memory.initRip(.qword, 0x10) },
1548 });1548 });
1549 try expectEqualHexStrings("\x48\x8D\x05\x10\x00\x00\x00", enc.code(), "lea rax, QWORD PTR [rip + 0x10]");1549 try expectEqualHexStrings("\x48\x8D\x05\x10\x00\x00\x00", enc.code(), "lea rax, QWORD PTR [rip + 0x10]");
15501550
1551 try enc.encode(.lea, &.{1551 try enc.encode(.lea, &.{
1552 .{ .reg = .rax },1552 .{ .reg = .rax },
1553 .{ .mem = Instruction.Memory.rip(.dword, 0x10) },1553 .{ .mem = Instruction.Memory.initRip(.dword, 0x10) },
1554 });1554 });
1555 try expectEqualHexStrings("\x48\x8D\x05\x10\x00\x00\x00", enc.code(), "lea rax, DWORD PTR [rip + 0x10]");1555 try expectEqualHexStrings("\x48\x8D\x05\x10\x00\x00\x00", enc.code(), "lea rax, DWORD PTR [rip + 0x10]");
15561556
1557 try enc.encode(.lea, &.{1557 try enc.encode(.lea, &.{
1558 .{ .reg = .eax },1558 .{ .reg = .eax },
1559 .{ .mem = Instruction.Memory.rip(.dword, 0x10) },1559 .{ .mem = Instruction.Memory.initRip(.dword, 0x10) },
1560 });1560 });
1561 try expectEqualHexStrings("\x8D\x05\x10\x00\x00\x00", enc.code(), "lea eax, DWORD PTR [rip + 0x10]");1561 try expectEqualHexStrings("\x8D\x05\x10\x00\x00\x00", enc.code(), "lea eax, DWORD PTR [rip + 0x10]");
15621562
1563 try enc.encode(.lea, &.{1563 try enc.encode(.lea, &.{
1564 .{ .reg = .eax },1564 .{ .reg = .eax },
1565 .{ .mem = Instruction.Memory.rip(.word, 0x10) },1565 .{ .mem = Instruction.Memory.initRip(.word, 0x10) },
1566 });1566 });
1567 try expectEqualHexStrings("\x8D\x05\x10\x00\x00\x00", enc.code(), "lea eax, WORD PTR [rip + 0x10]");1567 try expectEqualHexStrings("\x8D\x05\x10\x00\x00\x00", enc.code(), "lea eax, WORD PTR [rip + 0x10]");
15681568
1569 try enc.encode(.lea, &.{1569 try enc.encode(.lea, &.{
1570 .{ .reg = .ax },1570 .{ .reg = .ax },
1571 .{ .mem = Instruction.Memory.rip(.byte, 0x10) },1571 .{ .mem = Instruction.Memory.initRip(.byte, 0x10) },
1572 });1572 });
1573 try expectEqualHexStrings("\x66\x8D\x05\x10\x00\x00\x00", enc.code(), "lea ax, BYTE PTR [rip + 0x10]");1573 try expectEqualHexStrings("\x66\x8D\x05\x10\x00\x00\x00", enc.code(), "lea ax, BYTE PTR [rip + 0x10]");
15741574
1575 try enc.encode(.lea, &.{1575 try enc.encode(.lea, &.{
1576 .{ .reg = .rsi },1576 .{ .reg = .rsi },
1577 .{ .mem = Instruction.Memory.sib(.qword, .{1577 .{ .mem = Instruction.Memory.initSib(.qword, .{
1578 .base = .{ .reg = .rbp },1578 .base = .{ .reg = .rbp },
1579 .scale_index = .{ .scale = 1, .index = .rcx },1579 .scale_index = .{ .scale = 1, .index = .rcx },
1580 }) },1580 }) },
...@@ -1583,31 +1583,31 @@ test "lower RM encoding" {...@@ -1583,31 +1583,31 @@ test "lower RM encoding" {
15831583
1584 try enc.encode(.add, &.{1584 try enc.encode(.add, &.{
1585 .{ .reg = .r11 },1585 .{ .reg = .r11 },
1586 .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .ds }, .disp = 0x10000000 }) },1586 .{ .mem = Instruction.Memory.initSib(.qword, .{ .base = .{ .reg = .ds }, .disp = 0x10000000 }) },
1587 });1587 });
1588 try expectEqualHexStrings("\x4C\x03\x1C\x25\x00\x00\x00\x10", enc.code(), "add r11, QWORD PTR ds:0x10000000");1588 try expectEqualHexStrings("\x4C\x03\x1C\x25\x00\x00\x00\x10", enc.code(), "add r11, QWORD PTR ds:0x10000000");
15891589
1590 try enc.encode(.add, &.{1590 try enc.encode(.add, &.{
1591 .{ .reg = .r12b },1591 .{ .reg = .r12b },
1592 .{ .mem = Instruction.Memory.sib(.byte, .{ .base = .{ .reg = .ds }, .disp = 0x10000000 }) },1592 .{ .mem = Instruction.Memory.initSib(.byte, .{ .base = .{ .reg = .ds }, .disp = 0x10000000 }) },
1593 });1593 });
1594 try expectEqualHexStrings("\x44\x02\x24\x25\x00\x00\x00\x10", enc.code(), "add r11b, BYTE PTR ds:0x10000000");1594 try expectEqualHexStrings("\x44\x02\x24\x25\x00\x00\x00\x10", enc.code(), "add r11b, BYTE PTR ds:0x10000000");
15951595
1596 try enc.encode(.add, &.{1596 try enc.encode(.add, &.{
1597 .{ .reg = .r12b },1597 .{ .reg = .r12b },
1598 .{ .mem = Instruction.Memory.sib(.byte, .{ .base = .{ .reg = .fs }, .disp = 0x10000000 }) },1598 .{ .mem = Instruction.Memory.initSib(.byte, .{ .base = .{ .reg = .fs }, .disp = 0x10000000 }) },
1599 });1599 });
1600 try expectEqualHexStrings("\x64\x44\x02\x24\x25\x00\x00\x00\x10", enc.code(), "add r11b, BYTE PTR fs:0x10000000");1600 try expectEqualHexStrings("\x64\x44\x02\x24\x25\x00\x00\x00\x10", enc.code(), "add r11b, BYTE PTR fs:0x10000000");
16011601
1602 try enc.encode(.sub, &.{1602 try enc.encode(.sub, &.{
1603 .{ .reg = .r11 },1603 .{ .reg = .r11 },
1604 .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .r13 }, .disp = 0x10000000 }) },1604 .{ .mem = Instruction.Memory.initSib(.qword, .{ .base = .{ .reg = .r13 }, .disp = 0x10000000 }) },
1605 });1605 });
1606 try expectEqualHexStrings("\x4D\x2B\x9D\x00\x00\x00\x10", enc.code(), "sub r11, QWORD PTR [r13 + 0x10000000]");1606 try expectEqualHexStrings("\x4D\x2B\x9D\x00\x00\x00\x10", enc.code(), "sub r11, QWORD PTR [r13 + 0x10000000]");
16071607
1608 try enc.encode(.sub, &.{1608 try enc.encode(.sub, &.{
1609 .{ .reg = .r11 },1609 .{ .reg = .r11 },
1610 .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .r12 }, .disp = 0x10000000 }) },1610 .{ .mem = Instruction.Memory.initSib(.qword, .{ .base = .{ .reg = .r12 }, .disp = 0x10000000 }) },
1611 });1611 });
1612 try expectEqualHexStrings("\x4D\x2B\x9C\x24\x00\x00\x00\x10", enc.code(), "sub r11, QWORD PTR [r12 + 0x10000000]");1612 try expectEqualHexStrings("\x4D\x2B\x9C\x24\x00\x00\x00\x10", enc.code(), "sub r11, QWORD PTR [r12 + 0x10000000]");
16131613
...@@ -1630,7 +1630,7 @@ test "lower RMI encoding" {...@@ -1630,7 +1630,7 @@ test "lower RMI encoding" {
16301630
1631 try enc.encode(.imul, &.{1631 try enc.encode(.imul, &.{
1632 .{ .reg = .r11 },1632 .{ .reg = .r11 },
1633 .{ .mem = Instruction.Memory.rip(.qword, -16) },1633 .{ .mem = Instruction.Memory.initRip(.qword, -16) },
1634 .{ .imm = Instruction.Immediate.s(-1024) },1634 .{ .imm = Instruction.Immediate.s(-1024) },
1635 });1635 });
1636 try expectEqualHexStrings(1636 try expectEqualHexStrings(
...@@ -1641,7 +1641,7 @@ test "lower RMI encoding" {...@@ -1641,7 +1641,7 @@ test "lower RMI encoding" {
16411641
1642 try enc.encode(.imul, &.{1642 try enc.encode(.imul, &.{
1643 .{ .reg = .bx },1643 .{ .reg = .bx },
1644 .{ .mem = Instruction.Memory.sib(.word, .{ .base = .{ .reg = .rbp }, .disp = -16 }) },1644 .{ .mem = Instruction.Memory.initSib(.word, .{ .base = .{ .reg = .rbp }, .disp = -16 }) },
1645 .{ .imm = Instruction.Immediate.s(-1024) },1645 .{ .imm = Instruction.Immediate.s(-1024) },
1646 });1646 });
1647 try expectEqualHexStrings(1647 try expectEqualHexStrings(
...@@ -1652,7 +1652,7 @@ test "lower RMI encoding" {...@@ -1652,7 +1652,7 @@ test "lower RMI encoding" {
16521652
1653 try enc.encode(.imul, &.{1653 try enc.encode(.imul, &.{
1654 .{ .reg = .bx },1654 .{ .reg = .bx },
1655 .{ .mem = Instruction.Memory.sib(.word, .{ .base = .{ .reg = .rbp }, .disp = -16 }) },1655 .{ .mem = Instruction.Memory.initSib(.word, .{ .base = .{ .reg = .rbp }, .disp = -16 }) },
1656 .{ .imm = Instruction.Immediate.u(1024) },1656 .{ .imm = Instruction.Immediate.u(1024) },
1657 });1657 });
1658 try expectEqualHexStrings(1658 try expectEqualHexStrings(
...@@ -1672,19 +1672,19 @@ test "lower MR encoding" {...@@ -1672,19 +1672,19 @@ test "lower MR encoding" {
1672 try expectEqualHexStrings("\x48\x89\xD8", enc.code(), "mov rax, rbx");1672 try expectEqualHexStrings("\x48\x89\xD8", enc.code(), "mov rax, rbx");
16731673
1674 try enc.encode(.mov, &.{1674 try enc.encode(.mov, &.{
1675 .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .rbp }, .disp = -4 }) },1675 .{ .mem = Instruction.Memory.initSib(.qword, .{ .base = .{ .reg = .rbp }, .disp = -4 }) },
1676 .{ .reg = .r11 },1676 .{ .reg = .r11 },
1677 });1677 });
1678 try expectEqualHexStrings("\x4c\x89\x5d\xfc", enc.code(), "mov QWORD PTR [rbp - 4], r11");1678 try expectEqualHexStrings("\x4c\x89\x5d\xfc", enc.code(), "mov QWORD PTR [rbp - 4], r11");
16791679
1680 try enc.encode(.mov, &.{1680 try enc.encode(.mov, &.{
1681 .{ .mem = Instruction.Memory.rip(.qword, 0x10) },1681 .{ .mem = Instruction.Memory.initRip(.qword, 0x10) },
1682 .{ .reg = .r12 },1682 .{ .reg = .r12 },
1683 });1683 });
1684 try expectEqualHexStrings("\x4C\x89\x25\x10\x00\x00\x00", enc.code(), "mov QWORD PTR [rip + 0x10], r12");1684 try expectEqualHexStrings("\x4C\x89\x25\x10\x00\x00\x00", enc.code(), "mov QWORD PTR [rip + 0x10], r12");
16851685
1686 try enc.encode(.mov, &.{1686 try enc.encode(.mov, &.{
1687 .{ .mem = Instruction.Memory.sib(.qword, .{1687 .{ .mem = Instruction.Memory.initSib(.qword, .{
1688 .base = .{ .reg = .r11 },1688 .base = .{ .reg = .r11 },
1689 .scale_index = .{ .scale = 2, .index = .r12 },1689 .scale_index = .{ .scale = 2, .index = .r12 },
1690 .disp = 0x10,1690 .disp = 0x10,
...@@ -1694,13 +1694,13 @@ test "lower MR encoding" {...@@ -1694,13 +1694,13 @@ test "lower MR encoding" {
1694 try expectEqualHexStrings("\x4F\x89\x6C\x63\x10", enc.code(), "mov QWORD PTR [r11 + 2 * r12 + 0x10], r13");1694 try expectEqualHexStrings("\x4F\x89\x6C\x63\x10", enc.code(), "mov QWORD PTR [r11 + 2 * r12 + 0x10], r13");
16951695
1696 try enc.encode(.mov, &.{1696 try enc.encode(.mov, &.{
1697 .{ .mem = Instruction.Memory.rip(.word, -0x10) },1697 .{ .mem = Instruction.Memory.initRip(.word, -0x10) },
1698 .{ .reg = .r12w },1698 .{ .reg = .r12w },
1699 });1699 });
1700 try expectEqualHexStrings("\x66\x44\x89\x25\xF0\xFF\xFF\xFF", enc.code(), "mov WORD PTR [rip - 0x10], r12w");1700 try expectEqualHexStrings("\x66\x44\x89\x25\xF0\xFF\xFF\xFF", enc.code(), "mov WORD PTR [rip - 0x10], r12w");
17011701
1702 try enc.encode(.mov, &.{1702 try enc.encode(.mov, &.{
1703 .{ .mem = Instruction.Memory.sib(.byte, .{1703 .{ .mem = Instruction.Memory.initSib(.byte, .{
1704 .base = .{ .reg = .r11 },1704 .base = .{ .reg = .r11 },
1705 .scale_index = .{ .scale = 2, .index = .r12 },1705 .scale_index = .{ .scale = 2, .index = .r12 },
1706 .disp = 0x10,1706 .disp = 0x10,
...@@ -1710,25 +1710,25 @@ test "lower MR encoding" {...@@ -1710,25 +1710,25 @@ test "lower MR encoding" {
1710 try expectEqualHexStrings("\x47\x88\x6C\x63\x10", enc.code(), "mov BYTE PTR [r11 + 2 * r12 + 0x10], r13b");1710 try expectEqualHexStrings("\x47\x88\x6C\x63\x10", enc.code(), "mov BYTE PTR [r11 + 2 * r12 + 0x10], r13b");
17111711
1712 try enc.encode(.add, &.{1712 try enc.encode(.add, &.{
1713 .{ .mem = Instruction.Memory.sib(.byte, .{ .base = .{ .reg = .ds }, .disp = 0x10000000 }) },1713 .{ .mem = Instruction.Memory.initSib(.byte, .{ .base = .{ .reg = .ds }, .disp = 0x10000000 }) },
1714 .{ .reg = .r12b },1714 .{ .reg = .r12b },
1715 });1715 });
1716 try expectEqualHexStrings("\x44\x00\x24\x25\x00\x00\x00\x10", enc.code(), "add BYTE PTR ds:0x10000000, r12b");1716 try expectEqualHexStrings("\x44\x00\x24\x25\x00\x00\x00\x10", enc.code(), "add BYTE PTR ds:0x10000000, r12b");
17171717
1718 try enc.encode(.add, &.{1718 try enc.encode(.add, &.{
1719 .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .ds }, .disp = 0x10000000 }) },1719 .{ .mem = Instruction.Memory.initSib(.dword, .{ .base = .{ .reg = .ds }, .disp = 0x10000000 }) },
1720 .{ .reg = .r12d },1720 .{ .reg = .r12d },
1721 });1721 });
1722 try expectEqualHexStrings("\x44\x01\x24\x25\x00\x00\x00\x10", enc.code(), "add DWORD PTR [ds:0x10000000], r12d");1722 try expectEqualHexStrings("\x44\x01\x24\x25\x00\x00\x00\x10", enc.code(), "add DWORD PTR [ds:0x10000000], r12d");
17231723
1724 try enc.encode(.add, &.{1724 try enc.encode(.add, &.{
1725 .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .gs }, .disp = 0x10000000 }) },1725 .{ .mem = Instruction.Memory.initSib(.dword, .{ .base = .{ .reg = .gs }, .disp = 0x10000000 }) },
1726 .{ .reg = .r12d },1726 .{ .reg = .r12d },
1727 });1727 });
1728 try expectEqualHexStrings("\x65\x44\x01\x24\x25\x00\x00\x00\x10", enc.code(), "add DWORD PTR [gs:0x10000000], r12d");1728 try expectEqualHexStrings("\x65\x44\x01\x24\x25\x00\x00\x00\x10", enc.code(), "add DWORD PTR [gs:0x10000000], r12d");
17291729
1730 try enc.encode(.sub, &.{1730 try enc.encode(.sub, &.{
1731 .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .r11 }, .disp = 0x10000000 }) },1731 .{ .mem = Instruction.Memory.initSib(.qword, .{ .base = .{ .reg = .r11 }, .disp = 0x10000000 }) },
1732 .{ .reg = .r12 },1732 .{ .reg = .r12 },
1733 });1733 });
1734 try expectEqualHexStrings("\x4D\x29\xA3\x00\x00\x00\x10", enc.code(), "sub QWORD PTR [r11 + 0x10000000], r12");1734 try expectEqualHexStrings("\x4D\x29\xA3\x00\x00\x00\x10", enc.code(), "sub QWORD PTR [r11 + 0x10000000], r12");
...@@ -1743,12 +1743,12 @@ test "lower M encoding" {...@@ -1743,12 +1743,12 @@ test "lower M encoding" {
1743 try expectEqualHexStrings("\x41\xFF\xD4", enc.code(), "call r12");1743 try expectEqualHexStrings("\x41\xFF\xD4", enc.code(), "call r12");
17441744
1745 try enc.encode(.call, &.{1745 try enc.encode(.call, &.{
1746 .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .r12 } }) },1746 .{ .mem = Instruction.Memory.initSib(.qword, .{ .base = .{ .reg = .r12 } }) },
1747 });1747 });
1748 try expectEqualHexStrings("\x41\xFF\x14\x24", enc.code(), "call QWORD PTR [r12]");1748 try expectEqualHexStrings("\x41\xFF\x14\x24", enc.code(), "call QWORD PTR [r12]");
17491749
1750 try enc.encode(.call, &.{1750 try enc.encode(.call, &.{
1751 .{ .mem = Instruction.Memory.sib(.qword, .{1751 .{ .mem = Instruction.Memory.initSib(.qword, .{
1752 .base = .none,1752 .base = .none,
1753 .scale_index = .{ .index = .r11, .scale = 2 },1753 .scale_index = .{ .index = .r11, .scale = 2 },
1754 }) },1754 }) },
...@@ -1756,7 +1756,7 @@ test "lower M encoding" {...@@ -1756,7 +1756,7 @@ test "lower M encoding" {
1756 try expectEqualHexStrings("\x42\xFF\x14\x5D\x00\x00\x00\x00", enc.code(), "call QWORD PTR [r11 * 2]");1756 try expectEqualHexStrings("\x42\xFF\x14\x5D\x00\x00\x00\x00", enc.code(), "call QWORD PTR [r11 * 2]");
17571757
1758 try enc.encode(.call, &.{1758 try enc.encode(.call, &.{
1759 .{ .mem = Instruction.Memory.sib(.qword, .{1759 .{ .mem = Instruction.Memory.initSib(.qword, .{
1760 .base = .none,1760 .base = .none,
1761 .scale_index = .{ .index = .r12, .scale = 2 },1761 .scale_index = .{ .index = .r12, .scale = 2 },
1762 }) },1762 }) },
...@@ -1764,7 +1764,7 @@ test "lower M encoding" {...@@ -1764,7 +1764,7 @@ test "lower M encoding" {
1764 try expectEqualHexStrings("\x42\xFF\x14\x65\x00\x00\x00\x00", enc.code(), "call QWORD PTR [r12 * 2]");1764 try expectEqualHexStrings("\x42\xFF\x14\x65\x00\x00\x00\x00", enc.code(), "call QWORD PTR [r12 * 2]");
17651765
1766 try enc.encode(.call, &.{1766 try enc.encode(.call, &.{
1767 .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .gs } }) },1767 .{ .mem = Instruction.Memory.initSib(.qword, .{ .base = .{ .reg = .gs } }) },
1768 });1768 });
1769 try expectEqualHexStrings("\x65\xFF\x14\x25\x00\x00\x00\x00", enc.code(), "call gs:0x0");1769 try expectEqualHexStrings("\x65\xFF\x14\x25\x00\x00\x00\x00", enc.code(), "call gs:0x0");
17701770
...@@ -1774,22 +1774,22 @@ test "lower M encoding" {...@@ -1774,22 +1774,22 @@ test "lower M encoding" {
1774 try expectEqualHexStrings("\xE8\x00\x00\x00\x00", enc.code(), "call 0x0");1774 try expectEqualHexStrings("\xE8\x00\x00\x00\x00", enc.code(), "call 0x0");
17751775
1776 try enc.encode(.push, &.{1776 try enc.encode(.push, &.{
1777 .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .rbp } }) },1777 .{ .mem = Instruction.Memory.initSib(.qword, .{ .base = .{ .reg = .rbp } }) },
1778 });1778 });
1779 try expectEqualHexStrings("\xFF\x75\x00", enc.code(), "push QWORD PTR [rbp]");1779 try expectEqualHexStrings("\xFF\x75\x00", enc.code(), "push QWORD PTR [rbp]");
17801780
1781 try enc.encode(.push, &.{1781 try enc.encode(.push, &.{
1782 .{ .mem = Instruction.Memory.sib(.word, .{ .base = .{ .reg = .rbp } }) },1782 .{ .mem = Instruction.Memory.initSib(.word, .{ .base = .{ .reg = .rbp } }) },
1783 });1783 });
1784 try expectEqualHexStrings("\x66\xFF\x75\x00", enc.code(), "push QWORD PTR [rbp]");1784 try expectEqualHexStrings("\x66\xFF\x75\x00", enc.code(), "push QWORD PTR [rbp]");
17851785
1786 try enc.encode(.pop, &.{1786 try enc.encode(.pop, &.{
1787 .{ .mem = Instruction.Memory.rip(.qword, 0) },1787 .{ .mem = Instruction.Memory.initRip(.qword, 0) },
1788 });1788 });
1789 try expectEqualHexStrings("\x8F\x05\x00\x00\x00\x00", enc.code(), "pop QWORD PTR [rip]");1789 try expectEqualHexStrings("\x8F\x05\x00\x00\x00\x00", enc.code(), "pop QWORD PTR [rip]");
17901790
1791 try enc.encode(.pop, &.{1791 try enc.encode(.pop, &.{
1792 .{ .mem = Instruction.Memory.rip(.word, 0) },1792 .{ .mem = Instruction.Memory.initRip(.word, 0) },
1793 });1793 });
1794 try expectEqualHexStrings("\x66\x8F\x05\x00\x00\x00\x00", enc.code(), "pop WORD PTR [rbp]");1794 try expectEqualHexStrings("\x66\x8F\x05\x00\x00\x00\x00", enc.code(), "pop WORD PTR [rbp]");
17951795
...@@ -1870,48 +1870,48 @@ test "lower FD/TD encoding" {...@@ -1870,48 +1870,48 @@ test "lower FD/TD encoding" {
18701870
1871 try enc.encode(.mov, &.{1871 try enc.encode(.mov, &.{
1872 .{ .reg = .rax },1872 .{ .reg = .rax },
1873 .{ .mem = Instruction.Memory.moffs(.cs, 0x10) },1873 .{ .mem = Instruction.Memory.initMoffs(.cs, 0x10) },
1874 });1874 });
1875 try expectEqualHexStrings("\x2E\x48\xA1\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs rax, cs:0x10");1875 try expectEqualHexStrings("\x2E\x48\xA1\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs rax, cs:0x10");
18761876
1877 try enc.encode(.mov, &.{1877 try enc.encode(.mov, &.{
1878 .{ .reg = .eax },1878 .{ .reg = .eax },
1879 .{ .mem = Instruction.Memory.moffs(.fs, 0x10) },1879 .{ .mem = Instruction.Memory.initMoffs(.fs, 0x10) },
1880 });1880 });
1881 try expectEqualHexStrings("\x64\xA1\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs eax, fs:0x10");1881 try expectEqualHexStrings("\x64\xA1\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs eax, fs:0x10");
18821882
1883 try enc.encode(.mov, &.{1883 try enc.encode(.mov, &.{
1884 .{ .reg = .ax },1884 .{ .reg = .ax },
1885 .{ .mem = Instruction.Memory.moffs(.gs, 0x10) },1885 .{ .mem = Instruction.Memory.initMoffs(.gs, 0x10) },
1886 });1886 });
1887 try expectEqualHexStrings("\x65\x66\xA1\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs ax, gs:0x10");1887 try expectEqualHexStrings("\x65\x66\xA1\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs ax, gs:0x10");
18881888
1889 try enc.encode(.mov, &.{1889 try enc.encode(.mov, &.{
1890 .{ .reg = .al },1890 .{ .reg = .al },
1891 .{ .mem = Instruction.Memory.moffs(.ds, 0x10) },1891 .{ .mem = Instruction.Memory.initMoffs(.ds, 0x10) },
1892 });1892 });
1893 try expectEqualHexStrings("\xA0\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs al, ds:0x10");1893 try expectEqualHexStrings("\xA0\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs al, ds:0x10");
18941894
1895 try enc.encode(.mov, &.{1895 try enc.encode(.mov, &.{
1896 .{ .mem = Instruction.Memory.moffs(.cs, 0x10) },1896 .{ .mem = Instruction.Memory.initMoffs(.cs, 0x10) },
1897 .{ .reg = .rax },1897 .{ .reg = .rax },
1898 });1898 });
1899 try expectEqualHexStrings("\x2E\x48\xA3\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs cs:0x10, rax");1899 try expectEqualHexStrings("\x2E\x48\xA3\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs cs:0x10, rax");
19001900
1901 try enc.encode(.mov, &.{1901 try enc.encode(.mov, &.{
1902 .{ .mem = Instruction.Memory.moffs(.fs, 0x10) },1902 .{ .mem = Instruction.Memory.initMoffs(.fs, 0x10) },
1903 .{ .reg = .eax },1903 .{ .reg = .eax },
1904 });1904 });
1905 try expectEqualHexStrings("\x64\xA3\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs fs:0x10, eax");1905 try expectEqualHexStrings("\x64\xA3\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs fs:0x10, eax");
19061906
1907 try enc.encode(.mov, &.{1907 try enc.encode(.mov, &.{
1908 .{ .mem = Instruction.Memory.moffs(.gs, 0x10) },1908 .{ .mem = Instruction.Memory.initMoffs(.gs, 0x10) },
1909 .{ .reg = .ax },1909 .{ .reg = .ax },
1910 });1910 });
1911 try expectEqualHexStrings("\x65\x66\xA3\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs gs:0x10, ax");1911 try expectEqualHexStrings("\x65\x66\xA3\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs gs:0x10, ax");
19121912
1913 try enc.encode(.mov, &.{1913 try enc.encode(.mov, &.{
1914 .{ .mem = Instruction.Memory.moffs(.ds, 0x10) },1914 .{ .mem = Instruction.Memory.initMoffs(.ds, 0x10) },
1915 .{ .reg = .al },1915 .{ .reg = .al },
1916 });1916 });
1917 try expectEqualHexStrings("\xA2\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs ds:0x10, al");1917 try expectEqualHexStrings("\xA2\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs ds:0x10, al");
...@@ -1949,16 +1949,16 @@ test "invalid instruction" {...@@ -1949,16 +1949,16 @@ test "invalid instruction" {
1949 .{ .reg = .al },1949 .{ .reg = .al },
1950 });1950 });
1951 try invalidInstruction(.call, &.{1951 try invalidInstruction(.call, &.{
1952 .{ .mem = Instruction.Memory.rip(.dword, 0) },1952 .{ .mem = Instruction.Memory.initRip(.dword, 0) },
1953 });1953 });
1954 try invalidInstruction(.call, &.{1954 try invalidInstruction(.call, &.{
1955 .{ .mem = Instruction.Memory.rip(.word, 0) },1955 .{ .mem = Instruction.Memory.initRip(.word, 0) },
1956 });1956 });
1957 try invalidInstruction(.call, &.{1957 try invalidInstruction(.call, &.{
1958 .{ .mem = Instruction.Memory.rip(.byte, 0) },1958 .{ .mem = Instruction.Memory.initRip(.byte, 0) },
1959 });1959 });
1960 try invalidInstruction(.mov, &.{1960 try invalidInstruction(.mov, &.{
1961 .{ .mem = Instruction.Memory.rip(.word, 0x10) },1961 .{ .mem = Instruction.Memory.initRip(.word, 0x10) },
1962 .{ .reg = .r12 },1962 .{ .reg = .r12 },
1963 });1963 });
1964 try invalidInstruction(.lea, &.{1964 try invalidInstruction(.lea, &.{
...@@ -1967,7 +1967,7 @@ test "invalid instruction" {...@@ -1967,7 +1967,7 @@ test "invalid instruction" {
1967 });1967 });
1968 try invalidInstruction(.lea, &.{1968 try invalidInstruction(.lea, &.{
1969 .{ .reg = .al },1969 .{ .reg = .al },
1970 .{ .mem = Instruction.Memory.rip(.byte, 0) },1970 .{ .mem = Instruction.Memory.initRip(.byte, 0) },
1971 });1971 });
1972 try invalidInstruction(.pop, &.{1972 try invalidInstruction(.pop, &.{
1973 .{ .reg = .r12b },1973 .{ .reg = .r12b },
...@@ -1992,7 +1992,7 @@ fn cannotEncode(mnemonic: Instruction.Mnemonic, ops: []const Instruction.Operand...@@ -1992,7 +1992,7 @@ fn cannotEncode(mnemonic: Instruction.Mnemonic, ops: []const Instruction.Operand
19921992
1993test "cannot encode" {1993test "cannot encode" {
1994 try cannotEncode(.@"test", &.{1994 try cannotEncode(.@"test", &.{
1995 .{ .mem = Instruction.Memory.sib(.byte, .{ .base = .{ .reg = .r12 } }) },1995 .{ .mem = Instruction.Memory.initSib(.byte, .{ .base = .{ .reg = .r12 } }) },
1996 .{ .reg = .ah },1996 .{ .reg = .ah },
1997 });1997 });
1998 try cannotEncode(.@"test", &.{1998 try cannotEncode(.@"test", &.{
...@@ -2369,7 +2369,7 @@ const Assembler = struct {...@@ -2369,7 +2369,7 @@ const Assembler = struct {
2369 if (res.rip) {2369 if (res.rip) {
2370 if (res.base != null or res.scale_index != null or res.offset != null)2370 if (res.base != null or res.scale_index != null or res.offset != null)
2371 return error.InvalidMemoryOperand;2371 return error.InvalidMemoryOperand;
2372 return Instruction.Memory.rip(ptr_size orelse .qword, res.disp orelse 0);2372 return Instruction.Memory.initRip(ptr_size orelse .qword, res.disp orelse 0);
2373 }2373 }
2374 if (res.base) |base| {2374 if (res.base) |base| {
2375 if (res.rip)2375 if (res.rip)
...@@ -2377,9 +2377,9 @@ const Assembler = struct {...@@ -2377,9 +2377,9 @@ const Assembler = struct {
2377 if (res.offset) |offset| {2377 if (res.offset) |offset| {
2378 if (res.scale_index != null or res.disp != null)2378 if (res.scale_index != null or res.disp != null)
2379 return error.InvalidMemoryOperand;2379 return error.InvalidMemoryOperand;
2380 return Instruction.Memory.moffs(base, offset);2380 return Instruction.Memory.initMoffs(base, offset);
2381 }2381 }
2382 return Instruction.Memory.sib(ptr_size orelse .qword, .{2382 return Instruction.Memory.initSib(ptr_size orelse .qword, .{
2383 .base = .{ .reg = base },2383 .base = .{ .reg = base },
2384 .scale_index = res.scale_index,2384 .scale_index = res.scale_index,
2385 .disp = res.disp orelse 0,2385 .disp = res.disp orelse 0,
src/codegen.zig+2-11
...@@ -836,16 +836,6 @@ pub const GenResult = union(enum) {...@@ -836,16 +836,6 @@ pub const GenResult = union(enum) {
836 /// Traditionally, this corresponds to emitting a relocation in a relocatable object file.836 /// Traditionally, this corresponds to emitting a relocation in a relocatable object file.
837 lea_symbol: u32,837 lea_symbol: u32,
838 };838 };
839
840 fn fail(
841 gpa: Allocator,
842 src_loc: Zcu.LazySrcLoc,
843 comptime format: []const u8,
844 args: anytype,
845 ) Allocator.Error!GenResult {
846 const msg = try ErrorMsg.create(gpa, src_loc, format, args);
847 return .{ .fail = msg };
848 }
849};839};
850840
851fn genNavRef(841fn genNavRef(
...@@ -935,7 +925,8 @@ fn genNavRef(...@@ -935,7 +925,8 @@ fn genNavRef(
935 const atom = p9.getAtom(atom_index);925 const atom = p9.getAtom(atom_index);
936 return .{ .mcv = .{ .memory = atom.getOffsetTableAddress(p9) } };926 return .{ .mcv = .{ .memory = atom.getOffsetTableAddress(p9) } };
937 } else {927 } else {
938 return GenResult.fail(gpa, src_loc, "TODO genNavRef for target {}", .{target});928 const msg = try ErrorMsg.create(gpa, src_loc, "TODO genNavRef for target {}", .{target});
929 return .{ .fail = msg };
939 }930 }
940}931}
941932
src/codegen/llvm/BitcodeReader.zig+9-9
...@@ -33,9 +33,9 @@ pub const Block = struct {...@@ -33,9 +33,9 @@ pub const Block = struct {
33 .abbrevs = .{ .abbrevs = .{} },33 .abbrevs = .{ .abbrevs = .{} },
34 };34 };
3535
36 const set_bid: u32 = 1;36 const set_bid_id: u32 = 1;
37 const block_name: u32 = 2;37 const block_name_id: u32 = 2;
38 const set_record_name: u32 = 3;38 const set_record_name_id: u32 = 3;
3939
40 fn deinit(info: *Info, allocator: std.mem.Allocator) void {40 fn deinit(info: *Info, allocator: std.mem.Allocator) void {
41 allocator.free(info.block_name);41 allocator.free(info.block_name);
...@@ -61,7 +61,7 @@ pub const Record = struct {...@@ -61,7 +61,7 @@ pub const Record = struct {
61 assert(record.id == Abbrev.Builtin.define_abbrev.toRecordId());61 assert(record.id == Abbrev.Builtin.define_abbrev.toRecordId());
62 var i: usize = 0;62 var i: usize = 0;
63 while (i < record.operands.len) switch (record.operands[i]) {63 while (i < record.operands.len) switch (record.operands[i]) {
64 Abbrev.Operand.literal => {64 Abbrev.Operand.literal_id => {
65 try operands.append(.{ .literal = record.operands[i + 1] });65 try operands.append(.{ .literal = record.operands[i + 1] });
66 i += 2;66 i += 2;
67 },67 },
...@@ -211,7 +211,7 @@ fn nextRecord(bc: *BitcodeReader) !?Record {...@@ -211,7 +211,7 @@ fn nextRecord(bc: *BitcodeReader) !?Record {
211 .align_32_bits, .block_len => return error.UnsupportedArrayElement,211 .align_32_bits, .block_len => return error.UnsupportedArrayElement,
212 .abbrev_op => switch (try bc.readFixed(u1, 1)) {212 .abbrev_op => switch (try bc.readFixed(u1, 1)) {
213 1 => try operands.appendSlice(&.{213 1 => try operands.appendSlice(&.{
214 Abbrev.Operand.literal,214 Abbrev.Operand.literal_id,
215 try bc.readVbr(u64, 8),215 try bc.readVbr(u64, 8),
216 }),216 }),
217 0 => {217 0 => {
...@@ -334,9 +334,9 @@ fn parseBlockInfoBlock(bc: *BitcodeReader) !void {...@@ -334,9 +334,9 @@ fn parseBlockInfoBlock(bc: *BitcodeReader) !void {
334 try record.toOwnedAbbrev(bc.allocator),334 try record.toOwnedAbbrev(bc.allocator),
335 );335 );
336 },336 },
337 Block.Info.set_bid => block_id = std.math.cast(u32, record.operands[0]) orelse337 Block.Info.set_bid_id => block_id = std.math.cast(u32, record.operands[0]) orelse
338 return error.Overflow,338 return error.Overflow,
339 Block.Info.block_name => if (bc.keep_names) {339 Block.Info.block_name_id => if (bc.keep_names) {
340 const gop = try bc.block_info.getOrPut(bc.allocator, block_id orelse340 const gop = try bc.block_info.getOrPut(bc.allocator, block_id orelse
341 return error.UnspecifiedBlockId);341 return error.UnspecifiedBlockId);
342 if (!gop.found_existing) gop.value_ptr.* = Block.Info.default;342 if (!gop.found_existing) gop.value_ptr.* = Block.Info.default;
...@@ -346,7 +346,7 @@ fn parseBlockInfoBlock(bc: *BitcodeReader) !void {...@@ -346,7 +346,7 @@ fn parseBlockInfoBlock(bc: *BitcodeReader) !void {
346 byte.* = std.math.cast(u8, operand) orelse return error.InvalidName;346 byte.* = std.math.cast(u8, operand) orelse return error.InvalidName;
347 gop.value_ptr.block_name = name;347 gop.value_ptr.block_name = name;
348 },348 },
349 Block.Info.set_record_name => if (bc.keep_names) {349 Block.Info.set_record_name_id => if (bc.keep_names) {
350 const gop = try bc.block_info.getOrPut(bc.allocator, block_id orelse350 const gop = try bc.block_info.getOrPut(bc.allocator, block_id orelse
351 return error.UnspecifiedBlockId);351 return error.UnspecifiedBlockId);
352 if (!gop.found_existing) gop.value_ptr.* = Block.Info.default;352 if (!gop.found_existing) gop.value_ptr.* = Block.Info.default;
...@@ -467,7 +467,7 @@ const Abbrev = struct {...@@ -467,7 +467,7 @@ const Abbrev = struct {
467 block_len,467 block_len,
468 abbrev_op,468 abbrev_op,
469469
470 const literal = std.math.maxInt(u64);470 const literal_id = std.math.maxInt(u64);
471 const Encoding = enum(u3) {471 const Encoding = enum(u3) {
472 fixed = 1,472 fixed = 1,
473 vbr = 2,473 vbr = 2,
src/link/Elf.zig+84-3
...@@ -3467,7 +3467,7 @@ fn updateSectionSizes(self: *Elf) !void {...@@ -3467,7 +3467,7 @@ fn updateSectionSizes(self: *Elf) !void {
3467 if (atom_list.items.len == 0) continue;3467 if (atom_list.items.len == 0) continue;
34683468
3469 // Create jump/branch range extenders if needed.3469 // Create jump/branch range extenders if needed.
3470 try thunks.createThunks(shdr, @intCast(shndx), self);3470 try self.createThunks(shdr, @intCast(shndx));
3471 }3471 }
3472 }3472 }
34733473
...@@ -5576,6 +5576,88 @@ fn defaultEntrySymbolName(cpu_arch: std.Target.Cpu.Arch) []const u8 {...@@ -5576,6 +5576,88 @@ fn defaultEntrySymbolName(cpu_arch: std.Target.Cpu.Arch) []const u8 {
5576 };5576 };
5577}5577}
55785578
5579fn createThunks(elf_file: *Elf, shdr: *elf.Elf64_Shdr, shndx: u32) !void {
5580 const gpa = elf_file.base.comp.gpa;
5581 const cpu_arch = elf_file.getTarget().cpu.arch;
5582 // A branch will need an extender if its target is larger than
5583 // `2^(jump_bits - 1) - margin` where margin is some arbitrary number.
5584 const max_distance = switch (cpu_arch) {
5585 .aarch64 => 0x500_000,
5586 .x86_64, .riscv64 => unreachable,
5587 else => @panic("unhandled arch"),
5588 };
5589 const atoms = elf_file.sections.items(.atom_list)[shndx].items;
5590 assert(atoms.len > 0);
5591
5592 for (atoms) |ref| {
5593 elf_file.atom(ref).?.value = -1;
5594 }
5595
5596 var i: usize = 0;
5597 while (i < atoms.len) {
5598 const start = i;
5599 const start_atom = elf_file.atom(atoms[start]).?;
5600 assert(start_atom.alive);
5601 start_atom.value = try advanceSection(shdr, start_atom.size, start_atom.alignment);
5602 i += 1;
5603
5604 while (i < atoms.len) : (i += 1) {
5605 const atom_ptr = elf_file.atom(atoms[i]).?;
5606 assert(atom_ptr.alive);
5607 if (@as(i64, @intCast(atom_ptr.alignment.forward(shdr.sh_size))) - start_atom.value >= max_distance)
5608 break;
5609 atom_ptr.value = try advanceSection(shdr, atom_ptr.size, atom_ptr.alignment);
5610 }
5611
5612 // Insert a thunk at the group end
5613 const thunk_index = try elf_file.addThunk();
5614 const thunk_ptr = elf_file.thunk(thunk_index);
5615 thunk_ptr.output_section_index = shndx;
5616
5617 // Scan relocs in the group and create trampolines for any unreachable callsite
5618 for (atoms[start..i]) |ref| {
5619 const atom_ptr = elf_file.atom(ref).?;
5620 const file_ptr = atom_ptr.file(elf_file).?;
5621 log.debug("atom({}) {s}", .{ ref, atom_ptr.name(elf_file) });
5622 for (atom_ptr.relocs(elf_file)) |rel| {
5623 const is_reachable = switch (cpu_arch) {
5624 .aarch64 => r: {
5625 const r_type: elf.R_AARCH64 = @enumFromInt(rel.r_type());
5626 if (r_type != .CALL26 and r_type != .JUMP26) break :r true;
5627 const target_ref = file_ptr.resolveSymbol(rel.r_sym(), elf_file);
5628 const target = elf_file.symbol(target_ref).?;
5629 if (target.flags.has_plt) break :r false;
5630 if (atom_ptr.output_section_index != target.output_section_index) break :r false;
5631 const target_atom = target.atom(elf_file).?;
5632 if (target_atom.value == -1) break :r false;
5633 const saddr = atom_ptr.address(elf_file) + @as(i64, @intCast(rel.r_offset));
5634 const taddr = target.address(.{}, elf_file);
5635 _ = math.cast(i28, taddr + rel.r_addend - saddr) orelse break :r false;
5636 break :r true;
5637 },
5638 .x86_64, .riscv64 => unreachable,
5639 else => @panic("unsupported arch"),
5640 };
5641 if (is_reachable) continue;
5642 const target = file_ptr.resolveSymbol(rel.r_sym(), elf_file);
5643 try thunk_ptr.symbols.put(gpa, target, {});
5644 }
5645 atom_ptr.addExtra(.{ .thunk = thunk_index }, elf_file);
5646 }
5647
5648 thunk_ptr.value = try advanceSection(shdr, thunk_ptr.size(elf_file), Atom.Alignment.fromNonzeroByteUnits(2));
5649
5650 log.debug("thunk({d}) : {}", .{ thunk_index, thunk_ptr.fmt(elf_file) });
5651 }
5652}
5653fn advanceSection(shdr: *elf.Elf64_Shdr, adv_size: u64, alignment: Atom.Alignment) !i64 {
5654 const offset = alignment.forward(shdr.sh_size);
5655 const padding = offset - shdr.sh_size;
5656 shdr.sh_size += padding + adv_size;
5657 shdr.sh_addralign = @max(shdr.sh_addralign, alignment.toByteUnits() orelse 1);
5658 return @intCast(offset);
5659}
5660
5579const std = @import("std");5661const std = @import("std");
5580const build_options = @import("build_options");5662const build_options = @import("build_options");
5581const builtin = @import("builtin");5663const builtin = @import("builtin");
...@@ -5598,7 +5680,6 @@ const musl = @import("../musl.zig");...@@ -5598,7 +5680,6 @@ const musl = @import("../musl.zig");
5598const relocatable = @import("Elf/relocatable.zig");5680const relocatable = @import("Elf/relocatable.zig");
5599const relocation = @import("Elf/relocation.zig");5681const relocation = @import("Elf/relocation.zig");
5600const target_util = @import("../target.zig");5682const target_util = @import("../target.zig");
5601const thunks = @import("Elf/thunks.zig");
5602const trace = @import("../tracy.zig").trace;5683const trace = @import("../tracy.zig").trace;
5603const synthetic_sections = @import("Elf/synthetic_sections.zig");5684const synthetic_sections = @import("Elf/synthetic_sections.zig");
56045685
...@@ -5636,7 +5717,7 @@ const PltGotSection = synthetic_sections.PltGotSection;...@@ -5636,7 +5717,7 @@ const PltGotSection = synthetic_sections.PltGotSection;
5636const SharedObject = @import("Elf/SharedObject.zig");5717const SharedObject = @import("Elf/SharedObject.zig");
5637const Symbol = @import("Elf/Symbol.zig");5718const Symbol = @import("Elf/Symbol.zig");
5638const StringTable = @import("StringTable.zig");5719const StringTable = @import("StringTable.zig");
5639const Thunk = thunks.Thunk;5720const Thunk = @import("Elf/Thunk.zig");
5640const Value = @import("../Value.zig");5721const Value = @import("../Value.zig");
5641const VerneedSection = synthetic_sections.VerneedSection;5722const VerneedSection = synthetic_sections.VerneedSection;
5642const ZigObject = @import("Elf/ZigObject.zig");5723const ZigObject = @import("Elf/ZigObject.zig");
src/link/Elf/Atom.zig+1-1
...@@ -2251,6 +2251,6 @@ const Fde = eh_frame.Fde;...@@ -2251,6 +2251,6 @@ const Fde = eh_frame.Fde;
2251const File = @import("file.zig").File;2251const File = @import("file.zig").File;
2252const Object = @import("Object.zig");2252const Object = @import("Object.zig");
2253const Symbol = @import("Symbol.zig");2253const Symbol = @import("Symbol.zig");
2254const Thunk = @import("thunks.zig").Thunk;2254const Thunk = @import("Thunk.zig");
2255const ZigObject = @import("ZigObject.zig");2255const ZigObject = @import("ZigObject.zig");
2256const dev = @import("../../dev.zig");2256const dev = @import("../../dev.zig");
src/link/Elf/Thunk.zig created+144
...@@ -0,0 +1,144 @@
1value: i64 = 0,
2output_section_index: u32 = 0,
3symbols: std.AutoArrayHashMapUnmanaged(Elf.Ref, void) = .{},
4output_symtab_ctx: Elf.SymtabCtx = .{},
5
6pub fn deinit(thunk: *Thunk, allocator: Allocator) void {
7 thunk.symbols.deinit(allocator);
8}
9
10pub fn size(thunk: Thunk, elf_file: *Elf) usize {
11 const cpu_arch = elf_file.getTarget().cpu.arch;
12 return thunk.symbols.keys().len * trampolineSize(cpu_arch);
13}
14
15pub fn address(thunk: Thunk, elf_file: *Elf) i64 {
16 const shdr = elf_file.sections.items(.shdr)[thunk.output_section_index];
17 return @as(i64, @intCast(shdr.sh_addr)) + thunk.value;
18}
19
20pub fn targetAddress(thunk: Thunk, ref: Elf.Ref, elf_file: *Elf) i64 {
21 const cpu_arch = elf_file.getTarget().cpu.arch;
22 return thunk.address(elf_file) + @as(i64, @intCast(thunk.symbols.getIndex(ref).? * trampolineSize(cpu_arch)));
23}
24
25pub fn write(thunk: Thunk, elf_file: *Elf, writer: anytype) !void {
26 switch (elf_file.getTarget().cpu.arch) {
27 .aarch64 => try aarch64.write(thunk, elf_file, writer),
28 .x86_64, .riscv64 => unreachable,
29 else => @panic("unhandled arch"),
30 }
31}
32
33pub fn calcSymtabSize(thunk: *Thunk, elf_file: *Elf) void {
34 thunk.output_symtab_ctx.nlocals = @as(u32, @intCast(thunk.symbols.keys().len));
35 for (thunk.symbols.keys()) |ref| {
36 const sym = elf_file.symbol(ref).?;
37 thunk.output_symtab_ctx.strsize += @as(u32, @intCast(sym.name(elf_file).len + "$thunk".len + 1));
38 }
39}
40
41pub fn writeSymtab(thunk: Thunk, elf_file: *Elf) void {
42 const cpu_arch = elf_file.getTarget().cpu.arch;
43 for (thunk.symbols.keys(), thunk.output_symtab_ctx.ilocal..) |ref, ilocal| {
44 const sym = elf_file.symbol(ref).?;
45 const st_name = @as(u32, @intCast(elf_file.strtab.items.len));
46 elf_file.strtab.appendSliceAssumeCapacity(sym.name(elf_file));
47 elf_file.strtab.appendSliceAssumeCapacity("$thunk");
48 elf_file.strtab.appendAssumeCapacity(0);
49 elf_file.symtab.items[ilocal] = .{
50 .st_name = st_name,
51 .st_info = elf.STT_FUNC,
52 .st_other = 0,
53 .st_shndx = @intCast(thunk.output_section_index),
54 .st_value = @intCast(thunk.targetAddress(ref, elf_file)),
55 .st_size = trampolineSize(cpu_arch),
56 };
57 }
58}
59
60fn trampolineSize(cpu_arch: std.Target.Cpu.Arch) usize {
61 return switch (cpu_arch) {
62 .aarch64 => aarch64.trampoline_size,
63 .x86_64, .riscv64 => unreachable,
64 else => @panic("unhandled arch"),
65 };
66}
67
68pub fn format(
69 thunk: Thunk,
70 comptime unused_fmt_string: []const u8,
71 options: std.fmt.FormatOptions,
72 writer: anytype,
73) !void {
74 _ = thunk;
75 _ = unused_fmt_string;
76 _ = options;
77 _ = writer;
78 @compileError("do not format Thunk directly");
79}
80
81pub fn fmt(thunk: Thunk, elf_file: *Elf) std.fmt.Formatter(format2) {
82 return .{ .data = .{
83 .thunk = thunk,
84 .elf_file = elf_file,
85 } };
86}
87
88const FormatContext = struct {
89 thunk: Thunk,
90 elf_file: *Elf,
91};
92
93fn format2(
94 ctx: FormatContext,
95 comptime unused_fmt_string: []const u8,
96 options: std.fmt.FormatOptions,
97 writer: anytype,
98) !void {
99 _ = options;
100 _ = unused_fmt_string;
101 const thunk = ctx.thunk;
102 const elf_file = ctx.elf_file;
103 try writer.print("@{x} : size({x})\n", .{ thunk.value, thunk.size(elf_file) });
104 for (thunk.symbols.keys()) |ref| {
105 const sym = elf_file.symbol(ref).?;
106 try writer.print(" {} : {s} : @{x}\n", .{ ref, sym.name(elf_file), sym.value });
107 }
108}
109
110pub const Index = u32;
111
112const aarch64 = struct {
113 fn write(thunk: Thunk, elf_file: *Elf, writer: anytype) !void {
114 for (thunk.symbols.keys(), 0..) |ref, i| {
115 const sym = elf_file.symbol(ref).?;
116 const saddr = thunk.address(elf_file) + @as(i64, @intCast(i * trampoline_size));
117 const taddr = sym.address(.{}, elf_file);
118 const pages = try util.calcNumberOfPages(saddr, taddr);
119 try writer.writeInt(u32, Instruction.adrp(.x16, pages).toU32(), .little);
120 const off: u12 = @truncate(@as(u64, @bitCast(taddr)));
121 try writer.writeInt(u32, Instruction.add(.x16, .x16, off, false).toU32(), .little);
122 try writer.writeInt(u32, Instruction.br(.x16).toU32(), .little);
123 }
124 }
125
126 const trampoline_size = 3 * @sizeOf(u32);
127
128 const util = @import("../aarch64.zig");
129 const Instruction = util.Instruction;
130};
131
132const assert = std.debug.assert;
133const elf = std.elf;
134const log = std.log.scoped(.link);
135const math = std.math;
136const mem = std.mem;
137const std = @import("std");
138
139const Allocator = mem.Allocator;
140const Atom = @import("Atom.zig");
141const Elf = @import("../Elf.zig");
142const Symbol = @import("Symbol.zig");
143
144const Thunk = @This();
src/link/Elf/thunks.zig deleted-234
...@@ -1,234 +0,0 @@
1pub fn createThunks(shdr: *elf.Elf64_Shdr, shndx: u32, elf_file: *Elf) !void {
2 const gpa = elf_file.base.comp.gpa;
3 const cpu_arch = elf_file.getTarget().cpu.arch;
4 const max_distance = maxAllowedDistance(cpu_arch);
5 const atoms = elf_file.sections.items(.atom_list)[shndx].items;
6 assert(atoms.len > 0);
7
8 for (atoms) |ref| {
9 elf_file.atom(ref).?.value = -1;
10 }
11
12 var i: usize = 0;
13 while (i < atoms.len) {
14 const start = i;
15 const start_atom = elf_file.atom(atoms[start]).?;
16 assert(start_atom.alive);
17 start_atom.value = try advance(shdr, start_atom.size, start_atom.alignment);
18 i += 1;
19
20 while (i < atoms.len) : (i += 1) {
21 const atom = elf_file.atom(atoms[i]).?;
22 assert(atom.alive);
23 if (@as(i64, @intCast(atom.alignment.forward(shdr.sh_size))) - start_atom.value >= max_distance)
24 break;
25 atom.value = try advance(shdr, atom.size, atom.alignment);
26 }
27
28 // Insert a thunk at the group end
29 const thunk_index = try elf_file.addThunk();
30 const thunk = elf_file.thunk(thunk_index);
31 thunk.output_section_index = shndx;
32
33 // Scan relocs in the group and create trampolines for any unreachable callsite
34 for (atoms[start..i]) |ref| {
35 const atom = elf_file.atom(ref).?;
36 const file = atom.file(elf_file).?;
37 log.debug("atom({}) {s}", .{ ref, atom.name(elf_file) });
38 for (atom.relocs(elf_file)) |rel| {
39 const is_reachable = switch (cpu_arch) {
40 .aarch64 => aarch64.isReachable(atom, rel, elf_file),
41 .x86_64, .riscv64 => unreachable,
42 else => @panic("unsupported arch"),
43 };
44 if (is_reachable) continue;
45 const target = file.resolveSymbol(rel.r_sym(), elf_file);
46 try thunk.symbols.put(gpa, target, {});
47 }
48 atom.addExtra(.{ .thunk = thunk_index }, elf_file);
49 }
50
51 thunk.value = try advance(shdr, thunk.size(elf_file), Atom.Alignment.fromNonzeroByteUnits(2));
52
53 log.debug("thunk({d}) : {}", .{ thunk_index, thunk.fmt(elf_file) });
54 }
55}
56
57fn advance(shdr: *elf.Elf64_Shdr, size: u64, alignment: Atom.Alignment) !i64 {
58 const offset = alignment.forward(shdr.sh_size);
59 const padding = offset - shdr.sh_size;
60 shdr.sh_size += padding + size;
61 shdr.sh_addralign = @max(shdr.sh_addralign, alignment.toByteUnits() orelse 1);
62 return @intCast(offset);
63}
64
65/// A branch will need an extender if its target is larger than
66/// `2^(jump_bits - 1) - margin` where margin is some arbitrary number.
67fn maxAllowedDistance(cpu_arch: std.Target.Cpu.Arch) u32 {
68 return switch (cpu_arch) {
69 .aarch64 => 0x500_000,
70 .x86_64, .riscv64 => unreachable,
71 else => @panic("unhandled arch"),
72 };
73}
74
75pub const Thunk = struct {
76 value: i64 = 0,
77 output_section_index: u32 = 0,
78 symbols: std.AutoArrayHashMapUnmanaged(Elf.Ref, void) = .{},
79 output_symtab_ctx: Elf.SymtabCtx = .{},
80
81 pub fn deinit(thunk: *Thunk, allocator: Allocator) void {
82 thunk.symbols.deinit(allocator);
83 }
84
85 pub fn size(thunk: Thunk, elf_file: *Elf) usize {
86 const cpu_arch = elf_file.getTarget().cpu.arch;
87 return thunk.symbols.keys().len * trampolineSize(cpu_arch);
88 }
89
90 pub fn address(thunk: Thunk, elf_file: *Elf) i64 {
91 const shdr = elf_file.sections.items(.shdr)[thunk.output_section_index];
92 return @as(i64, @intCast(shdr.sh_addr)) + thunk.value;
93 }
94
95 pub fn targetAddress(thunk: Thunk, ref: Elf.Ref, elf_file: *Elf) i64 {
96 const cpu_arch = elf_file.getTarget().cpu.arch;
97 return thunk.address(elf_file) + @as(i64, @intCast(thunk.symbols.getIndex(ref).? * trampolineSize(cpu_arch)));
98 }
99
100 pub fn write(thunk: Thunk, elf_file: *Elf, writer: anytype) !void {
101 switch (elf_file.getTarget().cpu.arch) {
102 .aarch64 => try aarch64.write(thunk, elf_file, writer),
103 .x86_64, .riscv64 => unreachable,
104 else => @panic("unhandled arch"),
105 }
106 }
107
108 pub fn calcSymtabSize(thunk: *Thunk, elf_file: *Elf) void {
109 thunk.output_symtab_ctx.nlocals = @as(u32, @intCast(thunk.symbols.keys().len));
110 for (thunk.symbols.keys()) |ref| {
111 const sym = elf_file.symbol(ref).?;
112 thunk.output_symtab_ctx.strsize += @as(u32, @intCast(sym.name(elf_file).len + "$thunk".len + 1));
113 }
114 }
115
116 pub fn writeSymtab(thunk: Thunk, elf_file: *Elf) void {
117 const cpu_arch = elf_file.getTarget().cpu.arch;
118 for (thunk.symbols.keys(), thunk.output_symtab_ctx.ilocal..) |ref, ilocal| {
119 const sym = elf_file.symbol(ref).?;
120 const st_name = @as(u32, @intCast(elf_file.strtab.items.len));
121 elf_file.strtab.appendSliceAssumeCapacity(sym.name(elf_file));
122 elf_file.strtab.appendSliceAssumeCapacity("$thunk");
123 elf_file.strtab.appendAssumeCapacity(0);
124 elf_file.symtab.items[ilocal] = .{
125 .st_name = st_name,
126 .st_info = elf.STT_FUNC,
127 .st_other = 0,
128 .st_shndx = @intCast(thunk.output_section_index),
129 .st_value = @intCast(thunk.targetAddress(ref, elf_file)),
130 .st_size = trampolineSize(cpu_arch),
131 };
132 }
133 }
134
135 fn trampolineSize(cpu_arch: std.Target.Cpu.Arch) usize {
136 return switch (cpu_arch) {
137 .aarch64 => aarch64.trampoline_size,
138 .x86_64, .riscv64 => unreachable,
139 else => @panic("unhandled arch"),
140 };
141 }
142
143 pub fn format(
144 thunk: Thunk,
145 comptime unused_fmt_string: []const u8,
146 options: std.fmt.FormatOptions,
147 writer: anytype,
148 ) !void {
149 _ = thunk;
150 _ = unused_fmt_string;
151 _ = options;
152 _ = writer;
153 @compileError("do not format Thunk directly");
154 }
155
156 pub fn fmt(thunk: Thunk, elf_file: *Elf) std.fmt.Formatter(format2) {
157 return .{ .data = .{
158 .thunk = thunk,
159 .elf_file = elf_file,
160 } };
161 }
162
163 const FormatContext = struct {
164 thunk: Thunk,
165 elf_file: *Elf,
166 };
167
168 fn format2(
169 ctx: FormatContext,
170 comptime unused_fmt_string: []const u8,
171 options: std.fmt.FormatOptions,
172 writer: anytype,
173 ) !void {
174 _ = options;
175 _ = unused_fmt_string;
176 const thunk = ctx.thunk;
177 const elf_file = ctx.elf_file;
178 try writer.print("@{x} : size({x})\n", .{ thunk.value, thunk.size(elf_file) });
179 for (thunk.symbols.keys()) |ref| {
180 const sym = elf_file.symbol(ref).?;
181 try writer.print(" {} : {s} : @{x}\n", .{ ref, sym.name(elf_file), sym.value });
182 }
183 }
184
185 pub const Index = u32;
186};
187
188const aarch64 = struct {
189 fn isReachable(atom: *const Atom, rel: elf.Elf64_Rela, elf_file: *Elf) bool {
190 const r_type: elf.R_AARCH64 = @enumFromInt(rel.r_type());
191 if (r_type != .CALL26 and r_type != .JUMP26) return true;
192 const file = atom.file(elf_file).?;
193 const target_ref = file.resolveSymbol(rel.r_sym(), elf_file);
194 const target = elf_file.symbol(target_ref).?;
195 if (target.flags.has_plt) return false;
196 if (atom.output_section_index != target.output_section_index) return false;
197 const target_atom = target.atom(elf_file).?;
198 if (target_atom.value == -1) return false;
199 const saddr = atom.address(elf_file) + @as(i64, @intCast(rel.r_offset));
200 const taddr = target.address(.{}, elf_file);
201 _ = math.cast(i28, taddr + rel.r_addend - saddr) orelse return false;
202 return true;
203 }
204
205 fn write(thunk: Thunk, elf_file: *Elf, writer: anytype) !void {
206 for (thunk.symbols.keys(), 0..) |ref, i| {
207 const sym = elf_file.symbol(ref).?;
208 const saddr = thunk.address(elf_file) + @as(i64, @intCast(i * trampoline_size));
209 const taddr = sym.address(.{}, elf_file);
210 const pages = try util.calcNumberOfPages(saddr, taddr);
211 try writer.writeInt(u32, Instruction.adrp(.x16, pages).toU32(), .little);
212 const off: u12 = @truncate(@as(u64, @bitCast(taddr)));
213 try writer.writeInt(u32, Instruction.add(.x16, .x16, off, false).toU32(), .little);
214 try writer.writeInt(u32, Instruction.br(.x16).toU32(), .little);
215 }
216 }
217
218 const trampoline_size = 3 * @sizeOf(u32);
219
220 const util = @import("../aarch64.zig");
221 const Instruction = util.Instruction;
222};
223
224const assert = std.debug.assert;
225const elf = std.elf;
226const log = std.log.scoped(.link);
227const math = std.math;
228const mem = std.mem;
229const std = @import("std");
230
231const Allocator = mem.Allocator;
232const Atom = @import("Atom.zig");
233const Elf = @import("../Elf.zig");
234const Symbol = @import("Symbol.zig");
src/link/MachO.zig+111-19
...@@ -64,10 +64,10 @@ stubs_helper: StubsHelperSection = .{},...@@ -64,10 +64,10 @@ stubs_helper: StubsHelperSection = .{},
64objc_stubs: ObjcStubsSection = .{},64objc_stubs: ObjcStubsSection = .{},
65la_symbol_ptr: LaSymbolPtrSection = .{},65la_symbol_ptr: LaSymbolPtrSection = .{},
66tlv_ptr: TlvPtrSection = .{},66tlv_ptr: TlvPtrSection = .{},
67rebase: Rebase = .{},67rebase_section: Rebase = .{},
68bind: Bind = .{},68bind_section: Bind = .{},
69weak_bind: WeakBind = .{},69weak_bind_section: WeakBind = .{},
70lazy_bind: LazyBind = .{},70lazy_bind_section: LazyBind = .{},
71export_trie: ExportTrie = .{},71export_trie: ExportTrie = .{},
72unwind_info: UnwindInfo = .{},72unwind_info: UnwindInfo = .{},
73data_in_code: DataInCode = .{},73data_in_code: DataInCode = .{},
...@@ -324,10 +324,10 @@ pub fn deinit(self: *MachO) void {...@@ -324,10 +324,10 @@ pub fn deinit(self: *MachO) void {
324 self.stubs.deinit(gpa);324 self.stubs.deinit(gpa);
325 self.objc_stubs.deinit(gpa);325 self.objc_stubs.deinit(gpa);
326 self.tlv_ptr.deinit(gpa);326 self.tlv_ptr.deinit(gpa);
327 self.rebase.deinit(gpa);327 self.rebase_section.deinit(gpa);
328 self.bind.deinit(gpa);328 self.bind_section.deinit(gpa);
329 self.weak_bind.deinit(gpa);329 self.weak_bind_section.deinit(gpa);
330 self.lazy_bind.deinit(gpa);330 self.lazy_bind_section.deinit(gpa);
331 self.export_trie.deinit(gpa);331 self.export_trie.deinit(gpa);
332 self.unwind_info.deinit(gpa);332 self.unwind_info.deinit(gpa);
333 self.data_in_code.deinit(gpa);333 self.data_in_code.deinit(gpa);
...@@ -2005,7 +2005,7 @@ fn calcSectionSizeWorker(self: *MachO, sect_id: u8) void {...@@ -2005,7 +2005,7 @@ fn calcSectionSizeWorker(self: *MachO, sect_id: u8) void {
2005fn createThunksWorker(self: *MachO, sect_id: u8) void {2005fn createThunksWorker(self: *MachO, sect_id: u8) void {
2006 const tracy = trace(@src());2006 const tracy = trace(@src());
2007 defer tracy.end();2007 defer tracy.end();
2008 thunks.createThunks(sect_id, self) catch |err| {2008 self.createThunks(sect_id) catch |err| {
2009 const header = self.sections.items(.header)[sect_id];2009 const header = self.sections.items(.header)[sect_id];
2010 self.reportUnexpectedError("failed to create thunks and calculate size of section '{s},{s}': {s}", .{2010 self.reportUnexpectedError("failed to create thunks and calculate size of section '{s},{s}': {s}", .{
2011 header.segName(),2011 header.segName(),
...@@ -2562,7 +2562,7 @@ fn updateLazyBindSizeWorker(self: *MachO) void {...@@ -2562,7 +2562,7 @@ fn updateLazyBindSizeWorker(self: *MachO) void {
2562 defer tracy.end();2562 defer tracy.end();
2563 const doWork = struct {2563 const doWork = struct {
2564 fn doWork(macho_file: *MachO) !void {2564 fn doWork(macho_file: *MachO) !void {
2565 try macho_file.lazy_bind.updateSize(macho_file);2565 try macho_file.lazy_bind_section.updateSize(macho_file);
2566 const sect_id = macho_file.stubs_helper_sect_index.?;2566 const sect_id = macho_file.stubs_helper_sect_index.?;
2567 const out = &macho_file.sections.items(.out)[sect_id];2567 const out = &macho_file.sections.items(.out)[sect_id];
2568 var stream = std.io.fixedBufferStream(out.items);2568 var stream = std.io.fixedBufferStream(out.items);
...@@ -2585,9 +2585,9 @@ pub fn updateLinkeditSizeWorker(self: *MachO, tag: enum {...@@ -2585,9 +2585,9 @@ pub fn updateLinkeditSizeWorker(self: *MachO, tag: enum {
2585 data_in_code,2585 data_in_code,
2586}) void {2586}) void {
2587 const res = switch (tag) {2587 const res = switch (tag) {
2588 .rebase => self.rebase.updateSize(self),2588 .rebase => self.rebase_section.updateSize(self),
2589 .bind => self.bind.updateSize(self),2589 .bind => self.bind_section.updateSize(self),
2590 .weak_bind => self.weak_bind.updateSize(self),2590 .weak_bind => self.weak_bind_section.updateSize(self),
2591 .export_trie => self.export_trie.updateSize(self),2591 .export_trie => self.export_trie.updateSize(self),
2592 .data_in_code => self.data_in_code.updateSize(self),2592 .data_in_code => self.data_in_code.updateSize(self),
2593 };2593 };
...@@ -2640,13 +2640,13 @@ fn writeDyldInfo(self: *MachO) !void {...@@ -2640,13 +2640,13 @@ fn writeDyldInfo(self: *MachO) !void {
2640 var stream = std.io.fixedBufferStream(buffer);2640 var stream = std.io.fixedBufferStream(buffer);
2641 const writer = stream.writer();2641 const writer = stream.writer();
26422642
2643 try self.rebase.write(writer);2643 try self.rebase_section.write(writer);
2644 try stream.seekTo(cmd.bind_off - base_off);2644 try stream.seekTo(cmd.bind_off - base_off);
2645 try self.bind.write(writer);2645 try self.bind_section.write(writer);
2646 try stream.seekTo(cmd.weak_bind_off - base_off);2646 try stream.seekTo(cmd.weak_bind_off - base_off);
2647 try self.weak_bind.write(writer);2647 try self.weak_bind_section.write(writer);
2648 try stream.seekTo(cmd.lazy_bind_off - base_off);2648 try stream.seekTo(cmd.lazy_bind_off - base_off);
2649 try self.lazy_bind.write(writer);2649 try self.lazy_bind_section.write(writer);
2650 try stream.seekTo(cmd.export_off - base_off);2650 try stream.seekTo(cmd.export_off - base_off);
2651 try self.export_trie.write(writer);2651 try self.export_trie.write(writer);
2652 try self.base.file.?.pwriteAll(buffer, cmd.rebase_off);2652 try self.base.file.?.pwriteAll(buffer, cmd.rebase_off);
...@@ -4602,7 +4602,6 @@ const load_commands = @import("MachO/load_commands.zig");...@@ -4602,7 +4602,6 @@ const load_commands = @import("MachO/load_commands.zig");
4602const relocatable = @import("MachO/relocatable.zig");4602const relocatable = @import("MachO/relocatable.zig");
4603const tapi = @import("tapi.zig");4603const tapi = @import("tapi.zig");
4604const target_util = @import("../target.zig");4604const target_util = @import("../target.zig");
4605const thunks = @import("MachO/thunks.zig");
4606const trace = @import("../tracy.zig").trace;4605const trace = @import("../tracy.zig").trace;
4607const synthetic = @import("MachO/synthetic.zig");4606const synthetic = @import("MachO/synthetic.zig");
46084607
...@@ -4641,7 +4640,7 @@ const StringTable = @import("StringTable.zig");...@@ -4641,7 +4640,7 @@ const StringTable = @import("StringTable.zig");
4641const StubsSection = synthetic.StubsSection;4640const StubsSection = synthetic.StubsSection;
4642const StubsHelperSection = synthetic.StubsHelperSection;4641const StubsHelperSection = synthetic.StubsHelperSection;
4643const Symbol = @import("MachO/Symbol.zig");4642const Symbol = @import("MachO/Symbol.zig");
4644const Thunk = thunks.Thunk;4643const Thunk = @import("MachO/Thunk.zig");
4645const TlvPtrSection = synthetic.TlvPtrSection;4644const TlvPtrSection = synthetic.TlvPtrSection;
4646const Value = @import("../Value.zig");4645const Value = @import("../Value.zig");
4647const UnwindInfo = @import("MachO/UnwindInfo.zig");4646const UnwindInfo = @import("MachO/UnwindInfo.zig");
...@@ -5292,3 +5291,96 @@ pub const KernE = enum(u32) {...@@ -5292,3 +5291,96 @@ pub const KernE = enum(u32) {
5292 NOT_FOUND = 56,5291 NOT_FOUND = 56,
5293 _,5292 _,
5294};5293};
5294
5295fn createThunks(macho_file: *MachO, sect_id: u8) !void {
5296 const tracy = trace(@src());
5297 defer tracy.end();
5298
5299 const gpa = macho_file.base.comp.gpa;
5300 const slice = macho_file.sections.slice();
5301 const header = &slice.items(.header)[sect_id];
5302 const thnks = &slice.items(.thunks)[sect_id];
5303 const atoms = slice.items(.atoms)[sect_id].items;
5304 assert(atoms.len > 0);
5305
5306 for (atoms) |ref| {
5307 ref.getAtom(macho_file).?.value = @bitCast(@as(i64, -1));
5308 }
5309
5310 var i: usize = 0;
5311 while (i < atoms.len) {
5312 const start = i;
5313 const start_atom = atoms[start].getAtom(macho_file).?;
5314 assert(start_atom.isAlive());
5315 start_atom.value = advanceSection(header, start_atom.size, start_atom.alignment);
5316 i += 1;
5317
5318 while (i < atoms.len and
5319 header.size - start_atom.value < max_allowed_distance) : (i += 1)
5320 {
5321 const atom = atoms[i].getAtom(macho_file).?;
5322 assert(atom.isAlive());
5323 atom.value = advanceSection(header, atom.size, atom.alignment);
5324 }
5325
5326 // Insert a thunk at the group end
5327 const thunk_index = try macho_file.addThunk();
5328 const thunk = macho_file.getThunk(thunk_index);
5329 thunk.out_n_sect = sect_id;
5330 try thnks.append(gpa, thunk_index);
5331
5332 // Scan relocs in the group and create trampolines for any unreachable callsite
5333 try scanThunkRelocs(thunk_index, gpa, atoms[start..i], macho_file);
5334 thunk.value = advanceSection(header, thunk.size(), .@"4");
5335
5336 log.debug("thunk({d}) : {}", .{ thunk_index, thunk.fmt(macho_file) });
5337 }
5338}
5339
5340fn advanceSection(sect: *macho.section_64, adv_size: u64, alignment: Atom.Alignment) u64 {
5341 const offset = alignment.forward(sect.size);
5342 const padding = offset - sect.size;
5343 sect.size += padding + adv_size;
5344 sect.@"align" = @max(sect.@"align", alignment.toLog2Units());
5345 return offset;
5346}
5347
5348fn scanThunkRelocs(thunk_index: Thunk.Index, gpa: Allocator, atoms: []const MachO.Ref, macho_file: *MachO) !void {
5349 const tracy = trace(@src());
5350 defer tracy.end();
5351
5352 const thunk = macho_file.getThunk(thunk_index);
5353
5354 for (atoms) |ref| {
5355 const atom = ref.getAtom(macho_file).?;
5356 log.debug("atom({d}) {s}", .{ atom.atom_index, atom.getName(macho_file) });
5357 for (atom.getRelocs(macho_file)) |rel| {
5358 if (rel.type != .branch) continue;
5359 if (isReachable(atom, rel, macho_file)) continue;
5360 try thunk.symbols.put(gpa, rel.getTargetSymbolRef(atom.*, macho_file), {});
5361 }
5362 atom.addExtra(.{ .thunk = thunk_index }, macho_file);
5363 }
5364}
5365
5366fn isReachable(atom: *const Atom, rel: Relocation, macho_file: *MachO) bool {
5367 const target = rel.getTargetSymbol(atom.*, macho_file);
5368 if (target.getSectionFlags().stubs or target.getSectionFlags().objc_stubs) return false;
5369 if (atom.out_n_sect != target.getOutputSectionIndex(macho_file)) return false;
5370 const target_atom = target.getAtom(macho_file).?;
5371 if (target_atom.value == @as(u64, @bitCast(@as(i64, -1)))) return false;
5372 const saddr = @as(i64, @intCast(atom.getAddress(macho_file))) + @as(i64, @intCast(rel.offset - atom.off));
5373 const taddr: i64 = @intCast(rel.getTargetAddress(atom.*, macho_file));
5374 _ = math.cast(i28, taddr + rel.addend - saddr) orelse return false;
5375 return true;
5376}
5377
5378/// Branch instruction has 26 bits immediate but is 4 byte aligned.
5379const jump_bits = @bitSizeOf(i28);
5380const max_distance = (1 << (jump_bits - 1));
5381
5382/// A branch will need an extender if its target is larger than
5383/// `2^(jump_bits - 1) - margin` where margin is some arbitrary number.
5384/// mold uses 5MiB margin, while ld64 uses 4MiB margin. We will follow mold
5385/// and assume margin to be 5MiB.
5386const max_allowed_distance = max_distance - 0x500_000;
src/link/MachO/Atom.zig+1-1
...@@ -1220,6 +1220,6 @@ const MachO = @import("../MachO.zig");...@@ -1220,6 +1220,6 @@ const MachO = @import("../MachO.zig");
1220const Object = @import("Object.zig");1220const Object = @import("Object.zig");
1221const Relocation = @import("Relocation.zig");1221const Relocation = @import("Relocation.zig");
1222const Symbol = @import("Symbol.zig");1222const Symbol = @import("Symbol.zig");
1223const Thunk = @import("thunks.zig").Thunk;1223const Thunk = @import("Thunk.zig");
1224const UnwindInfo = @import("UnwindInfo.zig");1224const UnwindInfo = @import("UnwindInfo.zig");
1225const dev = @import("../../dev.zig");1225const dev = @import("../../dev.zig");
src/link/MachO/Thunk.zig created+125
...@@ -0,0 +1,125 @@
1value: u64 = 0,
2out_n_sect: u8 = 0,
3symbols: std.AutoArrayHashMapUnmanaged(MachO.Ref, void) = .{},
4output_symtab_ctx: MachO.SymtabCtx = .{},
5
6pub fn deinit(thunk: *Thunk, allocator: Allocator) void {
7 thunk.symbols.deinit(allocator);
8}
9
10pub fn size(thunk: Thunk) usize {
11 return thunk.symbols.keys().len * trampoline_size;
12}
13
14pub fn getAddress(thunk: Thunk, macho_file: *MachO) u64 {
15 const header = macho_file.sections.items(.header)[thunk.out_n_sect];
16 return header.addr + thunk.value;
17}
18
19pub fn getTargetAddress(thunk: Thunk, ref: MachO.Ref, macho_file: *MachO) u64 {
20 return thunk.getAddress(macho_file) + thunk.symbols.getIndex(ref).? * trampoline_size;
21}
22
23pub fn write(thunk: Thunk, macho_file: *MachO, writer: anytype) !void {
24 for (thunk.symbols.keys(), 0..) |ref, i| {
25 const sym = ref.getSymbol(macho_file).?;
26 const saddr = thunk.getAddress(macho_file) + i * trampoline_size;
27 const taddr = sym.getAddress(.{}, macho_file);
28 const pages = try aarch64.calcNumberOfPages(@intCast(saddr), @intCast(taddr));
29 try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little);
30 const off: u12 = @truncate(taddr);
31 try writer.writeInt(u32, aarch64.Instruction.add(.x16, .x16, off, false).toU32(), .little);
32 try writer.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little);
33 }
34}
35
36pub fn calcSymtabSize(thunk: *Thunk, macho_file: *MachO) void {
37 thunk.output_symtab_ctx.nlocals = @as(u32, @intCast(thunk.symbols.keys().len));
38 for (thunk.symbols.keys()) |ref| {
39 const sym = ref.getSymbol(macho_file).?;
40 thunk.output_symtab_ctx.strsize += @as(u32, @intCast(sym.getName(macho_file).len + "__thunk".len + 1));
41 }
42}
43
44pub fn writeSymtab(thunk: Thunk, macho_file: *MachO, ctx: anytype) void {
45 var n_strx = thunk.output_symtab_ctx.stroff;
46 for (thunk.symbols.keys(), thunk.output_symtab_ctx.ilocal..) |ref, ilocal| {
47 const sym = ref.getSymbol(macho_file).?;
48 const name = sym.getName(macho_file);
49 const out_sym = &ctx.symtab.items[ilocal];
50 out_sym.n_strx = n_strx;
51 @memcpy(ctx.strtab.items[n_strx..][0..name.len], name);
52 n_strx += @intCast(name.len);
53 @memcpy(ctx.strtab.items[n_strx..][0.."__thunk".len], "__thunk");
54 n_strx += @intCast("__thunk".len);
55 ctx.strtab.items[n_strx] = 0;
56 n_strx += 1;
57 out_sym.n_type = macho.N_SECT;
58 out_sym.n_sect = @intCast(thunk.out_n_sect + 1);
59 out_sym.n_value = @intCast(thunk.getTargetAddress(ref, macho_file));
60 out_sym.n_desc = 0;
61 }
62}
63
64pub fn format(
65 thunk: Thunk,
66 comptime unused_fmt_string: []const u8,
67 options: std.fmt.FormatOptions,
68 writer: anytype,
69) !void {
70 _ = thunk;
71 _ = unused_fmt_string;
72 _ = options;
73 _ = writer;
74 @compileError("do not format Thunk directly");
75}
76
77pub fn fmt(thunk: Thunk, macho_file: *MachO) std.fmt.Formatter(format2) {
78 return .{ .data = .{
79 .thunk = thunk,
80 .macho_file = macho_file,
81 } };
82}
83
84const FormatContext = struct {
85 thunk: Thunk,
86 macho_file: *MachO,
87};
88
89fn format2(
90 ctx: FormatContext,
91 comptime unused_fmt_string: []const u8,
92 options: std.fmt.FormatOptions,
93 writer: anytype,
94) !void {
95 _ = options;
96 _ = unused_fmt_string;
97 const thunk = ctx.thunk;
98 const macho_file = ctx.macho_file;
99 try writer.print("@{x} : size({x})\n", .{ thunk.value, thunk.size() });
100 for (thunk.symbols.keys()) |ref| {
101 const sym = ref.getSymbol(macho_file).?;
102 try writer.print(" {} : {s} : @{x}\n", .{ ref, sym.getName(macho_file), sym.value });
103 }
104}
105
106const trampoline_size = 3 * @sizeOf(u32);
107
108pub const Index = u32;
109
110const aarch64 = @import("../aarch64.zig");
111const assert = std.debug.assert;
112const log = std.log.scoped(.link);
113const macho = std.macho;
114const math = std.math;
115const mem = std.mem;
116const std = @import("std");
117const trace = @import("../../tracy.zig").trace;
118
119const Allocator = mem.Allocator;
120const Atom = @import("Atom.zig");
121const MachO = @import("../MachO.zig");
122const Relocation = @import("Relocation.zig");
123const Symbol = @import("Symbol.zig");
124
125const Thunk = @This();
src/link/MachO/synthetic.zig+1-1
...@@ -204,7 +204,7 @@ pub const StubsHelperSection = struct {...@@ -204,7 +204,7 @@ pub const StubsHelperSection = struct {
204 for (macho_file.stubs.symbols.items) |ref| {204 for (macho_file.stubs.symbols.items) |ref| {
205 const sym = ref.getSymbol(macho_file).?;205 const sym = ref.getSymbol(macho_file).?;
206 if (sym.flags.weak) continue;206 if (sym.flags.weak) continue;
207 const offset = macho_file.lazy_bind.offsets.items[idx];207 const offset = macho_file.lazy_bind_section.offsets.items[idx];
208 const source: i64 = @intCast(sect.addr + preamble_size + entry_size * idx);208 const source: i64 = @intCast(sect.addr + preamble_size + entry_size * idx);
209 const target: i64 = @intCast(sect.addr);209 const target: i64 = @intCast(sect.addr);
210 switch (cpu_arch) {210 switch (cpu_arch) {
src/link/MachO/thunks.zig deleted-218
...@@ -1,218 +0,0 @@
1pub fn createThunks(sect_id: u8, macho_file: *MachO) !void {
2 const tracy = trace(@src());
3 defer tracy.end();
4
5 const gpa = macho_file.base.comp.gpa;
6 const slice = macho_file.sections.slice();
7 const header = &slice.items(.header)[sect_id];
8 const thnks = &slice.items(.thunks)[sect_id];
9 const atoms = slice.items(.atoms)[sect_id].items;
10 assert(atoms.len > 0);
11
12 for (atoms) |ref| {
13 ref.getAtom(macho_file).?.value = @bitCast(@as(i64, -1));
14 }
15
16 var i: usize = 0;
17 while (i < atoms.len) {
18 const start = i;
19 const start_atom = atoms[start].getAtom(macho_file).?;
20 assert(start_atom.isAlive());
21 start_atom.value = advance(header, start_atom.size, start_atom.alignment);
22 i += 1;
23
24 while (i < atoms.len and
25 header.size - start_atom.value < max_allowed_distance) : (i += 1)
26 {
27 const atom = atoms[i].getAtom(macho_file).?;
28 assert(atom.isAlive());
29 atom.value = advance(header, atom.size, atom.alignment);
30 }
31
32 // Insert a thunk at the group end
33 const thunk_index = try macho_file.addThunk();
34 const thunk = macho_file.getThunk(thunk_index);
35 thunk.out_n_sect = sect_id;
36 try thnks.append(gpa, thunk_index);
37
38 // Scan relocs in the group and create trampolines for any unreachable callsite
39 try scanRelocs(thunk_index, gpa, atoms[start..i], macho_file);
40 thunk.value = advance(header, thunk.size(), .@"4");
41
42 log.debug("thunk({d}) : {}", .{ thunk_index, thunk.fmt(macho_file) });
43 }
44}
45
46fn advance(sect: *macho.section_64, size: u64, alignment: Atom.Alignment) u64 {
47 const offset = alignment.forward(sect.size);
48 const padding = offset - sect.size;
49 sect.size += padding + size;
50 sect.@"align" = @max(sect.@"align", alignment.toLog2Units());
51 return offset;
52}
53
54fn scanRelocs(thunk_index: Thunk.Index, gpa: Allocator, atoms: []const MachO.Ref, macho_file: *MachO) !void {
55 const tracy = trace(@src());
56 defer tracy.end();
57
58 const thunk = macho_file.getThunk(thunk_index);
59
60 for (atoms) |ref| {
61 const atom = ref.getAtom(macho_file).?;
62 log.debug("atom({d}) {s}", .{ atom.atom_index, atom.getName(macho_file) });
63 for (atom.getRelocs(macho_file)) |rel| {
64 if (rel.type != .branch) continue;
65 if (isReachable(atom, rel, macho_file)) continue;
66 try thunk.symbols.put(gpa, rel.getTargetSymbolRef(atom.*, macho_file), {});
67 }
68 atom.addExtra(.{ .thunk = thunk_index }, macho_file);
69 }
70}
71
72fn isReachable(atom: *const Atom, rel: Relocation, macho_file: *MachO) bool {
73 const target = rel.getTargetSymbol(atom.*, macho_file);
74 if (target.getSectionFlags().stubs or target.getSectionFlags().objc_stubs) return false;
75 if (atom.out_n_sect != target.getOutputSectionIndex(macho_file)) return false;
76 const target_atom = target.getAtom(macho_file).?;
77 if (target_atom.value == @as(u64, @bitCast(@as(i64, -1)))) return false;
78 const saddr = @as(i64, @intCast(atom.getAddress(macho_file))) + @as(i64, @intCast(rel.offset - atom.off));
79 const taddr: i64 = @intCast(rel.getTargetAddress(atom.*, macho_file));
80 _ = math.cast(i28, taddr + rel.addend - saddr) orelse return false;
81 return true;
82}
83
84pub const Thunk = struct {
85 value: u64 = 0,
86 out_n_sect: u8 = 0,
87 symbols: std.AutoArrayHashMapUnmanaged(MachO.Ref, void) = .{},
88 output_symtab_ctx: MachO.SymtabCtx = .{},
89
90 pub fn deinit(thunk: *Thunk, allocator: Allocator) void {
91 thunk.symbols.deinit(allocator);
92 }
93
94 pub fn size(thunk: Thunk) usize {
95 return thunk.symbols.keys().len * trampoline_size;
96 }
97
98 pub fn getAddress(thunk: Thunk, macho_file: *MachO) u64 {
99 const header = macho_file.sections.items(.header)[thunk.out_n_sect];
100 return header.addr + thunk.value;
101 }
102
103 pub fn getTargetAddress(thunk: Thunk, ref: MachO.Ref, macho_file: *MachO) u64 {
104 return thunk.getAddress(macho_file) + thunk.symbols.getIndex(ref).? * trampoline_size;
105 }
106
107 pub fn write(thunk: Thunk, macho_file: *MachO, writer: anytype) !void {
108 for (thunk.symbols.keys(), 0..) |ref, i| {
109 const sym = ref.getSymbol(macho_file).?;
110 const saddr = thunk.getAddress(macho_file) + i * trampoline_size;
111 const taddr = sym.getAddress(.{}, macho_file);
112 const pages = try aarch64.calcNumberOfPages(@intCast(saddr), @intCast(taddr));
113 try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little);
114 const off: u12 = @truncate(taddr);
115 try writer.writeInt(u32, aarch64.Instruction.add(.x16, .x16, off, false).toU32(), .little);
116 try writer.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little);
117 }
118 }
119
120 pub fn calcSymtabSize(thunk: *Thunk, macho_file: *MachO) void {
121 thunk.output_symtab_ctx.nlocals = @as(u32, @intCast(thunk.symbols.keys().len));
122 for (thunk.symbols.keys()) |ref| {
123 const sym = ref.getSymbol(macho_file).?;
124 thunk.output_symtab_ctx.strsize += @as(u32, @intCast(sym.getName(macho_file).len + "__thunk".len + 1));
125 }
126 }
127
128 pub fn writeSymtab(thunk: Thunk, macho_file: *MachO, ctx: anytype) void {
129 var n_strx = thunk.output_symtab_ctx.stroff;
130 for (thunk.symbols.keys(), thunk.output_symtab_ctx.ilocal..) |ref, ilocal| {
131 const sym = ref.getSymbol(macho_file).?;
132 const name = sym.getName(macho_file);
133 const out_sym = &ctx.symtab.items[ilocal];
134 out_sym.n_strx = n_strx;
135 @memcpy(ctx.strtab.items[n_strx..][0..name.len], name);
136 n_strx += @intCast(name.len);
137 @memcpy(ctx.strtab.items[n_strx..][0.."__thunk".len], "__thunk");
138 n_strx += @intCast("__thunk".len);
139 ctx.strtab.items[n_strx] = 0;
140 n_strx += 1;
141 out_sym.n_type = macho.N_SECT;
142 out_sym.n_sect = @intCast(thunk.out_n_sect + 1);
143 out_sym.n_value = @intCast(thunk.getTargetAddress(ref, macho_file));
144 out_sym.n_desc = 0;
145 }
146 }
147
148 pub fn format(
149 thunk: Thunk,
150 comptime unused_fmt_string: []const u8,
151 options: std.fmt.FormatOptions,
152 writer: anytype,
153 ) !void {
154 _ = thunk;
155 _ = unused_fmt_string;
156 _ = options;
157 _ = writer;
158 @compileError("do not format Thunk directly");
159 }
160
161 pub fn fmt(thunk: Thunk, macho_file: *MachO) std.fmt.Formatter(format2) {
162 return .{ .data = .{
163 .thunk = thunk,
164 .macho_file = macho_file,
165 } };
166 }
167
168 const FormatContext = struct {
169 thunk: Thunk,
170 macho_file: *MachO,
171 };
172
173 fn format2(
174 ctx: FormatContext,
175 comptime unused_fmt_string: []const u8,
176 options: std.fmt.FormatOptions,
177 writer: anytype,
178 ) !void {
179 _ = options;
180 _ = unused_fmt_string;
181 const thunk = ctx.thunk;
182 const macho_file = ctx.macho_file;
183 try writer.print("@{x} : size({x})\n", .{ thunk.value, thunk.size() });
184 for (thunk.symbols.keys()) |ref| {
185 const sym = ref.getSymbol(macho_file).?;
186 try writer.print(" {} : {s} : @{x}\n", .{ ref, sym.getName(macho_file), sym.value });
187 }
188 }
189
190 const trampoline_size = 3 * @sizeOf(u32);
191
192 pub const Index = u32;
193};
194
195/// Branch instruction has 26 bits immediate but is 4 byte aligned.
196const jump_bits = @bitSizeOf(i28);
197const max_distance = (1 << (jump_bits - 1));
198
199/// A branch will need an extender if its target is larger than
200/// `2^(jump_bits - 1) - margin` where margin is some arbitrary number.
201/// mold uses 5MiB margin, while ld64 uses 4MiB margin. We will follow mold
202/// and assume margin to be 5MiB.
203const max_allowed_distance = max_distance - 0x500_000;
204
205const aarch64 = @import("../aarch64.zig");
206const assert = std.debug.assert;
207const log = std.log.scoped(.link);
208const macho = std.macho;
209const math = std.math;
210const mem = std.mem;
211const std = @import("std");
212const trace = @import("../../tracy.zig").trace;
213
214const Allocator = mem.Allocator;
215const Atom = @import("Atom.zig");
216const MachO = @import("../MachO.zig");
217const Relocation = @import("Relocation.zig");
218const Symbol = @import("Symbol.zig");