(后续)如何在X86-64 Assembly中打印出命令行参数?

yc0p9oo0  于 2023-06-23  发布在  其他
关注(0)|答案(1)|浏览(123)

我想在x86-64汇编中打印出命令行参数(使用AT&T语法)。
这是我上一篇关于如何简单地访问这些参数的文章的后续问题。我还想知道如何将所有命令行参数打印到控制台。

.globl main
main:
  push %rbp                        # rbp not used, for alignment only
  mov %rsp, %rbp

  mov %edi, %esi                   # move argc to second parameter register
  lea format_string(%rip), %rdi    # the format string is the first parameter
  xor %eax, %eax                   # 0 xmm registers used
  call printf@plt
  xor %eax, %eax                   # return 0 to behave nicely

  mov 16(%rbp), %rsi               # get argv[1] (pointer to first command line argument)
  mov (%rsi), %rdi                 # load the pointer to the first argument into %rdi
  lea arg_format(%rip), %rsi       # load argument format string
  xor %eax, %eax                   # 0 xmm registers used
  call printf@plt

  pop %rbp
  ret

.section .rodata
format_string: .string "Arguments: %d\n"
arg_format: .string "First Argument: %s\n"
hpcdzsge

hpcdzsge1#

你试图从16(%rbp)得到argv,这是没有意义的。不在堆栈上。它是main的第二个参数,因此在进入函数时它就在%rsi中。
由于%rsi是call-clobbered,我们需要在第一个printf调用中将其保存在调用保留寄存器中。我选择了下面的%rbx%rbp也可以工作)。由于它是调用保留的,我们需要在main函数的开始和结束时保存和恢复它(这也是为了处理堆栈对齐)。
由于%rbx指向argv向量的开始,或者换句话说,它的第零个元素argv[0],我们必须加上8来指向argv[1]。所以mov 8(%rbx), %rsi会帮我们得到它。
此外,您的代码在第二次调用printf时颠倒了参数顺序。
下面是一个适合我的固定版本:

.globl main
main:
        push %rbx                       # %rbx is call preserved
        mov %rsi, %rbx                  # save argv in %rbx
        mov %edi, %esi                  # move argc to second parameter register
        lea format_string(%rip), %rdi   # the format string is the first parameter
        xor %eax, %eax                  # 0 xmm registers used
        call printf@plt

        mov 8(%rbx), %rsi               # argv[1] as second parameter
        lea arg_format(%rip), %rdi      # format string as first parameter
        xor %eax, %eax                  # 0 xmm registers used
        call printf@plt

        xor %eax, %eax                  # NOW this is the return value
        pop %rbx
        ret  

.section .rodata
format_string: .string "Arguments: %d\n"
arg_format: .string "First Argument: %s\n"

如果你想打印所有的参数,那么你需要写一个循环。您可以在每次迭代时向%rbx添加8,以指向argv的下一个元素。将其加载到寄存器中,测试其是否为零(即空指针),否则有条件地跳出循环;否则打印出来。我将把实现留给您作为实践。

相关问题