int main(void) {return 0;}
可以使用 gcc -o test test.c
进行编译。
据我了解,gcc 执行编译、汇编和链接三个步骤。后两个步骤通过运行 as
和 ld
完成。
您可以使用 gcc -S test.c
生成汇编代码。
要将汇编代码转换为可执行文件,您应该在终端输入什么?(这样做的原因是为了学习汇编语言)
以下是使用gcc编译器的不同阶段:
gcc -E --> Preprocessor, but don't compile
gcc -S --> Compile but don't assemble
gcc -c --> Preprocess, compile, and assemble, but don't link
gcc with no switch will link your object files and generate the executable
// main.c
#include <stdio.h>
int main(void)
{
printf("Hello World !\n");
return 0;
}
为了预处理、编译、汇编,并最终链接简单的“hello world”程序,请按照以下步骤进行:
第一步/4)对main.c进行预处理以生成main.i:
$: gcc -E main.c -o main.i
注意:你也可以直接调用 C 预处理器:
$: cpp main.c -o main.i
第二步/第四步:编译main.i生成main.s:
$: gcc -S main.i -o main.s
第三步/第四步:将main.s组装生成main.o:
$: as main.s -o main.o
注意:您可以使用gcc的-c(小写C)标志将前面提到的1、2、3步骤合并:
$: gcc -c main.s -o main.o // OR $: gcc -c main.c -o main.o
步骤4/4) 将main.o与其它必要的目标文件链接,例如crti.o和crtn.o(它们分别定义函数前导和epilog),crt1.o(包含启动程序初始执行的_start符号),libc.so路径或-lc标志用于libc,最后设置动态链接器的名称,以生成一个动态链接的ELF可执行文件:
在x86_64上:
$: ld /usr/lib/x86_64-linux-gnu/crti.o /usr/lib/x86_64-linux-gnu/crtn.o /usr/lib/x86_64-linux-gnu/crt1.o -lc main.o -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o main_ELF_executable
或者(如果您想指定到libc.so的路径)
$: ld /usr/lib/x86_64-linux-gnu/crti.o /usr/lib/x86_64-linux-gnu/crtn.o /usr/lib/x86_64-linux-gnu/crt1.o /usr/lib/x86_64-linux-gnu/libc.so main.o -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o main_ELF_executable
在32位ARM上:
$: ld /usr/lib/arm-linux-gnueabihf/crti.o /usr/lib/arm-linux-gnueabihf/crtn.o /usr/lib/arm-linux-gnueabihf/crt1.o -lc main.o -dynamic-linker /lib/ld-linux.so.3 -o main_ELF_executable
或者(如果您想指定libc.so的路径)
$: ld /usr/lib/arm-linux-gnueabihf/crti.o /usr/lib/arm-linux-gnueabihf/crtn.o /usr/lib/arm-linux-gnueabihf/crt1.o /usr/lib/arm-linux-gnueabihf/libc.so main.o -dynamic-linker /lib/ld-linux-armhf.so.3 -o main_ELF_executable
您可以运行ELF可执行文件'main_ELF_executable':
$: ./main_ELF_executable
你好,世界!
参考资料:
https://linux.die.net/man/1/gcc
gcc test.s -o test
会为您编译test.s
文件并生成可执行文件test
。
NASM也是值得学习的,它可能比gcc
更容易、更友好地编译汇编代码。
gcc
为您处理了许多系统相关的繁文缛节,与它如何处理项目的其他部分完全兼容。 - vonbrand在执行gcc -S -o test.s test.c
命令后,输入gcc -o test test.s
。
你可能已经知道或者不知道,编译的四个阶段是预处理(-E)、编译为汇编代码(-S)、汇编为目标代码(-c)和最后的链接。对我来说最难理解的是如何使用预处理器输出。以下是如何操作:
gcc -E hello.c | gcc -S -xc -o hello.s -
gcc -c hello.s -o hello.o
gcc hello.o -o hello
你可以让 gcc
在任何地方开始和停止编译过程。使用命令 gcc test.s -o test
将会把 test.s
从汇编语言编译为可执行文件 test
。
我所做的是首先通过以下方式运行预处理器:
clang++ test.cpp -E > test.i
然后使用以下方式编译它...
clang++ -S test.i
它应该创建一个汇编文件test.s... 然后通过以下方式制作机器指令文件
as test.s -o test.o
现在你需要链接它,这对像我这样的蠢人来说有点困惑...
所以我们不知道我们最后一个过程的参数是什么... 要找出来... 运行
clang++ -v test.s
它应该给你一些大文本... 找到这一行“-dynamic-linker”... 在你的输出文本中肯定有一个-dynamic-linker... 现在复制从-dynamic-linker到输出的其余部分的文本... 只需复制包括“-dynamic-linker”在内的之后的所有内容... 现在我得到的是...
-dynamic-linker /system/bin/linker -o a.out /data/data/com.termux/files/usr/lib/gcc/arm-linux-androideabi/11.1.0/../../../../lib/crtbegin_dynamic.o -L/data/data/com.termux/files/usr/lib/gcc/arm-linux-androideabi/11.1.0 -L/data/data/com.termux/files/usr/lib/gcc/arm-linux-androideabi/11.1.0/../../../../lib -L/data/data/com.termux/files/usr/lib/gcc/arm-linux-androideabi/11.1.0/../../.. -L/data/data/com.termux/files/usr/lib -L/system/lib /data/data/com.termux/files/home/CPP/Cpp_Log/hello_world/test.o -lc++_shared -lgcc -ldl -lm -lc -lgcc -ldl /data/data/com.termux/files/usr/lib/gcc/arm-linux-androideabi/11.1.0/../../../../lib/crtend_android.o
在这里需要修改的是你的目标文件所在的位置... 在我的情况下,它是/data/data/com.termux/files/usr/tmp/test-169b42.o ... 我需要将其更改为我的test.o文件所在的位置 /data/data/com.termux/files/home/CPP/Cpp_Log/hello_world/test.o ... 这是我的test.o文件所在的位置... 所以我们需要传递的参数是...
-dynamic-linker /system/bin/linker -o a.out /data/data/com.termux/files/usr/lib/gcc/arm-linux-androideabi/11.1.0/../../../../lib/crtbegin_dynamic.o -L/data/data/com.termux/files/usr/lib/gcc/arm-linux-androideabi/11.1.0 -L/data/data/com.termux/files/usr/lib/gcc/arm-linux-androideabi/11.1.0/../../../../lib -L/data/data/com.termux/files/usr/lib/gcc/arm-linux-androideabi/11.1.0/../../.. -L/data/data/com.termux/files/usr/lib -L/system/lib /data/data/com.termux/files/home/CPP/Cpp_Log/hello_world/main.o -lc++_shared -lgcc -ldl -lm -lc -lgcc -ldl /data/data/com.termux/files/usr/lib/gcc/arm-linux-androideabi/11.1.0/../../../../lib/crtend_android.o
现在进行链接...使用ld
命令...所以命令是ld args -o test
或者在我们的情况下...
ld -dynamic-linker /system/bin/linker -o a.out /data/data/com.termux/files/usr/lib/gcc/arm-linux-androideabi/11.1.0/../../../../lib/crtbegin_dynamic.o -L/data/data/com.termux/files/usr/lib/gcc/arm-linux-androideabi/11.1.0 -L/data/data/com.termux/files/usr/lib/gcc/arm-linux-androideabi/11.1.0/../../../../lib -L/data/data/com.termux/files/usr/lib/gcc/arm-linux-androideabi/11.1.0/../../.. -L/data/data/com.termux/files/usr/lib -L/system/lib /data/data/com.termux/files/home/CPP/Cpp_Log/hello_world/main.o -lc++_shared -lgcc -ldl -lm -lc -lgcc -ldl /data/data/com.termux/files/usr/lib/gcc/arm-linux-androideabi/11.1.0/../../../../lib/crtend_android.o -pie -o test
...
因为 Android5+ 只能运行 pie elf 可执行文件,所以我在 -o test 前加了 "-pie" (位置无关可执行文件) ...
现在应该会给你一个名为 test 的可执行文件,只需通过 ./test
运行它即可。
它应该可以正常工作。
-v
参数查看GCC如何调用其子程序,例如:gcc -o test test.c -v
。 - makes