* note that rax:rdx are implicitly used as source/destination registers, * so some reg spillage is necessary. * emit: * mov %rax, %r11 * mov %rdx, %r10 * mov % , %rax * either: * mov % , %rdx * OR * mov , %rdx * mul %rdx * mov %r10, %rdx * mov %rax, % * mov %r11, %rax */
| 522 | * mov %r11, %rax |
| 523 | */ |
| 524 | static void |
| 525 | emit_mul(struct bpf_jit_state *st, uint32_t op, uint32_t sreg, uint32_t dreg, |
| 526 | uint32_t imm) |
| 527 | { |
| 528 | const uint8_t ops = 0xF7; |
| 529 | const uint8_t mods = 4; |
| 530 | |
| 531 | /* save rax & rdx */ |
| 532 | emit_mov_reg(st, EBPF_ALU64 | EBPF_MOV | BPF_X, RAX, REG_TMP0); |
| 533 | emit_mov_reg(st, EBPF_ALU64 | EBPF_MOV | BPF_X, RDX, REG_TMP1); |
| 534 | |
| 535 | /* rax = dreg */ |
| 536 | emit_mov_reg(st, EBPF_ALU64 | EBPF_MOV | BPF_X, dreg, RAX); |
| 537 | |
| 538 | if (BPF_SRC(op) == BPF_X) |
| 539 | /* rdx = sreg */ |
| 540 | emit_mov_reg(st, EBPF_ALU64 | EBPF_MOV | BPF_X, |
| 541 | sreg == RAX ? REG_TMP0 : sreg, RDX); |
| 542 | else |
| 543 | /* rdx = imm */ |
| 544 | emit_mov_imm(st, EBPF_ALU64 | EBPF_MOV | BPF_K, RDX, imm); |
| 545 | |
| 546 | emit_rex(st, op, RAX, RDX); |
| 547 | emit_bytes(st, &ops, sizeof(ops)); |
| 548 | emit_modregrm(st, MOD_DIRECT, mods, RDX); |
| 549 | |
| 550 | if (dreg != RDX) |
| 551 | /* restore rdx */ |
| 552 | emit_mov_reg(st, EBPF_ALU64 | EBPF_MOV | BPF_X, REG_TMP1, RDX); |
| 553 | |
| 554 | if (dreg != RAX) { |
| 555 | /* dreg = rax */ |
| 556 | emit_mov_reg(st, EBPF_ALU64 | EBPF_MOV | BPF_X, RAX, dreg); |
| 557 | /* restore rax */ |
| 558 | emit_mov_reg(st, EBPF_ALU64 | EBPF_MOV | BPF_X, REG_TMP0, RAX); |
| 559 | } |
| 560 | } |
| 561 | |
| 562 | /* |
| 563 | * emit mov <ofs>(%<sreg>), %<dreg> |
no test coverage detected