今天有看CS630的Chapter 15,发现里头的一个例程manydots.s无法正常编译。 $ gcc manydots.s -o manydots /tmp/ccIvmRVT.o: In function `_start": (.text+0x0): multiple definition of `_start" /usr/lib/gcc/x86_64-linux-gnu/4.3.1/../../../../lib/crt1.o:(.text+0x0): first defined here /usr/lib/gcc/x86_64-linux-gnu/4.3.1/../../../../lib/crt1.o: In function `_start": (.text+0x20): undefined reference to `main" collect2: ld returned 1 exit status $ sed -i -e "s/_start/main/g" manydots.s $ gcc manydots.s -o manydots $ ./manydots Segmentation fault $ file manydots manydots: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.8, not stripped
通过上面的实验,首先根据提示发现_start有multiple definition,所以根据自己的经验,把里头的_start符号替换成main。因为用gcc编译时默认的程序入口是main,而不是 _start。资料[2]告诉我们_start是真正的程序入口,但是这个真正的入口是gcc默认链接到我们的可执行文件中的,如果我们这里又设置一个 _start符号,那就是multiple definition了(你可以通过gcc的-S选项编译一个C语言程序产生汇编代码,看看汇编代码的程序入口,刚好是main,关于谁是真正的程序入 口,你可以看看资料[2])。 那修改了_start为main后,能够正常编译,但为什么还出现segmentation fault呢?原因是源代码mangdots.s是为32为平台写的,而我用的处理器是64位的,并且安装了64位的Ubuntu/Linux。 [color="black"]$ cat /proc/cpuinfo | grep "model name" model name : AMD Athlon(tm) 64 X2 Dual Core Processor 4200+ model name : AMD Athlon(tm) 64 X2 Dual Core Processor 4200+ $ uname -a Linux falcon 2.6.26-1-amd64 #1 SMP Thu Aug 28 11:13:42 UTC 2008 x86_64 GNU/Linux
我们发现,64位平台跟32位平台有很大的不同,包括参数传递方式,指令集都有很大的变化,那怎么能够让它正常运行呢?利用 gcc的-m32参数编译产生32位的目标代码,而不是64位的目标代码,因为32位的目标代码可以运行在64位的主机上。 $ gcc -m32 manydots.s -o manydots $ ./manydots How many dots do you want to see? 10 .......... $ file manydots manydots: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.8, not stripped 可以看到,这样就okay了。 实际上,我们还可以分步来做:先汇编,后链接。这样可以减少目标代码的大小,先看看原来的大小。 [color="black"]$ wc -c manydots 6495 manydots
我们分步汇编、链接: [color="black"]// 这个时候是需要一个默认的_start入口的,如果不指定,会默认设置一个程序入口地址,因为这个时候没有人给我们设置一个真正的入口_start了。 $ sed -i -e "s/main/_start/g" manydots.s $ as --32 manydots.s -o manydots.o $ ld -m elf_i386 manydots.o -o manydots $ wc -c manydots 1026 manydots $ echo "6495-1026" | bc 5469 $ ./manydots How many dots do you want to see? 10 ..........