arm汇编语言访问ARGV

Access ARGV in arm assembly language

我正在做一个应该相当简单的练习来打印传递给程序的参数数量,然后将第一个参数打印为字符串。我得到了参数的数量,但打印似乎只是给出了随机的内存位置。我运行程序是这样的:

argdisplay ab ac ad

它正确地打印了参数的数量,但不是参数字符串。

Argc: 4
Argc: �

我的程序是:

.data
stringD:     .asciz "Argc: %d\n"
stringS:     .asciz "Argc: %s\n"    

.text
.global main

main:
no_args:    
    push {ip, lr}
    mov r1, r0
    ldr r0, =stringD
    bl printf
arg_string: 
    ldr r1, [sp, #8]
    ldr r0, =stringS
    bl printf
    pop {ip, pc}

.global printf
.end

我对 argv 的理解是它是一个由四个字节分隔的数组,所以我输入 #8 来尝试打印第二个参数。

argv 参数未在堆栈上传递。它是 main 函数的第二个参数,所以它在 r1 中进入 main。所以:

  • 您需要在覆盖 r1 以调用 printf

    之前保存它(或指向所需字符串的指针)
  • 你需要将其保存在调用保留寄存器(r4-r8, r10)(或堆栈上,但不太方便)

  • 您需要在函数的开始和结束时保存和恢复该寄存器

这是一个固定版本。由于 r1 中的 argv 是指向 argv 数组中第 0 个指针的指针,因此 4 个字节后将是指向第一个参数 argv[1] 的指针,即您想要的打印。我们在第一次调用 print 时将其保存在 r4 中,并将 r4 添加到要压入和弹出的寄存器列表中。

main:
    push {r4, ip, lr}
    ldr r4, [r1, #4]

    mov r1, r0
    ldr r0, =stringD
    bl printf

    mov r1, r4
    ldr r0, =stringS
    bl printf

    mov r0, #0      // return 0
    pop {r4, ip, pc}

一些其他注意事项:

  • 我们在退出时将 r0 清零,这样我们的 main 函数 returns 0 表示成功。返回一个随机值对于想要测试退出代码的用户来说很烦人。

  • 您可能不想将两个输出都标记为 Argc

  • 最后的
  • .global printf应该是.extern printf。您没有在这个模块中定义 printf ,而是告诉汇编程序它将在另一个模块中找到。此外,将此指令 放在 printf 的调用之前(可能在文件顶部)也更有意义。

  • 标签 no_argsarg_string 没有在任何地方用作分支目标,因此它们没有任何效果,也可能是注释(在这种情况下它们可能是更具描述性)。

  • .end 是不必要的,除非您要在它后面添加您希望汇编程序忽略的其他内容。如果您在文件末尾添加了更多实际代码,然后想知道为什么汇编器不汇编它,则更有可能令人烦恼。

  • 由于您不打算写入stringDstringS,因此将它们放在只读数据部分。将 .data 替换为 .section .rodata.

  • 没有传递参数的情况下优雅地处理会很好。目前它有点工作,因为如果不存在参数则 argv[1] 为空,并且 Linux 上的 printf 接受带有 %s 的空指针并打印字符串 (null).但你可以考虑更好的选择。