代码之家  ›  专栏  ›  技术社区  ›  iProgram

寄存器如何作为程序集中的参数工作?

  •  1
  • iProgram  · 技术社区  · 7 年前

    我试图理解汇编如何处理参数和返回值。

    到目前为止,我了解到%eax是返回值,要加载单个参数,我需要加载 %rip + offset %rid 通过使用 leaq var(%rip), %rdi .

    为了进一步了解参数,我创建了一个c程序,它接收10个参数(11个参数包括格式化字符串),以尝试找出寄存器的顺序。然后我在Mac上使用gcc将C代码转换成汇编代码。

    以下是我使用的C代码:

    #include <stdio.h>
    
    int main(){
      printf("%s %s %s %s %s %s %s %s %s %s", "1 ", "2", "3", "4", "5", "6", "7", "8", "9", "10");
      return 0;
    }
    

    .section  __TEXT,__text,regular,pure_instructions
      .macosx_version_min 10, 13
      .globl  _main                   ## -- Begin function main
      .p2align  4, 0x90
    _main:                                  ## @main
      .cfi_startproc
    ## %bb.0:
      pushq %rbp
      .cfi_def_cfa_offset 16
      .cfi_offset %rbp, -16
      movq  %rsp, %rbp
      .cfi_def_cfa_register %rbp
      pushq %r15
      pushq %r14
      pushq %rbx
      pushq %rax
      .cfi_offset %rbx, -40
      .cfi_offset %r14, -32
      .cfi_offset %r15, -24
      subq  $8, %rsp
      leaq  L_.str.10(%rip), %r10
      leaq  L_.str.9(%rip), %r11
      leaq  L_.str.8(%rip), %r14
      leaq  L_.str.7(%rip), %r15
      leaq  L_.str.6(%rip), %rbx
      leaq  L_.str(%rip), %rdi
      leaq  L_.str.1(%rip), %rsi
      leaq  L_.str.2(%rip), %rdx
      leaq  L_.str.3(%rip), %rcx
      leaq  L_.str.4(%rip), %r8
      leaq  L_.str.5(%rip), %r9
      movl  $0, %eax
      pushq %r10
      pushq %r11
      pushq %r14
      pushq %r15
      pushq %rbx
      callq _printf
      addq  $48, %rsp
      xorl  %eax, %eax
      addq  $8, %rsp
      popq  %rbx
      popq  %r14
      popq  %r15
      popq  %rbp
      retq
      .cfi_endproc
                                            ## -- End function
      .section  __TEXT,__cstring,cstring_literals
    L_.str:                                 ## @.str
      .asciz  "%s %s %s %s %s %s %s %s %s %s"
    
    L_.str.1:                               ## @.str.1
      .asciz  "1 "
    
    L_.str.2:                               ## @.str.2
      .asciz  "2"
    
    L_.str.3:                               ## @.str.3
      .asciz  "3"
    
    L_.str.4:                               ## @.str.4
      .asciz  "4"
    
    L_.str.5:                               ## @.str.5
      .asciz  "5"
    
    L_.str.6:                               ## @.str.6
      .asciz  "6"
    
    L_.str.7:                               ## @.str.7
      .asciz  "7"
    
    
    L_.str.8:                               ## @.str.8
      .asciz  "8"
    
    L_.str.9:                               ## @.str.9
      .asciz  "9"
    
    L_.str.10:                              ## @.str.10
      .asciz  "10"
    
    
    .subsections_via_symbols
    

    .text
      .globl  _main                   ## -- Begin function main
    _main:                                  ## @main
      pushq %rbp
      movq  %rsp, %rbp
      pushq %r15
      pushq %r14
      pushq %rbx
      pushq %rax
      subq  $8, %rsp
      leaq  L_.str.10(%rip), %r10
      leaq  L_.str.9(%rip), %r11
      leaq  L_.str.8(%rip), %r14
      leaq  L_.str.7(%rip), %r15
      leaq  L_.str.6(%rip), %rbx
      leaq  L_.str(%rip), %rdi
      leaq  L_.str.1(%rip), %rsi
      leaq  L_.str.2(%rip), %rdx
      leaq  L_.str.3(%rip), %rcx
      leaq  L_.str.4(%rip), %r8
      leaq  L_.str.5(%rip), %r9
      movl  $0, %eax
      pushq %r10
      pushq %r11
      pushq %r14
      pushq %r15
      pushq %rbx
      callq _printf
      addq  $48, %rsp
      xorl  %eax, %eax
      addq  $8, %rsp
      popq  %rbx
      popq  %r14
      popq  %r15
      popq  %rbp
      retq
    
    .data
    L_.str:                                 ## @.str
      .asciz  "%s %s %s %s %s %s %s %s %s %s"
    
    L_.str.1:                               ## @.str.1
      .asciz  "1 "
    
    L_.str.2:                               ## @.str.2
      .asciz  "2"
    
    L_.str.3:                               ## @.str.3
      .asciz  "3"
    
    L_.str.4:                               ## @.str.4
      .asciz  "4"
    
    L_.str.5:                               ## @.str.5
      .asciz  "5"
    
    L_.str.6:                               ## @.str.6
      .asciz  "6"
    
    L_.str.7:                               ## @.str.7
      .asciz  "7"
    
    L_.str.8:                               ## @.str.8
      .asciz  "8"
    
    L_.str.9:                               ## @.str.9
      .asciz  "9"
    
    L_.str.10:                              ## @.str.10
      .asciz  "10"
    

    我知道在代码的开头,基指针被推到堆栈上,然后被复制到堆栈指针中供以后使用。

    然后leaq将每个字符串加载到每个寄存器中,这些寄存器将用作printf的参数。

    我想知道的是为什么寄存器 r10 r11 r14 r15 在第一个参数加载到内存和寄存器之前 rsi rdx rcx r8 在第一个参数之后把r9加载到内存中?还有为什么你 代替 r12 r13 ?

    1 回复  |  直到 7 年前
        1
  •  2
  •   user3344003    7 年前

    首先,看起来您正在使用未优化的代码,因此发生了不需要优化的事情。

    rdi = format string
    rsi = 1
    rdx = 2
    rcx = 3
    r8 = 4
    r9 = 5
    

    这会让你对电话会议有所了解。前六个参数通过寄存器。剩下的参数在堆栈上传递。

    这只是编译器选择的顺序。

    为什么用r14和r15代替r12和r13?

    在这种情况下,为什么从堆栈指针中加8和减8,寄存器的推送和弹出顺序是否重要?

    它可能只是编译器生成的一些锅炉板函数代码。