我正在使用elf64编译并尝试获取参数并将其写入控制台 .
我将函数称为./test wooop
在单步执行gdb之后似乎没有问题,一切都设置好了:
rax:0x4 rbx:0x1 rcx:指向字符串,x / 6cb $ rcx给出'w''o''o''o''p'0x0 rdx:0x5 <---正确确定长度
在int 80h之后,rax包含-14并且没有任何内容打印到控制台 . 如果我在.data中定义一个字符串,它就可以了 . gdb以相同的方式显示$ rcx的值 .
有任何想法吗?这是我的完整资料来源
%define LF 0Ah
%define stdout 1
%define sys_exit 1
%define sys_write 4
global _start
section .data
usagemsg: db "test {string}",LF,0
testmsg: db "wooop",0
section .text
_start:
pop rcx ;this is argc
cmp rcx, 2 ;one argument
jne usage
pop rcx
pop rcx ; argument now in rcx
test rcx,rcx
jz usage
;mov rcx, testmsg ;<-----uncomment this to print ok!
call print
jmp exit
usage:
mov rcx, usagemsg
call print
jmp exit
calclen:
push rdi
mov rdi, rcx
push rcx
xor rcx,rcx
not rcx
xor al,al
cld
repne scasb
not rcx
lea rdx, [rcx-1]
pop rcx
pop rdi
ret
print:
push rax
push rbx
push rdx
call calclen
mov rax, sys_write
mov rbx, stdout
int 80h
pop rdx
pop rbx
pop rax
ret
exit:
mov rax, sys_exit
mov rbx, 0
int 80h
谢谢
编辑:改变我如何使我的系统调用如下,它工作正常 . 感谢你的帮助!
sys_write现在是1
sys_exit现在是60
stdout现在进入rdi,而不是rbx
要写入的字符串现在在rsi中设置,而不是rcx
int 80h被syscall取代
2 回答
我还在运行32位硬件,所以这是一个疯狂的猜测!您可能知道,64位系统调用号完全不同,使用“syscall”而不是int 80h . 但是,仍然可以使用int 80h和32位系统调用号,64位寄存器被截断为32位 . 您的测试表明这适用于.data中的地址,但是使用“堆栈地址”,它返回-14(-EFAULT - 错误地址) . 我唯一能想到的是将rcx截断为ecx会导致“坏地址”(如果它在堆栈中) . 我不知道堆栈在64位代码中的位置 . 这有意义吗?
我尝试使用“正确的”64位系统调用号码和寄存器以及“系统调用”,看看是否有帮助 .
最好,弗兰克
正如您所说,您使用ELF64作为编译的目标 . 不幸的是,这是你的第一个错误 . 在Linux上使用"old"系统调用接口,例如只有在运行32位任务时才可以使用
int 80h
. 显然,您可以简单地将源组装为ELF32,但如果以64位模式运行任务,即额外的寄存器和64位操作,您将失去所有优势 .为了在64位任务中进行系统调用,必须使用"new"系统调用接口 . 系统调用本身是使用
syscall
指令完成的 . 内核会破坏寄存器rcx
和r11
. 系统的编号在寄存器rax
中指定,而调用的参数在rdi
,rsi
,rdx
,r10
,r8
和r9
中传递 . 请记住,系统调用的数量与32位模式的数量不同 . 您可以在unistd_64.h
中找到它们,通常在/usr/include/asm
或您的发行版存储它的任何地方 .