精华内容
下载资源
问答
  • linux下程序编译链接过程

    千次阅读 2020-07-26 14:53:02
    Linux下使用GCC将源码编译成可执行文件的过程可以分解为4个步骤,分别是预处理(Prepressing)、编译(Compilation)、汇编(Assembly)和链接(Linking)。一个简单的hello word程序编译过程如下: 1. 预处理 ...

    微信公众号:二进制人生
    专注于嵌入式linux开发。
    更新:2020/05/20,内容整理自网络。


    在Linux下使用GCC将源码编译成可执行文件的过程可以分解为4个步骤,分别是预处理(Prepressing)、编译(Compilation)、汇编(Assembly)和链接(Linking)。一个简单的hello word程序编译过程如下:

    1. 预处理

    首先源代码文件(.c/.cpp)和相关头文件(.h/.hpp)被预处理器cpp预编译成.i文件(C++为.ii)。预处理命令为:

    gcc –E hello.c –o hello.i
    

    预编译过程主要处理那些源代码中以#开始的预编译指令,主要处理规则如下:

    u 将所有的#define删除,并且展开所有的宏定义;

    u 处理所有条件编译指令,如#if,#ifdef、#elif,#else、#endif等;

    u 处理#include预编译指令,将被包含的文件插入到该预编译指令的位置。该过程递归进行,及被包含的文件可能还包含其他文件。

    u 删除所有的注释//和 /**/;

    u 添加行号和文件标识,如#2 “hello.c” 2,以便于编译时编译器产生调试用的行号信息及用于编译时产生编译错误或警告时能够显示行号信息;

    u 保留所有的#pragma编译器指令,因为编译器须要使用它们。

    所以如果想看宏的展开,可以使用gcc -E。

    2. 编译

    编译过程就是把预处理完的文件进行一系列词法分析,语法分析,语义分析及优化后生成相应的汇编代码文件(.s)。

    语法分析:分析表达式是否遵循语法规则

    词法分析:分析关键字,标识符,立即数是否合法

    语义分析:在语法分析基础上进一步分析表达式是否合法

    编译的命令为:

    gcc –S hello.i –o hello.s
    

    或者从源文件直接输出汇编代码文件:

    gcc –S hello.c –o hello.s
    

    3. 汇编

    汇编就是将汇编代码转变成机器可以执行的命令,生成目标文件(.o),汇编器as根据汇编指令和机器指令的对照表一一翻译即可完成。汇编的命令为:

    gcc –c hello.s –o hello.o
    

    或者从源文件直接输出目标文件:

    gcc –c hello.c –o hello.o
    

    4. 链接

    链接就是链接器ld将各个目标文件组装在一起,解决符号依赖,库依赖关系,并生成可执行文件。

    链接过程是由于汇编程序生成的目标文件并不能立即就被执行,其中可能还有许多没有解决的问题。例如,某个源文件中的函数可能引用了另一个源文件中定义的某个符号(如变量或者函数调用等);在程序中可能调用了某个库文件中的函数,等等。所有的这些问题,都需要经链接程序的处理方能得以解决。

    链接程序的主要工作就是将有关的目标文件彼此相连接,也即将在一个文件中引用的符号同该符号在另外一个文件中的定义连接起来,使得所有的这些目标文件成为一个能够按操作系统装入执行的统一整体。根据开发人员指定的同库函数的链接方式的不同,链接处理可分为两种:

    • 1)静态链接
      在这种链接方式下,函数的代码将从其所在地静态链接库中被拷贝到最终的可执行程序中。这样该程序在被执行时这些代码将被装入到该进程的虚拟地址空间中。静态链接库实际上是一个目标文件的集合,其中的每个文件含有库中的一个或者一组相关函数的代码。

    • 2)动态链接
      在此种方式下,函数的代码被放到称作是动态链接库或共享对象的某个目标文件中。链接程序此时所作的只是在最终的可执行程序中记录下共享对象的名字以及其它少量的登记信息。在此可执行文件被执行时,动态链接库的全部内容将被映射到运行时相应进程的虚地址空间。动态链接程序将根据可执行程序中记录的信息找到相应的函数代码。

    对于可执行文件中的函数调用,可分别采用动态链接或静态链接的方法。

    使用动态链接能够使最终的可执行文件比较短小(没有将函数部分拷贝),并且当共享对象被多个进程使用时能节约一些内存,因为在内存中只需要保存一份此共享对象的代码。但并不是使用动态链接就一定比使用静态链接要优越。在某些情况下动态链接可能带来一些性能上损害,例如移植性将大大降低。

    我们在linux使用的gcc编译器便是把以上的几个过程进行捆绑,使用户只使用一次命令就把编译工作完成。
    链接的命令为:ld。

    一般我们使用一条命令就可以完成上述4个步骤:

    gcc hello.c
    

    实际上gcc只是一些其它程序的包装,它会根据不同参数去调用预编译编译程序cc1、汇编器as、链接器ld。

    总结起来编译过程就上面的四个过程:预编译、编译、汇编、链接。了解了这四个过程中所做的工作,对我们理解头文件、库等的工作过程是有帮助的,而且清楚的了解编译链接过程还对我们在编程时定位错误,以及编程时尽量调动编译器的检测错误会有很大的帮助的。


    每天进步一点点…
    喜欢的看官点个在看

    图 二进制人生公众号

    展开全文
  • Linux C Hook动态链接过程

    千次阅读 2020-10-28 19:41:40
    这里讲一讲劫持GCC编译的链接过程,这里我们需要了解一下动态链接的一个环境变量,LD_PRELOAD; LD_PRELOAD 环境变量可以定义在程序运行前优先加载的动态链接库。这使得我们可以有选择性地加载不同动态链接库中的相同...

    Linux 下GCC的编译可分为4个步骤:预处理 --> 编译 --> 汇编 -->链接

    这里讲一讲劫持GCC编译的链接过程,这里我们需要了解一下动态链接的一个环境变量,LD_PRELOAD;
    LD_PRELOAD 环境变量可以定义在程序运行前优先加载的动态链接库。这使得我们可以有选择性地加载不同动态链接库中的相同函数,即通过设置该变量,在主程序和其动态链接库中间加载别的动态链接库,甚至覆盖原本的库,这就有可能出现劫持程序执行的安全问题。

    “ldpreload.c”

    #include<stdio.h>
    #include<string.h>
    
    void main() {
        char passwd[] = "password";
        char str[128];
    
        scanf("%s", &str);
        if (!strcmp(passwd, str)) {
            printf("the password is correct\n");
            return;
        }
        printf("the password is invalid\n");
    }
    
    

    程序很简单,就不多解释了,根据对环境变量LD_PRELOAD的解释,我们要构造一个恶意的动态链接库来重载 strcmp() 函数,编译为动态链接库,并设置 LD_PRELOAD 环境变量:

    “hook.c”

    #include<stdio.h>
    #include<stdio.h>
    int strcmp(const char *s1, const char *s2) {
        printf("LD_PRELOAD hooked\n");
        return 0;
    }
    
    //编译hook so库
    curits@curits-virtual-machine:~/Desktop/ld_preload$ gcc -shared -o hook.so hook.c 
    curits@curits-virtual-machine:~/Desktop/ld_preload$ ls
    hook.c  hook.so  ldpreload.c
    //正常执行ldpreload程序
    curits@curits-virtual-machine:~/Desktop/ld_preload$ gcc ldpreload.c
    curits@curits-virtual-machine:~/Desktop/ld_preload$ ./a.out 
    124
    the password is invalid
    //链接时替换strcmp结果
    curits@curits-virtual-machine:~/Desktop/ld_preload$ export LD_PRELOAD="./hook.so"
    curits@curits-virtual-machine:~/Desktop/ld_preload$ ./a.out 
    123
    LD_PRELOAD hooked
    the password is correct
    //移除hook
    curits@curits-virtual-machine:~/Desktop/ld_preload$ ./a.out 
    ERROR: ld.so: object 'NULL' from LD_PRELOAD cannot be preloaded (cannot open shared object file): ignored.
    123
    the password is invalid
    
    展开全文
  • Linux下程序编译链接过程Linux下使用gcc将源码(.c文件)编译成可执行文件的过程可以分解为4个步骤,分别是预处理(Prepressing),编译(Compilation),汇编(Assembly),链接(Linking) 1.预处理 .c ----> .i ...

    Linux下程序编译链接过程

    在Linux下使用gcc将源码(.c文件)编译成可执行文件的过程可以分解为4个步骤,分别是预处理(Prepressing),编译(Compilation),汇编(Assembly),链接(Linking)

    在这里插入图片描述

    1.预处理

    .c ----> .i
    命令:gcc -E hello.c -o hello.i
    ---> -E:可以使编译器在预处理完成后就停止编译  -o:指定gcc输出的结果
    

    预处理过程主要处理那些源代码中以#开头的代码:
    1.处理#define,展开所有的宏定义
    2.处理条件编译指令,如#ifdef、#else、#endif
    3.处理#include,将包含的头文件插入到该预处理指令的位置,该过程递归进行,因为被包含的文件可能还包含其他文件
    4.添加行号和文件标识,如#2 “hello.c” 2,以便编译时编译器产生调试用的行号信息及用于编译时产生编译错误或警告时能够显示行号信息
    5.保留所有的#pragma编译器指令,因为编译器要使用它们

    2.编译

    .i ----> .s
    命令:gcc -S hello.i -o hello.s 或者 gcc -S hello.c -o hello.s
    ---> -S:可以使编译器在编译完成后就停止编译  -o:指定gcc输出的结果
    

    编译过程就是把预处理完的文件进行一系列词法分析,语法分析,语义分析及优化后生成相应的汇编代码文件(.s)
    1.语法分析:分析表达式是否遵循语法规则
    2.词法分析:分析关键字,标识符,立即数是否合法
    3.语义分析:在语法分析基础上进一步分析表达式是否合法

    3.汇编

    .s ----> .o
    命令:gcc -c hello.s -o hello.o 或者 gcc -c hello.c -o hello.o
    ---> -c:可以使编译器在汇编完成后就停止编译  -o:指定gcc输出的结果
    

    汇编就是将汇编代码转变成机器可以执行的命令,生成目标文件(.o),汇编器as根据汇编指令和机器指令的对照表一一翻译即可完成

    4.链接

    多个.o ----> 可执行文件
    命令:gcc -o hello hello.c   //一步到位
    

    链接就是链接器ld将各个目标文件组装在一起,解决符号依赖,库依赖关系,并生成可执行文件
    同时,链接处理可以分为两种:静态链接,动态链接(详细可以看我的上一篇博客静态库和动态库^ -^)

    5.运行

    ./hello  //当编译通过后,执行./+可执行文件名就可以运行文件了
    

    其实可以把gcc当成一个翻译组织,它有很多成员(翻译官)。他根据不同的参数去调用不同的翻译官来翻译。最后,了解这四个过程中所做的工作,对我们理解头文件、库等的工作过程是有帮助的,而且清楚了编译链接过程还对我们在编程时定位错误,以及编程时尽量调动编译器的检测错误也有很大帮助。

    展开全文
  • arm-linux编译链接过程

    2014-05-13 17:36:52
    目前只知道编译内核时先make menuconfig进行一些个性化的设置。... 只是这个过程到底是怎么样的,linux内核如何实现这一系列复杂的链接编译。网上看了点资料,总结一下。  内核编译首先要生成

     目前只知道编译内核时先make menuconfig进行一些个性化的设置。然后执行make即可在内核源码根目录下得到ELF文件vmlinux,并且在相应体系结构arch/arm/boot目录下得到zImage可执行的压缩内核映像,进而烧写到开发板中。

        只是这个过程到底是怎么样的,linux内核如何实现这一系列复杂的链接编译。网上看了点资料,总结一下。

        内核编译首先要生成的是vmlinux。这是一个ELF格式,非压缩的内核。他是如何得来的,在源码根目录下。vmlinux.cmd文件中可以查看到。

        cmd_vmlinux := arm-linux-ld -EL  -p --no-undefined -X --build-id -o vmlinux -T arch/arm/kernel/vmlinux.lds arch/arm/kernel/head.o arch/arm/kernel/init_task.o  init/built-in.o --start-group  usr/built-in.o  arch/arm/kernel/built-in.o  arch/arm/mm/built-in.o  arch/arm/common/built-in.o  arch/arm/mach-s3c64xx/built-in.o  arch/arm/plat-samsung/built-in.o  kernel/built-in.o  mm/built-in.o  fs/built-in.o  ipc/built-in.o  security/built-in.o  crypto/built-in.o  block/built-in.o  arch/arm/lib/lib.a  lib/lib.a  arch/arm/lib/built-in.o  lib/built-in.o  drivers/built-in.o  sound/built-in.o  firmware/built-in.o  net/built-in.o --end-group .tmp_kallsyms2.o

        可以看出vmlinux的生成依赖于arch/arm/kernel/head.o,arch/arm/kernel/init_task.o,以及其他子目录下的built-in.o。至于底层还需要什么文件也可以按图索骥了。

        vmlinux虽然已经是一个编译好的内核映像,但并不是最终烧写的映像,vmlinux需要通过arm-linux-objcopy转换,在对应体系结构下生成bin格式的映像文件Image。压缩映像由make zImage命令完成。最终生成zImage。

        过程为:

        1.用gzip对压缩内核二进制映象arch/arm/boot/ Image 进行压缩,生成arch/arm/boot/compressed/piggy.gz 文件

        2.在/arch/arm/boot/conpressed目录下生成vmlinux

        vmlinux把内含的内核符号表剥离,在arch/arm/boot/compressed/vmlinux.bin,再将vmlinux.bin压缩成vmlinux.bin.gz,将vmlinux.scr和vmlinux.bin.gz链接成piggy.o,将head.o、misc.o和piggy.o链接成当前目录下的vmlinux,将vmlinux文件strip掉符号表得到arch/i386/boot/vmlinux.bin。

        对应代码:

        cmd_arch/arm/boot/compressed/vmlinux := arm-linux-ld -EL    --defsym zreladdr=0x50008000 -p --no-undefined -X -T arch/arm/boot/compressed/vmlinux.lds arch/arm/boot/compressed/head.o arch/arm/boot/compressed/piggy.gzip.o arch/arm/boot/compressed/misc.o arch/arm/boot/compressed/decompress.o arch/arm/boot/compressed/lib1funcs.o -o arch/arm/boot/compressed/vmlinux

        这是具备自解压功能的压缩内核,也是ELF格式。

        3.用 arm-linux-objcopy 命令把 arch/arm/boot/compressed/vmlinux 转换为二进制格式映象:

        arch/arm/boot/zImage

        该目录下。zImage.cmd代码为

        cmd_arch/arm/boot/zImage := arm-linux-objcopy -O binary -R .note -R .note.gnu.build-id -R .comment -S  arch/arm/boot/compressed/vmlinux arch/arm/boot/zImage

        zImage为压缩了的可执行二进制文件。但在这个文件开头部分内嵌有gzip解压缩代码。linux内核启动时由bootloader把这个映像文件调入内存RAM中,执行完开头的解压缩部分后即可真正进入内核。

        至于arm中linux内核是如何启动的,下回再述

    展开全文
  • linux共享库链接过程

    2018-03-07 08:53:00
    一 与静态库链接 1 符号解析(symbol resolution) 将符号的引用与定义联系在一起。#引用信息和定义信息在哪儿,怎么联系在一起的 1)内部符号解析-编译器  2)外部符号解析-连接器   与静态库链接: 链接器...
  • C/C++编译链接过程 文件以main.c为例,main.c内容如图(1)所示 1、第一步预编译后生成main.i文件,其中部分内容如图所示,预编译阶段做的事情有: (1)处理预编译指令 (2)删除注释 (3)将包含的头文件展开...
  • ARM Linux编译链接过程分析

    千次阅读 2010-10-23 18:55:00
     ARM Linux 编译生成过程3.1 平台无关过程首先,根目录下面生成了 vmlinux ,这个可以从根目录下的 Makefile 过程看到。当然,简单一些,也可以看根目录下的 .vmlinux.cmd 文件,其内容如下:cmd_vmlinux :...
  • 编译链接过程 【1】预处理 源代码被预编译为一个 .i文件 在Linux下,对于一个已经编写好的main.c源程序,代码 gcc -E mainn.c -o main.i 完成对程序的预处理。 或者:cpp main.c &gt; main.i 预处理主要...
  • 本文介绍Linux系统中可执行程序动态链接过程
  • 加上-fPIC参数后,编译后的文件和没有加这个参数的文件,有什么区别呢? 没有加这个参数的编译后的共享库,也可以使用,它和加了参数后的使用起来又有什么区别呢? position independent(位置无关) ...
  • 先列出书中一个例子的简单代码实现,以展示动态链接过程。 Lib.h #ifndef LIB_H #define LIB_H void foobar(int i); #endif Lib.c #include<stdio.h> void foobar(int i) { printf("Printing from ...
  • Linux 链接

    2016-04-24 08:52:48
    磁盘分区进行硬盘分区的时候,最小都是以磁柱为单位进行分割的,那么分割完成之后自然就是格式化(format),在 Linux里面进行格式化的时候必须要考虑到Block与inode的信息。 Block(块)是磁盘可以存取的最小单位,...
  •  (1)作用:预编译过程主要处理那些源代码中以#开始的预编译指令,比如删除注释  (2)将所有的#define删除,并且展开所有的宏定义,比如头文件原地展开  (3)处理所有条件编译指令,如#if,#ifde...
  • linux链接

    2011-08-02 18:41:14
    看了深入理解计算机系统《链接》这一张,写出来,虽然其中有很多还不是很懂,但根据自己的理解写出了一点心得,如果各位... linux的目标文件格式(ELF),就是要生成的目标文件,大体过程如下:  以c编译器为例,例如
  • 今天看到一个很有意思的小程序,它让我对Linux下C程序的编译链接有了一个全新的认识! 这个程序的就是写一个简单的输出“hello World!”: 要求:1.不使用C运行库,写一个独立于任何库的程序。(也就是说我们不能#...
  • 我们很少关注编译链接过程,因为通常的开发环境都是流行的集成开发环境(IDE),如Visual Studio等。这样的IDE一般都将编译和链接的过程一步完成,通常将这种编译和链接合并到一起的过程称为构建(Build)。在Linux...
  • Linux下库函数动态链接过程分析(转) 作者: renyuan000 和linux相关  新浪微博QQ空间QQ微博百度搜藏腾讯朋友QQ收藏百度空间人人网开心网0 Linux下库函数动态链接过程分析-结合glibc-2.11...
  •   Linux环境下gcc用来编译c语言,g++用来编译c语言或者c++ 程序的编译过程 预处理-编译-汇编-链接 预处理 宏替换 头文件展开 去注释   对于gcc/g++需要添加-E命令行参数,生成的文件对应后缀为“.i”。 ...
  • 1.用gcc编译链接过程 1.1. 可执行程序生成: 一步完成 和 两步完成 及环境变量 PATH 介绍 1.2. 从 c 源代码到可执行程序的几个阶段: (1) 预编译 : gcc -E main.c -o main.i (2) 编译: gcc -S main.i -o ...
  • 太精辟了 ... http://www.ibm.com/developerworks/cn/linux/l-elf/part1/ http://www.ibm.com/developerworks/cn/linux/l-elf/part2/ 转载于:https://www.cnblogs.co...
  • 安装虚拟,centos7,putty全过程 首先下载如下安装包 putty链接:https://pan.baidu.com/s/1oXNOkUi6d2rRjFwUJFco-Q 提取码:gcgi vmware链接:https://pan.baidu.com/s/1XIg_07g-EM-7mPyjInYkLw 提取码:...
  • Linux启动过程

    2019-08-30 14:23:13
    启动过程,和启动几个关连目录。别注意/etc/init.d/这个目录指向(软链接)/etc/rc.d/init.d/。林写在查nginx启动脚本时。...Linux启动过程 redhat的启动方式和执行次序是: 加载内核 执行init程序 /etc/rc.d/rc.sy...
  • c++程序在Linux中编译链接及装载过程预编译编译汇编链接深入编译链接和运行CPU、内存 与 I/O32位4GLinux虚拟地址空间布局指令和数据分析二进制可重定位目标文件 hello.o 的组成强符号与弱符号符号表链接过程分析可...
  • Linux学习笔记-编译与链接过程

    千次阅读 2018-08-12 21:59:58
    Linux编译与链接过程 1.编译:compile,将*.cpp-&gt;*.o 2.链接:link,将所有的*.o-&gt;executable 编译: g++ -c main.cpp -o main.o g++ -c other.cpp -o other.o (-c表示compile,不是link) 链接:...
  • 一、linux C语言的编译链接过程  gcc编译命令  gcc -E hello.c -o hello.i 预处理 到/usr/include下找到头文件  gcc -S hello.i -o hello.s 编译 形成汇编代码  gcc -c

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 5,410
精华内容 2,164
关键字:

linux链接过程

linux 订阅