实验1:GCC编译
1.实验目的
1)熟悉GCC的编译过程,学会使用ARM GCC交叉工具链编译应用程序并放入QEMU上运行。
2)学会写简单的Makefile。
2.实验详解
本实验通过一个简单的C语言程序代码演示GCC的编译过程。下面是一个简单的test.c的程序代码。#include
#include
#include
#define PAGE_SIZE 4096
#define MAX_SIZE 100*PAGE_SIZE
int main()
{
char *buf = (char *)malloc(MAX_SIZE);
memset(buf, 0, MAX_SIZE);
printf("buffer address=0x%p
", buf);
free(buf);
return 0;
}
1)预处理。
GCC的“-E”选项可以让编译器在预处理阶段就结束,选项“-o”可以指定输出的文件格式。arm-linux-gnueabi-gcc -E test.c -o test.i
预处理阶段会把C标准库的头文件中的代码包含到这段程序中。test.i文件的内容如下所示。extern void *malloc (size_t __size) __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__malloc__)) ;
…
int main()
{
char *buf = (char *)malloc(100*4096);
memset(buf, 0, 100*4096);
printf("buffer address=0x%p
", buf);
free(buf);
return 0;
}
2)编译。
编译阶段主要是对预处理好的.i文件进行编译,并生成汇编代码。GCC首先检查代码是否有语法错误等,然后把代码编译成汇编代码。我们这里使用“-S”选项来编译。$ arm-linux-gnueabi-gcc -S test.i -o test.s
编译阶段生成的汇编代码如下。.LC0:
.ascii "buffer address=0x%p
"
.text
.align 2
.global main
.thumb
.thumb_func
.type main, %function
main:
@ args = 0, pretend = 0, frame = 8
@ frame_needed = 1, uses_anonymous_args = 0
push {r7, lr}
sub sp, sp, #8
add r7, sp, #0
mov r0, #409600
bl malloc
mov r3, r0
str r3, [r7, #4]
ldr r3, [r7, #4]
mov r2, r3
mov r3, #409600
mov r0, r2
mov r1, #0
mov r2, r3
bl memset
movw r3, #:lower16:.LC0
movt r3, #:upper16:.LC0
mov r0, r3
ldr r1, [r7, #4]
bl printf
ldr r0, [r7, #4]
bl free
mov r3, #0
mov r0, r3
add r7, r7, #8
mov sp, r7
pop {r7, pc}
.size main, .-main
.ident "GCC: (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3"
.section .note.GNU-stack,"",%progbits
3)汇编。
汇编阶段是将汇编文件转化成二进制文件,利用“-c”选项就可以生成二进制文件。$ arm-linux-gnueabi-gcc -c test.s -o test.o
4)链接。
链接阶段会对编译好的二进制文件进行链接,这里会默认链接C语言标准库(libc)。我们的代码里调用的malloc()、memset()以及printf()等函数都由C语言标准库提供,链接过程会把程序的目标文件和所需的库文件链接起来,最终生成可执行文件。
Linux的库文件分成两大类:一类是动态链接库(通常以.so结尾),另一类是静态链接库(通常以.a结尾)。在默认情况下,GCC在链接时优先使用动态链接库,只有当动态链接库不存在时才使用静态链接库。下面使用“--static”来让test程序静态链接C语言标准库,原因是交叉工具链使用的libc的动态库和QEMU中使用的库可能不一样。如果使用动态链接,可能导致运行报错。$ arm-linux-gnueabi-gcc test.o -o test --static
以ARM GCC交叉工具链为例,C函数库动态库的目录在/usr/arm-linux-gnueabi/lib里,最终的库文件是libc-2.23.so文件。$ ls -l /usr/arm-linux-gnueabi/lib/libc.so.6
lrwxrwxrwx 1 root root 12 Apr 16 2016 /usr/arm-linux-gnueabi/lib/libc.so.6 -> libc-2.23.so
C语言标准库的静态库地址如下。$ ls -l /usr/arm-linux-gnueabi/lib/libc.a
-rw-r--r-- 1 root root 3175586 Apr 16 2016 /usr/arm-linux-gnueabi/lib/libc.a
5)放到QEMU上运行。
把test程序放入runninglinuxkernel-4.0/kmodules目录里,启动QEMU并运行test程序。/ # ./mnt/test
buffer address=0x0xb6f73008
/ #
6)编写一个简单的Makefile文件来编译。cc = arm-linux-gnueabi-gcc
prom = test
obj = test.o
CFLAGS = -static
$(prom): $(obj)
$(cc) -o $(prom) $(obj) $(CFLAGS)
%.o: %.c
$(cc) -c $< -o $@
clean:
rm -rf $(obj) $(prom)
EDN