我最近决定让x86-64程序集一试。我在显示argv
时遇到了问题是的,我写的代码很糟糕,它做出了假设,并且没有检查错误,我知道,但我真的不认为这是造成这种情况的原因问题
这是我的计划归结为其核心。
.globl _start
.text
main:
_start:
movl $10,%edx # No. of chars to write
movq 16(%rsp),%rcx # argv[1]
movl $1,%ebx # stdout
movl $4,%eax # write
int $0x80
movl $0,%ebx
movl $1,%eax
int $0x80
我运行我的程序./myprog helloworldddddddddd
所以argv [0] =。/ myprog 和argv [1] = helloworlddddddddddd或我输入的任何内容
我的程序应该将argv [1]中的前十个字符写入stdout。
除非它不起作用。写入返回-14,这是错误EFAULT?这意味着不好的地址。
所以我写了这个
.globl _start
.text
main:
_start:
movq 16(%rsp),%rax
movq $bob,%rbx
subq %rcx,%rcx
.Lloop:
movb (%rax,%rcx),%dl
movb %dl,(%rbx,%rcx)
cmpb $0,%dl
je .Ldone
addq $1,%rcx
jmp .Lloop
.Ldone: movl $10,%edx
movq $bob,%rcx
movl $1,%ebx
movl $4,%eax
int $0x80
movl $0,%ebx
movl $1,%eax
int $0x80
.comm bob,50
它将argv [1]复制到我称为bob的内存区域,然后尝试将此副本写入stdout。我确定它是非常糟糕的x86,但它确实有效。如果我编译并运行程序,它会输出argv [1]
中的所有内容最后我在C
中写了这个#include <unistd.h>
int main(int argc, char **argv) {
write(1,argv[1],10);
return 0;
}
这更像是我的第一个程序,而不是我的第二个程序,但也有效。在这个阶段,我完全感到困惑。
所以在我看来,&#34;写&#34;系统调用不允许读取我的程序的argv数组,但它可以读取副本。哦,如果我用C语言写它,它就可以了。这看起来很奇怪。谁能告诉我发生了什么,为什么?
编辑:
有人指出我使用混合的32位和64位代码。所以我改为100%64位。
第一个程序:
.globl _start
.text
main:
_start:
movl $10,%edx # No. of chars to write
movl 16(%rsp),%esi # argv[1]
movl $1,%edi # stdout
movl $1,%eax # write
syscall
movl $0,%edi
movl $60,%eax
syscall
第二个程序:
.globl _start
.text
main:
_start:
movq 16(%rsp),%rax
movq $bob,%rbx
subq %rcx,%rcx
.Lloop:
movb (%rax,%rcx),%dl
movb %dl,(%rbx,%rcx)
cmpb $0,%dl
je .Ldone
addq $1,%rcx
jmp .Lloop
.Ldone: movl $10,%edx # No. of chars to write
movq $bob,%rsi # buffer
movl $1,%edi # stdout
movl $1,%eax # write
syscall
movl $0,%edi # return 0
movl $60,%eax # exit
syscall
.comm bob,50
仍然是同样的错误,第一个程序仍然无法工作,即使它现在是64位,第二个程序仍然有效,即使它现在也是64位
第一个程序的64位版本的Strace。 (那个不起作用的人):
execve("./Myprog", ["./Myprog", "bananablahblah"], [/* 46 vars */]) = 0
write(1, 0x1491f543, 10) = -1 EFAULT (Bad address)
_exit(0) = ?
+++ exited with 0 +++
答案 0 :(得分:2)
你在这里犯了三个主要错误:
您将main
与_start
混淆。它们不是同义词 - _start
的标准C库实现在调用main
之前进行了一些重要的初始化。您可能不想尝试重新实现_start
- 不要在您的可执行文件中定义它;链接libc以获取它。
您正在尝试在64位可执行文件中使用32位系统调用(int $0x80
)。这不能正常工作;特别是,它无法读取存在于4GB边界之上的内存,包括在你的堆栈上!您必须使用syscall
指令进行64位系统调用。但请记住,它使用稍微不同的调用约定,并使用不同的电话号码!
您在需要64位等效位置的某些位置使用32位指令和寄存器。这有时适用于低指针和值,但会截断其他一些值。除非你特别需要更小的东西(例如,char
的8位寄存器),否则习惯总是使用64位指令和64位代码寄存器。