【发布时间】:2016-09-09 15:43:56
【问题描述】:
我一直在研究 while 循环来遍历所有 CLI 参数。在研究仅打印 1 个元素的解决方案时,我注意到了一些事情;这就是导致我来到这里的思考过程。
我注意到,如果我执行lea 16(%rsp), %someRegisterToWrite,我就能够获取/打印 argv[1]。接下来我尝试了lea 24(%rsp), %someRTW,这让我可以访问 argv[2]。我一直向上看它是否会继续工作,并且确实如此。
我的想法是继续将 8 添加到 %someRTW 并增加一个“计数器”,直到计数器等于 argc。以下代码在输入单个参数时效果很好,但没有打印任何带有 2 个参数的参数,当我输入 3 个参数时,它将打印前 2 个参数,中间没有空格。
.section __DATA,__data
.section __TEXT,__text
.globl _main
_main:
lea (%rsp), %rbx #argc
lea 16(%rsp), %rcx #argv[1]
mov $0x2, %r14 #counter
L1:
mov (%rcx), %rsi #%rsi = user_addr_t cbuf
mov (%rcx), %r10
mov 16(%rcx), %r11
sub %r10, %r11 #Get number of bytes until next arg
mov $0x2000004, %eax #4 = write
mov $1, %edi #edi = file descriptor
mov %r11, %rdx #user_size_t nbyte
syscall
cmp (%rbx), %r14 #if counter < argc
jb L2
jge L3
L2:
inc %r14
mov 8(%rcx), %rcx #mov 24(%rsp) back into %rcx
mov $0x2000004, %eax
mov $0x20, %rsi #0x20 = space
mov $2, %rdx
syscall
jmp L1
L3:
xor %rax, %rax
xor %edi, %edi
mov $0x2000001, %eax
syscall
【问题讨论】:
-
syscallclobbersrcx。 PS:学习使用调试器。 -
还有
%r11,OP 也使用它。 -
@PeterCordes 是但不是跨越
syscall -
除了已经提到的 sys_write 系统调用不直接打印字符,它需要一个指向包含字符的缓冲区的指针。由于这个原因,第二个系统调用中的
mov $0x20, %rsi将不起作用。 RSI 需要是一个 pointer 指向包含空格的缓冲区,我不确定为什么要在执行mov $2, %rdx时使用该系统调用打印 2 个字符. -
您似乎也在尝试使用此
mov 16(%rcx), %r11sub %r10, %r11确定命令行参数的长度。如果它试图获取字符串长度,它将不起作用,因为参数指针可能不在连续的位置。当您检索参数开头的地址时,您应该通过向下扫描字符串查找 NUL(\0) 字符来查找字符串长度。
标签: macos assembly 64-bit x86-64 att