【问题标题】:"No such file or directory" error when trying to execute a binary [duplicate]尝试执行二进制文件时出现“没有这样的文件或目录”错误[重复]
【发布时间】:2024-04-29 10:50:02
【问题描述】:

我在 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 创建了一个可执行文件,但是当我尝试运行它时,出现“没有这样的文件或目录”错误。

【问题讨论】:

  • 关于编辑 - 我正在添加 Linux 标签。这段代码是用 NASM 编译的;是关于在类似 Linux 的环境中运行可执行文件(证实了我们被标记为 Ubuntu 的事实);链接器目标是 ELF64。我建议,鉴于这些信息,Linux 仍然是一个适用的标签,因为它是一个关于 Linux 环境中软件开发的问题,要解决这个问题需要一个 Linux 特定的解决方案。

标签: linux assembly ubuntu-14.04 nasm x86-64


【解决方案1】:

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

【讨论】:

  • 非常感谢,这行得通!
  • @TatianaRoodenko:您也可以只在 64 位代码中使用 32 位操作,而不是符号扩展至 64。每条指令将短一个字节(无 REX 前缀)。 mov esi, [val1]/imul esi, [val2]/add esi, [val3]。由于您最终将调用 printf,因此您不妨首先在 rsi 中构建您的输入,而不是将其移动到那里(尤其是不要通过内存,除非您想保存该值以备后用)。另请注意,mov [val1], rax 会覆盖 val1 和 val2,因为它是 64 位存储。
  • @PeterCordes 谢谢!
【解决方案2】:
  1. 你尝试过开始吗?

    ./test
    

可能是当前路径不在路径列表中,在哪里可以搜索可执行文件。

  1. 检查权限是否允许执行文件,例如:

    $ ls ./test
    
    -rwxr-xr-x user user .... test
    

【讨论】:

  • 是的,我做到了,它不起作用。也尝试用 sudo 运行它,但得到了同样的错误
  • 使用ls的文件看起来如何?
  • -rwxrwxr-x 1 cephalgia cephalgia 2072 гру 12 18:37 ./test64*
  • 是的,我一直在尝试这个
最近更新 更多