【嵌入式】了解gcc背后的故事

一、gcc生成使用.a静态库与.so动态库

1)创建一个新文件夹test1

mkdir test1

进入文件夹test1

cd test1

在这里插入图片描述
使用vim命令生成hello.h,hello.c,main.c三个文件

vim hello.h

#ifndef HELLO_H
#define HELLO_H
void hello(const char *name);
#endif//HELLO_H

vim hello.c

#include<stdio.h>
void hello(const char *name)
{
        printf("Hello %s!\n",name):
}

vim main.c

#include"hello.h"
int main()
{
        hello("everyone");
        return 0;
}

在这里插入图片描述
2)将hello.c用gcc编译成.o文件

gcc -c  hello.c

在这里插入图片描述
3)由.o文件生成静态库

ar -crv libmyhello.a hello.o

在这里插入图片描述
4)在程序中使用静态库

gcc -o hello main.c -L. -lmyhello

运行程序

./hello

在这里插入图片描述
尝试删除静态库函数后再运行程序试试

rm libmyhello.a

在这里插入图片描述

发现程序依旧能运行,说明静态库中的公用函数hello已经连接到目标文件hello中了。

5)由.o文件生成动态库

gcc -shared -fPIC -o libmyhello.so hello.o

在这里插入图片描述
6)在程序中使用动态库

./hello

结果程序出错了
在这里插入图片描述

原来是程序在运行时,会在/usr/lib和/lib等目录中寻找需要的动态库文件。找到了,则载入动态库;找不到,则会提示类似上述错误而终止程序运行。

将文件libmyhello.so复制到目录/user/lib中,并再次运行。

sudo mv libmyhello.so /usr/lib

在这里插入图片描述
运行成功,也进一步说明动态库在程序运行时是需要的。

二、c语言程序的静态库和动态库

1.自定义c语言程序

在test文件夹中分别创建sub1.c,sub2.c,main1.c三个文件
sub1.c:包含函数x2x(两数相除)

float x2x(int a,int b)
{
        return a/b;
}

sub2.c:包含函数x2y(两数相乘)

float x2y(int a,int b)
{
        return a*b;
}

main1.c:包含main函数

#include<stdio.h>
#include"sub1.c"
#include"sub2.c"
int main()
{
        int a=4,b=2;
        printf("a= %d  b= %d\n",a,b);
        printf("x2x:a/b= %f\n",x2x(a,b));
        printf("x2y:a*b= %f\n",x2y(a,b));
        return 0;
}

2.生成静态库与可执行程序文件

使用gcc编译sub1.c和sub2.c得到.o文件

gcc -c sub1.c sub2.c

在这里插入图片描述
使用ar命令生成静态库

ar -crv libsub1.a sub1.o
ar -crv libsub2.a sub2.o

在这里插入图片描述
在程序中使用静态库

gcc main1.c libsub1.a libsub2.a -o main2

运行程序main2
在这里插入图片描述

3.生成动态库与可执行程序文件

使用gcc命令生成动态库

gcc -shared -fPIC -o libsub1.so sub1.o
gcc -shared -fPIC -o libsub2.so sub2.o

在这里插入图片描述
在程序中使用动态库

gcc main1.c libsub1.so libsub2.so -o main3

在这里插入图片描述

将两个.so文件移动到目录/usr/lib 中去

sudo mv libsub1.so /usr/lib
sudo mv libsub2.so /usr/lib

运行程序
在这里插入图片描述

三、Linux gcc的编译过程

在test3目录下创建一个简单的c语言程序文件test.c

#include<stdio.h>
int main()
{
        printf("Hello World!\n");
        return 0;
}

其实这个程序一步到位的编译指令是gcc test.c -o test
实质上其编译过程分为4个阶段:预处理/预编译→编译→汇编→连接

1)预处理/预编译
将源文件 hello.c 文件预处理生成 hello.i

gcc -E test.c -o test.i

2)编译
将预处理生成的 hello.i 文件编译生成汇编程序 hello.s

gcc -S test.i -o test.s

3)汇编
将编译生成的 hello.s 文件汇编生成目标文件 hello.o

// 用gcc进行汇编
gcc -c hello.s -o hello.o

//用as进行汇编
as -c hello.s -o hello.o

4)连接
分为静态链接和动态链接,生成可执行文件

//动态链接
gcc hello.c -o hello

//静态链接
gcc -static hello.c -o hello

5)程序运行
在这里插入图片描述

四、gcc编译工具集

1.了解ELF文件

1)分析ELF文件

ELF文件包括下面几个段

  • .test:已编译程序的指令代码段。
  • .rodata:ro代表read only,即制度数据(譬如常熟const)。
  • .data:已初始化的c程序全局变量和静态局部变量
  • .bss:未初始化的c程序全局变量和静态局部变量
  • .dbug:调试符号表,调试器用此段的信息帮助调试

在这里插入图片描述

可以使用readelf -S命令查看各个section的信息

readelf -S test

在这里插入图片描述
2)反汇编ELF

由于ELF文件无法被当做普通文本文件打开,如果希望直接查看一个ELF文件包含的命令和数据,需要使用反汇编的方法。

使用objdump -D命令对其进行反汇编

objdump -D test

在这里插入图片描述

2.as汇编编译器

1)首先是下载安装nasm编译器
下载链接: https://www.nasm.us/pub/nasm/releasebuilds/2.14rc16/nasm-2.14rc16.tar.gz
将链接复制到ubuntu内的火狐浏览器进行下载,下载完成后查看文件地址
在这里插入图片描述
然后观察路径,发现压缩包在/tmp/mozilla_huo0内
在这里插入图片描述
控制版中依次执行以下命令进入文件夹

cd /
cd tmp
cd mozilla_huo0

在这里插入图片描述
找到下载的安装包了,解压

tar zxvf nasm-2.14rc16.tar.gz

解压完成后依次执行以下命令进行安装

cd nasm-2.14rc16/
./configure
make
sudo make install

查看是否安装成功

nasm -version

在这里插入图片描述
2)编译汇编文件 hello.asm
新建文件hello.asm,代码如下:

; hello.asm 
section .data            ; 数据段声明
        msg db "Hello, world!", 0xA     ; 要输出的字符串
        len equ $ - msg                 ; 字串长度
section .text            ; 代码段声明
global _start            ; 指定入口函数
_start:                  ; 在屏幕上显示一个字符串
        mov edx, len     ; 参数三:字符串长度
        mov ecx, msg     ; 参数二:要显示的字符串
        mov ebx, 1       ; 参数一:文件描述符(stdout) 
        mov eax, 4       ; 系统调用号(sys_write) 
        int 0x80         ; 调用内核功能
                         ; 退出程序
        mov ebx, 0       ; 参数一:退出代码
        mov eax, 1       ; 系统调用号(sys_exit) 
        int 0x80         ; 调用内核功能

编译

nasm -f elf64 hello.asm

链接:

ld -s -o hello hello.o

运行程序
在这里插入图片描述
3)对比汇编与C代码的编译生成的可执行程序文件
C语言:
在这里插入图片描述
汇编:
在这里插入图片描述
发现直接由汇编生成的程序文件要更小。

五、linux环境下运行c语言小游戏

1)实现小游戏前要先下载curses库

curses库是UNIX下的一套专门用来处理终端界面下的光标移动以及屏幕显示的一个函数库。

sudo apt-get install libncurses5 libncurses5-dev 

2)创建小游戏程序文件,并对其进行编译

链接: Linux 环境下C语言编译实现贪吃蛇游戏

gcc mysnake1.0.c -lcurses -o mysnake

在这里插入图片描述
3)运行小游戏
在这里插入图片描述
在这里插入图片描述

六、实验总结

此次实验加深了解了gcc编译器,学会了用gcc命令生成并使用静态库和动态库,且都生成了可执行程序文件。除此之外,也有了解到编译工具集中个软件的用途,比如ELF文件格式和汇编语言格式。最后也体验到了linux环境下的c语言小游戏,对curses库有一个初步的认识和了解。

七、参考

Linux 环境下C语言编译实现贪吃蛇游戏
GCC编译器背后的故事

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值