【问题标题】:Getting command line parameters from an assembly program从汇编程序中获取命令行参数
【发布时间】:2013-08-26 16:06:48
【问题描述】:

通读《专业汇编语言书》;它似乎为读取命令行参数提供了错误的代码。我稍微纠正了一下,现在它从段错误变为读取参数计数,然后是段错误。

这是完整的代码:

.data
    output1:
        .asciz "There are %d params:\n"
    output2:
        .asciz "%s\n"

.text
.globl main
main:
    movl 4(%esp), %ecx  /* Get argument count.  */
    pushl %ecx
    pushl $output1
    call printf
    addl $4, %esp       /* remove output1  */

    /* ECX was corrupted by the printf call,
       pop it off the stack so that we get it's original
       value.  */
    popl %ecx

    /* We don't want to corrupt the stack pointer
       as we move ebp to point to the next command-line
       argument.  */
    movl %esp, %ebp
    /* Remove argument count from EBP.  */
    addl $4, %ebp

pr_arg:
    pushl (%ebp)
    pushl $output2
    call printf
    addl $8, %esp       /* remove output2 and current argument.  */
    addl $4, %ebp       /* Jump to next argument.  */
    loop pr_arg

    /* Done.  */
    pushl $0
    call exit

书中的代码:

.section .data
output1:
    .asciz “There are %d parameters:\n”
output2:
    .asciz “%s\n”
.section .text
.globl _start
_start:
    movl (%esp), %ecx
    pushl %ecx
    pushl $output1
    call printf
    addl $4, %esp
    popl %ecx
    movl %esp, %ebp
    addl $4, %ebp
loop1:
    pushl %ecx
    pushl (%ebp)
    pushl $output2
    call printf
    addl $8, %esp
    popl %ecx
    addl $4, %ebp
    loop loop1
    pushl $0
    call exit

用 GCC (gcc cmd.S) 编译它,也许这就是问题所在? __libc_start_main 以某种方式修改堆栈?不太确定...

更糟糕的是,尝试调试它以查看堆栈,但 GDB 似乎抛出了很多与 printf 相关的东西(其中之一是 printf.c: File not found 或类似的东西)。

【问题讨论】:

  • movl %esp, %ebp / addl $4, %ebp 你不是把ebp指向argc吗?在我看来,如果你想要 argv,你应该加 8。
  • 好吧,4(%esp)4(%ebp) 指向 argc,所以我要删除 argc,因此 (%ebp) 应该指向 argv[0] 对吗?
  • 在我看来,当您到达/* Remove argument count from EBP. */ 点时,您的esp 将指向与您输入main 时相同的位置,因此esp+4 指向argc。因此,要使 ebp 指向 argv,我猜你应该添加 8 而不是 4。
  • 你是对的。我按照你说的做了,但是输出如下:codepad.org/h2VnzD2J
  • 我可能记错了,但您在访问argv 时似乎遗漏了一级间接性。您的代码似乎假定esp+8argv[0]esp+12argv[1] 等。据我回忆,它应该类似于mov eax,[esp+8] ; get argv / mov ebx,[eax] ; get argv[0] / mov ecx,[eax+4] ; get argv[1] 等。

标签: linux assembly x86 gnu-assembler


【解决方案1】:

在@Michael 的帮助下,我能够找到问题所在。

按照@Michael 的建议将 %ebp 用作argv(尽管他使用了%eax)。另一个问题是我需要将 (%ebp) 的值与 0(空终止符)进行比较,然后在该点结束程序。

代码:

    movl 8(%esp), %ebp  /* Get argv.  */

pr_arg:
    cmpl $0, (%ebp)
    je endit

    pushl %ecx
    pushl (%ebp)
    pushl $output2
    call printf
    addl $8, %esp       /* remove output2 and current argument.  */
    addl $4, %ebp

    popl %ecx
    loop pr_arg

    ret

【讨论】:

  • addl $12, %esp 删除两个参数对我来说看起来不对!没关系,因为您使用exit() 退出,但如果您尝试从main: 退出ret,那就很重要了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-05-19
  • 2011-04-10
  • 2014-01-03
  • 1970-01-01
  • 1970-01-01
  • 2013-07-08
  • 2011-02-24
相关资源
最近更新 更多