我在Ubuntu上使用NASM汇编程序。我正在尝试执行此代码:
section .data
fmt db "%d",0
val1 dd 23
val2 dd 9
val3 dd 7
section .text
global _start
extern printf
_start:
push val1
push val2
push val3
pop rax
pop rbx
imul rax, rbx
push rax
pop rax
pop rbx
add rax, rbx
push rax
pop rax
mov [val1], rax
push val1
push fmt
call printf
add rsp, 16
mov rax,0
ret
nasm -f elf64 test64.asm
成功创建了test64.o并且ld -s -o hello test64.o -lc
创建了一个可执行文件,但是当我尝试运行它时,我得到一个“没有这样的文件或目录”错误。
答案 0 :(得分:2)
1)您使用printf
的错误调用约定。参数在寄存器中传递,而不是在堆栈中传递:https://en.wikipedia.org/wiki/X86_calling_conventions#System_V_AMD64_ABI。此外,printf
需要EAX
中的值(在您的情况下为0)。
2)程序启动时,堆栈上没有返回地址。看这里:http://www.dreamincode.net/forums/topic/285550-nasm-linux-getting-command-line-parameters。为此,
mov rax,0
ret
错了。但是如果你使用64-bit-Linux-syscall
mov edi, 0 ; return 0 (success)
mov eax, 60 ; sys_exit
syscall
您将看不到printf
的输出,因为它被缓冲并且不会刷新缓冲区。您可以致电fflush(0)
或exit
。
3)要在Linux中使用C函数,您必须使用特殊加载器(/lib64/ld-linux-x86-64.so.2
)进行链接。我只是不知道它是否默认安装。
4)push val1
推送val1的地址,而不是其值。使用括号来获取值。我想你只想将32位DWORD加载到64位寄存器中。您可以直接将DWORD加载到32位寄存器(64位寄存器的上半部分将被清除)或使用movsx
进行签名操作。
精髓:
section .data
fmt db `%d\n`,0 ; backticks for '\n'
val1 dd 23
val2 dd 9
val3 dd 7
section .text
global _start
extern printf, exit
_start:
movsx rax, dword [val1] ; signed dword to signed qword
movsx rbx, dword [val2]
imul rax, rbx
mov ebx, [val3] ; unsigned dword into RBX
add rax, rbx
mov [val1], rax
mov rdi, fmt ; string pointer
mov rsi, [val1] ; immediate value
xor eax, eax ; no vector registers used
call printf
xor edi, edi
call exit
nasm -f elf64 test64.asm
ld -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o test64 test64.o -lc
./test64
答案 1 :(得分:0)
您是否尝试过启动它?
./test
可能是,当前路径不在路径列表中,在哪里搜索可执行文件。
检查权限是否允许执行文件,例如:
$ ls ./test
-rwxr-xr-x user user .... test