GCC命令背后的故事

本文通过几个简单的程序实例,学习gcc命令生成静态库.a 和动态库.so的方法和库的使用。以及了解gcc命令背后的编译文章,分析了解学习ELF文件格式。


一:预备知识:

(1)gcc命令的使用

语法:
  gcc  [options]  file...

选项:

  -c        :编译和汇编,但不链接。
  -o <file> :指定输出文件。    
  -S        :只编译(不汇编或链接)。
  -E        :仅执行预处理(不要编译、汇编或链接)。

(2)静态库.a 和动态库.so

     函数库,什么是库?库就是一段已经编译好了的代码,在编程的时候加上特定的头文件,就可以使用对应的库函数。
并且使用库,在编译的时候也不会再去编译库,可以节省时间成本。库的分类分为静态库和动态库两种。
     静态库:静态链接库( .a)。之所以叫做静态,是因为静态库在编译的时候会被直接拷贝一份,复制到目标程序,
  代码在目标程序里就不会再改变。程序运行则不需要静态库的存在。
     动态库:动态链接库(.so)。与静态库相反,动态库在编译时并不会被拷贝到目标程序中,目标程序中只会存储指向
  动态库的引用。等程序运行时,动态库才会被加载进来。

(3)ar 命令的使用

  描述:ar命令是建立或修改备存文件,或是从备存文件中抽取文件。ar可以集合许多文件,成为单一的备存文件。
  语法:ar [options]  [mod]  归档文件  [成员文件…] 
  option必选选项:
     -d  删除备存文件中的成员文件。
     -m  变更成员文件在备存文件中的次序。
     -p  显示备存文件中的成员文件内容。
     -q  将文件附加在备存文件末端。
     -r  将文件插入备存文件中。
     -t  显示备存文件中所包含的文件。
     -x  自备存文件中取出成员文件。
  mod可选选项:
    a<成员文件>  将文件插入备存文件中指定的成员文件之后。
    b<成员文件>  将文件插入备存文件中指定的成员文件之前。
    c  建立备存文件。
    f  避免过长的文件名不兼容于其他系统的ar指令指令,因此可利用此参数,截掉要放入备存文件中
    过长的成员文件名称。
    i<成员文件>  将文件插入备存文件中指定的成员文件之前。
    o  保留备存文件中文件的日期。
    s  若备存文件中包含了对象模式,可利用此参数建立备存文件的符号表。
    S  不产生符号表。
    u  只将日期较新文件插入备存文件中。
    v  程序执行时显示详细的信息。
    V  显示版本信息。

(4)ELF文件格式

    ELF(Executable and Linkable Format,可执行与可链接格式)文件格式,我们经gcc编译之后生成的可执行文件
 属于ELF文件。
   文件大致分为下面几个段:
      text:已编译程序指令代码
      rodata:只读数据
      data:初始化C程序的全局变量与静态局部变量
      bss:未初始化的C程序的全局变量与静态局部变量
      debug:调试符号表

在这里插入图片描述

二、hello实例使用库

(1)使用Vim命令编写hello.h,hello.c,main.c文件
在这里插入图片描述

(2)
①hello.c
在这里插入图片描述
②hello.h
在这里插入图片描述
③main.c
在这里插入图片描述

(3)<$ gcc -c hello.c> 将hello.c编译成hello.o文件
在这里插入图片描述
(4)< $ ar -crv libmyhello.a hello.o>由.o文件创建静态库
在这里插入图片描述
(5)< gcc main.c -L. -myhello -o hello>使用静态库在这里插入图片描述
(6)< gcc -c main.c>
< gcc -o hello main.o libmyhello.c > 先生成main.o再使用库生成可执行文件
在这里插入图片描述
(7)删除静态库.a文件后执行可执行文件
在这里插入图片描述

(8)<gcc -shared -fPIC -o libmyhello.so hello.o>生成动态库文件

      shared:表示指定生成动态链接库,不可省略
      -fPIC:表示编译为位置独立的代码,不可省略
      命令中的-o 不能够被省略          

在执行./hello文件时,会报错
解决方式:< sudo mv libmyhello.so /usr/lib>

    将libmyhello.so复制到目录/usr/lib中。由于运行时,是在/usr/lib中找库文件的。
    sudo:增加权限

在这里插入图片描述

三、库使用实例练习

(1)使用vim编写.c文件和.h文件
① sub1.c
在这里插入图片描述
②sub2.c
在这里插入图片描述
③sub1.h
在这里插入图片描述
④main.c
在这里插入图片描述

(2)< gcc -c sub1.c sub2.c>将 .c文件,用gcc分别编译为.o 目标文件
在这里插入图片描述

(3)< ar cry libsub.a sub1.o sub2.o > 用 ar工具生成1个 .a 静态库文件在这里插入图片描述
(4)< gcc -o main main1.c libsub.a>将 main函数的目标文件与此静态库文件进行链接,生成最终的可执行程序 在这里插入图片描述
(5)< stat 文件名 >记录库文件和可执行程序大小
在这里插入图片描述
(6)动态库的生成和使用
< gcc -shared -fPIC -o libsub.so sub1.o sub2.o> :生成动态库文件
< gcc -o main main1.c libsub.so >: 链接动态库生成可执行文件
在这里插入图片描述
(7)动态库文件大小
在这里插入图片描述
(8)大小比较结论,静态库文件比动态库文件小,生成可执行文件大小差距不大。

四、gcc编译器背后的故事

(1)gcc 编译过程

①:预处理

   命令:gcc -E hello.c -o hello.i
   过程:1.将所有#define删除,展开宏定义。处理所有条件预编译指令
        2.处理所有#inlcude预编译指令
        3.删除注释//,/* */
        4.添加行号和文件标识,以便编译时产生调试用的行号及编译错误警告行号。
        5.保留所有的#pragma 编译器指令

编写程序代码

在这里插入图片描述
预处理
在这里插入图片描述
cat查看预处理后生成的hello.i文件
在这里插入图片描述

②:编译

   命令: gcc -S hello.i -o hello.s
   // 将预处理生成的 hello.i 文件编译生成汇编程序 hello.s
   // GCC 的选项-S 使 GCC 在执行完编译后停止,生成汇编程序

在这里插入图片描述
cat查看hello.s文件
在这里插入图片描述

③:汇编

   命令:gcc -c hello.s -o hello.o
   // 将编译生成的 hello.s 文件汇编生成目标文件 hello.o
   // GCC 的选项-c 使 GCC 在执行完汇编后停止,生成目标文件

在这里插入图片描述

④: 链接

   前面我们已经联系了静态库和动态库的生成与使用。通过链接最终生成可执行程序。这里不再赘述。

使用动态库链接效果:
在这里插入图片描述

(2)ELF文件格式分析

①< readelf -S hello > 查看ELF文件各section的信息
在这里插入图片描述
②< objdump -D hello >反汇编方式查看ELF文件指令与数据
格式:PC地址: 指令编码 指令的汇编格式在这里插入图片描述
③<gcc -o hello -g hello.c >
< objdump -S hello >将反汇编与C语言代码混合显示
在这里插入图片描述
在这里插入图片描述

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值