首先,我想澄清一下,我知道这个问题可能已经被回答了数百次。然而,在经过几个小时的谷歌搜索后,我却找不到完全符合我的要求的内容。此外,尽管我已经写了相当长时间的C程序,但我对nasm和ld还比较陌生。因此,如果我能得到一个简单的答案,而不必阅读整个nasm/ld教程或完整的手册,我将不胜感激。
我想做的是: 假设我有一个用C语言编写的函数,调用了C标准库中的某些函数:
我想在nasm中调用这个函数,所以我尝试了这个方法:
我没有收到任何错误信息,但似乎我无法运行可执行的输出文件。
如果C函数不调用任何库函数,则上述代码可以编译并且可以正常运行。我还找出了一种直接调用nasm中的库函数并使用gcc生成最终可执行文件的方法。但是它们都不完全符合我的要求。
编辑: 1. 我正在运行64位Ubuntu,但我正在尝试编写32位程序,因此我使用了像-m32和-melf_i386这样的标志。 2.
我想做的是: 假设我有一个用C语言编写的函数,调用了C标准库中的某些函数:
/* foo.c */
#include <stdio.h>
void foo(int i)
{
printf("%d\n", i);
}
我想在nasm中调用这个函数,所以我尝试了这个方法:
; main.asm
global _start
extern foo
section .text
_start:
push 1234567
call foo
add esp, 4
mov eax, 1
xor ebx, ebx
int 80h
然后我尝试编译并运行它们:
[user ~/Documents/asm/callc]#make all
nasm main.asm -felf
gcc -c foo.c -o foo.o -m32
ld -o main main.o foo.o -melf_i386 -lc
[user ~/Documents/asm/callc]#ls
foo.c foo.o main main.asm main.o Makefile
[user ~/Documents/asm/callc]#./main
bash: ./main: No such file or directory
[user ~/Documents/asm/callc]#bash main
main: main: cannot execute binary file
我没有收到任何错误信息,但似乎我无法运行可执行的输出文件。
如果C函数不调用任何库函数,则上述代码可以编译并且可以正常运行。我还找出了一种直接调用nasm中的库函数并使用gcc生成最终可执行文件的方法。但是它们都不完全符合我的要求。
编辑: 1. 我正在运行64位Ubuntu,但我正在尝试编写32位程序,因此我使用了像-m32和-melf_i386这样的标志。 2.
file *
的输出:[user ~/Documents/asm/sof]#file *
foo.c: C source, ASCII text
foo.c~: empty
foo.o: ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV), not stripped
main: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), not stripped
main.asm: C source, ASCII text
main.asm~: empty
main.o: ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV), not stripped
Makefile: makefile script, ASCII text
Makefile~: makefile script, ASCII text
3. 我真的不知道如何告诉ld包含C标准库。我在其他帖子中找到了像-lglibc或-lc之类的东西。-lgibc行不通,-lc似乎能够摆脱所有错误,一开始可能会让我以为它起作用了,但也许这就是问题所在,因为它可能没有链接正确的库。
更新
将-I/lib32/ld-linux.so.2
添加到ld
命令中解决了我的问题。
以下是编译/汇编/链接和运行程序的命令:
nasm main.asm -felf
gcc -c foo.c -o foo.o -m32
ld -o main main.o foo.o -melf_i386 -lc -I/lib32/ld-linux.so.2
./main
file *
命令,并编辑你的回答以包含输出结果。此外,虽然这不会导致无效可执行文件的问题,但如果C运行时代码没有先运行,你就不应该期望调用C标准库函数。 - Jonathon Reinhart#
通常意味着 shell 正在以 root 用户身份运行。对于非 root 用户,通常是$
。有一个转义序列(\$
)可以显示正确的提示符,因此要么您正在以 root 用户身份运行,要么您已配置 shell 以欺骗方式运行。 :) - cHao_start
。你可以将main
创建为起始点。如果你创建了_start
,那么你就会错过所有正常的支持代码,在调用main
之前进行排序的小细节,例如“加载标准 C 共享库”等。 - Jonathan Leffler