| ... | ... | @@ -184,9 +184,6 @@ const Function = struct { |
| 184 | 184 | if (arch != .x86_64 and arch != .i386) { |
| 185 | 185 | return self.fail(inst.base.src, "TODO implement inline asm support for more architectures", .{}); |
| 186 | 186 | } |
| 187 | | if (!mem.eql(u8, inst.args.asm_source, "syscall")) { |
| 188 | | return self.fail(inst.base.src, "TODO implement support for more x86 assembly instructions", .{}); |
| 189 | | } |
| 190 | 187 | for (inst.args.inputs) |input, i| { |
| 191 | 188 | if (input.len < 3 or input[0] != '{' or input[input.len - 1] != '}') { |
| 192 | 189 | return self.fail(inst.base.src, "unrecognized asm input constraint: '{}'", .{input}); |
| ... | ... | @@ -198,6 +195,12 @@ const Function = struct { |
| 198 | 195 | try self.genSetReg(inst.base.src, arch, reg, arg); |
| 199 | 196 | } |
| 200 | 197 | |
| 198 | if (mem.eql(u8, inst.args.asm_source, "syscall")) { |
| 199 | try self.code.appendSlice(&[_]u8{ 0x0f, 0x05 }); |
| 200 | } else { |
| 201 | return self.fail(inst.base.src, "TODO implement support for more x86 assembly instructions", .{}); |
| 202 | } |
| 203 | |
| 201 | 204 | if (inst.args.output) |output| { |
| 202 | 205 | if (output.len < 4 or output[0] != '=' or output[1] != '{' or output[output.len - 1] != '}') { |
| 203 | 206 | return self.fail(inst.base.src, "unrecognized asm output constraint: '{}'", .{output}); |
| ... | ... | @@ -214,10 +217,80 @@ const Function = struct { |
| 214 | 217 | fn genSetReg(self: *Function, src: usize, comptime arch: Target.Cpu.Arch, reg: Reg(arch), mcv: MCValue) !void { |
| 215 | 218 | switch (arch) { |
| 216 | 219 | .x86_64 => switch (reg) { |
| 217 | | .rax => return self.fail(src, "TODO implement genSetReg for x86_64 'rax'", .{}), |
| 218 | | .rdi => return self.fail(src, "TODO implement genSetReg for x86_64 'rdi'", .{}), |
| 219 | | .rsi => return self.fail(src, "TODO implement genSetReg for x86_64 'rsi'", .{}), |
| 220 | | .rdx => return self.fail(src, "TODO implement genSetReg for x86_64 'rdx'", .{}), |
| 220 | .rax => switch (mcv) { |
| 221 | .none, .unreach => unreachable, |
| 222 | .immediate => |x| { |
| 223 | // Setting the eax register zeroes the upper part of rax, so if the number is small |
| 224 | // enough, that is preferable. |
| 225 | // Best case: zero |
| 226 | // 31 c0 xor eax,eax |
| 227 | if (x == 0) { |
| 228 | return self.code.appendSlice(&[_]u8{ 0x31, 0xc0 }); |
| 229 | } |
| 230 | // Next best case: set eax with 4 bytes |
| 231 | // b8 04 03 02 01 mov eax,0x01020304 |
| 232 | if (x <= std.math.maxInt(u32)) { |
| 233 | try self.code.resize(self.code.items.len + 5); |
| 234 | self.code.items[self.code.items.len - 5] = 0xb8; |
| 235 | const imm_ptr = self.code.items[self.code.items.len - 4 ..][0..4]; |
| 236 | mem.writeIntLittle(u32, imm_ptr, @intCast(u32, x)); |
| 237 | return; |
| 238 | } |
| 239 | // Worst case: set rax with 8 bytes |
| 240 | // 48 b8 08 07 06 05 04 03 02 01 movabs rax,0x0102030405060708 |
| 241 | try self.code.resize(self.code.items.len + 10); |
| 242 | self.code.items[self.code.items.len - 10] = 0x48; |
| 243 | self.code.items[self.code.items.len - 9] = 0xb8; |
| 244 | const imm_ptr = self.code.items[self.code.items.len - 8 ..][0..8]; |
| 245 | mem.writeIntLittle(u64, imm_ptr, x); |
| 246 | return; |
| 247 | }, |
| 248 | .embedded_in_code => return self.fail(src, "TODO implement x86_64 genSetReg %rax = embedded_in_code", .{}), |
| 249 | .register => return self.fail(src, "TODO implement x86_64 genSetReg %rax = register", .{}), |
| 250 | }, |
| 251 | .rdi => switch (mcv) { |
| 252 | .none, .unreach => unreachable, |
| 253 | .immediate => |x| { |
| 254 | // Setting the edi register zeroes the upper part of rdi, so if the number is small |
| 255 | // enough, that is preferable. |
| 256 | // Best case: zero |
| 257 | // 31 ff xor edi,edi |
| 258 | if (x == 0) { |
| 259 | return self.code.appendSlice(&[_]u8{ 0x31, 0xff }); |
| 260 | } |
| 261 | // Next best case: set edi with 4 bytes |
| 262 | // bf 04 03 02 01 mov edi,0x1020304 |
| 263 | if (x <= std.math.maxInt(u32)) { |
| 264 | try self.code.resize(self.code.items.len + 5); |
| 265 | self.code.items[self.code.items.len - 5] = 0xbf; |
| 266 | const imm_ptr = self.code.items[self.code.items.len - 4 ..][0..4]; |
| 267 | mem.writeIntLittle(u32, imm_ptr, @intCast(u32, x)); |
| 268 | return; |
| 269 | } |
| 270 | // Worst case: set rdi with 8 bytes |
| 271 | // 48 bf 08 07 06 05 04 03 02 01 movabs rax,0x0102030405060708 |
| 272 | try self.code.resize(self.code.items.len + 10); |
| 273 | self.code.items[self.code.items.len - 10] = 0x48; |
| 274 | self.code.items[self.code.items.len - 9] = 0xbf; |
| 275 | const imm_ptr = self.code.items[self.code.items.len - 8 ..][0..8]; |
| 276 | mem.writeIntLittle(u64, imm_ptr, x); |
| 277 | return; |
| 278 | }, |
| 279 | .embedded_in_code => return self.fail(src, "TODO implement x86_64 genSetReg %rdi = embedded_in_code", .{}), |
| 280 | .register => return self.fail(src, "TODO implement x86_64 genSetReg %rdi = register", .{}), |
| 281 | }, |
| 282 | .rsi => switch (mcv) { |
| 283 | .none, .unreach => unreachable, |
| 284 | .immediate => return self.fail(src, "TODO implement x86_64 genSetReg %rsi = immediate", .{}), |
| 285 | .embedded_in_code => return self.fail(src, "TODO implement x86_64 genSetReg %rsi = embedded_in_code", .{}), |
| 286 | .register => return self.fail(src, "TODO implement x86_64 genSetReg %rsi = register", .{}), |
| 287 | }, |
| 288 | .rdx => switch (mcv) { |
| 289 | .none, .unreach => unreachable, |
| 290 | .immediate => return self.fail(src, "TODO implement x86_64 genSetReg %rdx = immediate", .{}), |
| 291 | .embedded_in_code => return self.fail(src, "TODO implement x86_64 genSetReg %rdx = embedded_in_code", .{}), |
| 292 | .register => return self.fail(src, "TODO implement x86_64 genSetReg %rdx = register", .{}), |
| 293 | }, |
| 221 | 294 | else => return self.fail(src, "TODO implement genSetReg for x86_64 '{}'", .{@tagName(reg)}), |
| 222 | 295 | }, |
| 223 | 296 | else => return self.fail(src, "TODO implement genSetReg for more architectures", .{}), |