首页 > 解决方案 > 这两条指令在以下函数中做了什么?

问题描述

所以我几乎是 IA32 汇编语言的菜鸟。我尝试将此 C 函数编译为 IA32 程序集(-mpreferred-stack-boundary=2):

__attribute__((cdecl))
int odd_sum(int a[], int n, int sum) {
  if (n == 0) return sum;
  else if ((a[n-1] % 2) == 0)
    return odd_sum(a, n-1, sum);
  else return odd_sum(a, n-1, sum + a[n-1]);
}

和 GCC 输出这个:

    .file   "test.c"
    .text
    .globl  _odd_sum
    .def    _odd_sum;   .scl    2;  .type   32; .endef
_odd_sum:
LFB0:
    .cfi_startproc
    pushl   %ebp
    .cfi_def_cfa_offset 8
    .cfi_offset 5, -8
    movl    %esp, %ebp
    .cfi_def_cfa_register 5
    subl    $12, %esp
    cmpl    $0, 12(%ebp)
    jne L2
    movl    16(%ebp), %eax
    jmp L3
L2:
    movl    12(%ebp), %eax
    addl    $1073741823, %eax
    leal    0(,%eax,4), %edx
    movl    8(%ebp), %eax
    addl    %edx, %eax
    movl    (%eax), %eax
    andl    $1, %eax
    testl   %eax, %eax
    jne L4
    movl    12(%ebp), %eax
    leal    -1(%eax), %edx
    movl    16(%ebp), %eax
    movl    %eax, 8(%esp)
    movl    %edx, 4(%esp)
    movl    8(%ebp), %eax
    movl    %eax, (%esp)
    call    _odd_sum
    jmp L3
L4:
    movl    12(%ebp), %eax
    addl    $1073741823, %eax
    leal    0(,%eax,4), %edx
    movl    8(%ebp), %eax
    addl    %edx, %eax
    movl    (%eax), %edx
    movl    16(%ebp), %eax
    addl    %eax, %edx
    movl    12(%ebp), %eax
    subl    $1, %eax
    movl    %edx, 8(%esp)
    movl    %eax, 4(%esp)
    movl    8(%ebp), %eax
    movl    %eax, (%esp)
    call    _odd_sum
L3:
    leave
    .cfi_restore 5
    .cfi_def_cfa 4, 4
    ret
    .cfi_endproc
LFE0:
    .ident  "GCC: (MinGW.org GCC-8.2.0-3) 8.2.0"

我无法理解的是这两行:

   addl    $1073741823, %eax
   leal    0(,%eax,4), %edx

我知道这两行应该与 . 有关系a[n-1],但我似乎无法理解他们在这个过程中到底做了什么。有人可以帮我解决这个问题吗?

标签: cassemblyx86

解决方案


这只是一种计算数组偏移量的奇特方式a[n-1]

10737418230x3fffffff。例如,如果n是 3,它将添加它们并获取0x40000002. 然后它乘以 4 与第二条指令,结果是0x00000008,丢弃最高位。

所以我们留下了 8 个字节的偏移量,这正是您需要的偏移量(以字节为单位)a[n-1],即a[2](当 an 的大小int为 4 个字节时)。


推荐阅读