x86汇编条件语句的实现

Implementation of conditional statement in x86 assembly

我想知道如何将这行代码实现到 x86 masm 程序集中:

    if (x >= 1 && x <= 100) {
        printsomething1();
    } else if (x >= 101 && x <= 200) {
        printsomething2();
    } else {
        printsomething3();
    }

如果你有一个像样的 C 编译器,你可以把它编译成汇编语言。对于 gcc 使用 -S 标志:

gcc test.c -S

这将创建文件 test.s,其中包含可以在需要时进行汇编和链接的汇编语言输出。

比如为了让你的代码编译成功,我稍微改写成这样:

#include <stdio.h>
#include <stdlib.h>

void printsomething (int y)
{
    printf ("something %d", y);
}

void func (int x)
{
    if (x >= 1 && x <= 100)
        printsomething(1);
    else
    if (x >= 101  && x <= 200)
        printsomething(2);
    else
        printsomething(3);
}

int main (int argc, char **argv)
{
    int x = 0;
    if (argc > 1)
        x = atoi (argv [1]);
    return 0;
}

它编译成这个汇编器:

    .file   "s.c"
    .text
    .section    .rodata
.LC0:
    .string "something %d"
    .text
    .globl  printsomething
    .type   printsomething, @function
printsomething:
.LFB5:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    subq    , %rsp
    movl    %edi, -4(%rbp)
    movl    -4(%rbp), %eax
    movl    %eax, %esi
    movl    $.LC0, %edi
    movl    [=12=], %eax
    call    printf
    nop
    leave
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE5:
    .size   printsomething, .-printsomething
    .globl  func
    .type   func, @function
func:
.LFB6:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    subq    , %rsp
    movl    %edi, -4(%rbp)
    cmpl    [=12=], -4(%rbp)
    jle .L3
    cmpl    0, -4(%rbp)
    jg  .L3
    movl    , %edi
    call    printsomething
    jmp .L4
.L3:
    cmpl    0, -4(%rbp)
    jle .L5
    cmpl    0, -4(%rbp)
    jg  .L5
    movl    , %edi
    call    printsomething
    jmp .L4
.L5:
    movl    , %edi
    call    printsomething
.L4:
    nop
    leave
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE6:
    .size   func, .-func
    .globl  main
    .type   main, @function
main:
.LFB7:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    subq    , %rsp
    movl    %edi, -20(%rbp)
    movq    %rsi, -32(%rbp)
    movl    [=12=], -4(%rbp)
    cmpl    , -20(%rbp)
    jle .L7
    movq    -32(%rbp), %rax
    addq    , %rax
    movq    (%rax), %rax
    movq    %rax, %rdi
    call    atoi
    movl    %eax, -4(%rbp)
.L7:
    movl    [=12=], %eax
    leave
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE7:
    .size   main, .-main
    .ident  "GCC: (GNU) 7.3.1 20180712 (Red Hat 7.3.1-6)"
    .section    .note.GNU-stack,"",@progbits

检查它的 func: 部分,您将看到它如何设置与 1、100、101 等的比较

我会把它分成连续的范围,(假设 x 是无符号的)像:

  • x 为 0,执行 printsomething3()
  • x 是 1 到 100,什么也不做 printsomething1()
  • x 是 101 到 200,什么也不做 printsomething2()
  • x 为 201 或更高,什么也不做 printsomething3()

然后从最低到最高工作,例如:

    ;eax = x;

    cmp eax,0
    je .printsomething3
    cmp eax,100
    jbe .printsomething1
    cmp eax,200
    jbe .printsomething2
    jmp .printsomething3

如果唯一的区别是他们打印的字符串(而不是他们用来打印它的代码)我会更进一步:

    mov esi,something3     ;esi = address of string if x is 0
    cmp eax,0
    je .print
    mov esi,something1     ;esi = address of string if x is 1 to 100
    cmp eax,100
    jbe .print
    mov esi,something2     ;esi = address of string if x is 101 to 200
    cmp eax,200
    jbe .print
    mov esi,something3     ;esi = address of string if x is 201 or higher
    jmp .print