assembly 如何在X86-64汇编中打印命令行参数的数量?

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

我试图打印x86-64汇编程序中存在的命令行参数的数量。
根据我的理解,参数信息存储在堆栈中。
我觉得我错过了一些关于如何从堆栈中检索存储的项的基本知识,但我不知道确切的内容。

.file "args.s"

.globl main
.type main, @function

.section .data
format_string:
  .string "Argument: %s\n"

.section .text
main:
  pushq %rbp
  movq %rsp, %rbp

  popq %rsp                   ; get argc
  movq %rsp, %rdi             ; move argc to rdi, first parameter register
  movq $format_string, %rdi   ; pass in the string to be used and give the parameter
  call printf                 

  leave
  ret
.size main, .-main
mrfwxfqh

mrfwxfqh1#

你有以下问题(至少):
1.该堆栈布局用于初始入口点,而不是main
1.你弹出的是你刚刚压入的rbp,而不是堆栈上已经存在的任何东西。
1.您弹出rsp(堆栈指针),稍后它会咬您:push / pop和call / ret指令使用rsp作为指针。
1.虽然main也获取argc作为参数,但64位调用约定不会在堆栈上传递它。
1.当rdi应该是rsi时,尝试在rdi中传递argc,因为它是printf的第二个参数。因为int是32位,所以可以使用esi

  1. printf试图将argc解释为字符串,因为您在格式字符串中使用了%s而不是%d
    1.对于printf,您不需要将%al置零(这在实践中并不致命,因为它只需要是一个上限,因此在非旧版本的libc中,其中的任何值都应该有效。旧的GCC计算了间接跳跃,因此AL values above 8 could crash
    可选:您的代码不是位置独立的,这在现代系统中是推荐的(有时是必需的)。您可以将格式字符串放入.rodata,因为它是只读的。
    一个固定的版本可能看起来像:
.globl main
main:
  push %rbp                        # rbp not used, for alignment only

  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
 
  pop %rbp
  ret

.section .rodata
format_string: .string "Arguments: %d\n"

相关问题