精华内容
下载资源
问答
  • 为了屏蔽I/O设备的底层差异,产生虚拟文件系统virtual file system(VFS)。为了屏蔽内存和I/O的差异产生了虚拟存储器(虚拟内存),而为了屏蔽CPU、I/O和内存的差异进而产生进程的概念。 虚拟的概念是由大名鼎鼎的...

    一、简单的CS历史
    现代大多数计算机都是基于冯.诺伊曼提出的存储程序原理采用冯.诺伊曼架构,即由运算器、控制器、存储器和输入输出设备组成。

    为了屏蔽I/O设备的底层差异,产生虚拟文件系统virtual file system(VFS)。为了屏蔽内存和I/O的差异产生了虚拟存储器(虚拟内存),而为了屏蔽CPU、I/O和内存的差异进而产生进程的概念。

    虚拟的概念是由大名鼎鼎的计算机公司IBM提出的,为了方便理解虚拟,IBM写出下面的几句话:

    1、看得见 存在 物理
    2、看得见 不存在 虚拟
    3、看不见 存在 透明

    二、程序是怎么执行的
    我们或多或少都有疑问,这些看似平常的由字符组成的文章是通过怎样的过程可最终以在计算机上执行,高级语言如pascal、c、c++、java等,尽管语言不相同,持有各自的特性,但其最终生成的无非就是指令数据,毫不夸张的讲程序其实就是指令和数据。所以计算机是在做运算,处理指令和数据。那么我们用高级语言编写的程序最终是怎么成为计算机可以识别的机器语言的。在linux系统上,当我们输入./a.out并进行回车时发生了什么。作为一名程序员,这是我们需要知道的。

    下边的代码,用于分析编译、链接过程。

    #include<stdio.h>
    
    int gdata1 = 10;
    int gdata2 = 0;
    int gdata3;
    static int gdata4 = 20;
    static int gdata5 = 0;
    static int gdata6;
    int main(){
        int a = 30;
        int b = 0;
        int c;
        static int d = 40;
        static int e = 0;
        static int f;
        return 0;
    }

    上边共定义的12个变量,其中哪些是指令,哪些是数据。都分布在内存的哪些区域是我们所需清楚的。
    为探究上述问题,首先我们需要清楚的了解虚拟地址空间的内存布局。操作系统为每一个进程分配虚拟地址空间,而虚拟地址空间的大小,取决于CPU的位数,更具体的说是ALU(算术逻辑运算单元的宽度)即一次可以处理最长整数的宽度,同时也可以理解为数据总线的条数。在32bit的linux内核,也可以理解为地址总线的条数,因为地址总线的条数和数据总线的条数相同。总而言之,在32bit操作系统下,虚拟地址空间的大小为2^32即4G的大小的虚拟地址空间。

    三、虚拟地址空间
    由上边分析可知,在32bit的CPU架构下地址总线的条数为32条,所以其寻址能力为2^32个,按字节编址,所以虚拟地址空间的大小为4GB。下面以图示的方式说明这4GB的虚拟地址空间布局是什么样的。
    这里写图片描述

    用户空间的分析:
    (1)保留区:很多情况下,正是由于我们对虚拟地址空间布局不熟悉所以编写出错误的程序。如果熟悉虚拟地址空间的内存布局,大可避免这些不必要的错误。如下边的小程序正是许多许多新手程序员经常犯的错误:

    #include<stdio.h>
    #include<string.h>
    int main(){
        char* p = NULL;
        int len = strlen(p);
        printf("len = %d\n",len);
        return 0;
    }

    显然程序中并没有给指针变量p分配合理的内存,就对p进行了访问,此时p所指向的内存区域正是虚拟地址空间中128MB的保留区,所以会出现段错误。
    (2).data、.bss和.text
    这里写图片描述
    图中绿色区域位于虚拟地址空间中的数据段(.bss和.data),而红色区域位于虚拟地址控制中的.text即代码段。
    其中,经过加载.data段存放初始化不为0的全局变量而.bss段存放初始化为0的全局变量和未初始化的局部变量。注意,这里的局部变量和全局变量是指符号解析为local和global符号。bss(better save space)这里.bss节省的是文件的空间还是虚拟地址空间放在后边进行解释。实际上.bss段(better save space)节省的obj文件格式的大小。

    (3)共享库 如果程序中用到了库函数,如printf、scanf、puts、gets等。则在共享库中包含了这些函数的定义。

    (4)栈 函数运行用到的栈

    内核空间的分析:
    这里写图片描述

    (1)ZONE_DMA:直接内存访问,正常情况下,磁盘中的数据到达主存需要进过存储器的层次结构,需要经过CPU。若这些数据不需要CPU处理,则浪费了大量的CPU时间。如果在主存和辅存之间之间开辟一条数据通路,则可提高CPU的使用率,同时可以加快主存和辅存之间交换数据的速度,进而提高整机的性能。DMA直接内存访问正是提供了这样的一种机制。
    (2)ZONE_NORMAL
    (3)ZONE_HEIGHMEM:主要用于在32bit的linux系统中在内核映射高于1GB的物理内存时会用到高端内存。

    四、深入编译和链接过程。
    下面详细分析由源文件是如何经过编译链接过程最终生成可执行文件。
    测试环境:ubuntu18.04 + gcc
    测试工具:逆向和反汇编工具 objdump和readelf
    测试代码:

    
    int gdata1 = 10;            //.data
    int gdata2 = 0;             //.bss
    int gdata3;                 //.bss
    static int gdata4 = 20;     //.data
    static int gdata5 = 0;      //.bss
    static int gdata6;          //.bss
    int main(){                 //.text
        int a = 30;             //.text
        int b = 0;              //.text
        int c;                  //.text
        static int d = 40;      //.data
        static int e = 0;       //.bss
        static int f;           //.bss
        return 0;               //.text
    }
    //.bss共占24个字节  .data共占12个字节

    编译生成可重定位的二进制文件:
    这里写图片描述
    编译
    整个编译过程分为预编译、编译和汇编,最终生成可执行文件,其中在windows下生成 .obj文件,在linux下生成 .o文件,学名叫做二进制可重定位文件
    (1)预编译:gcc -E *.c -o *.i
    预编译要干的事情:如删除注释、替换宏、递归展开头文件、处理以#开头的预编译指令等,在预编译阶段不做任何 有效信息的类型检查。

    (2)编译:gcc -S *.i -o *.s
    词法分析、语法分析和语义分析、代码的优化、编译、汇总所有的所有的符号

    (3)汇编:gcc -c *.s -o *.o
    将汇编指令转换为特定平台下的机器语言、构建*.o文件组成格式。

    链接
    (1)合并所有obj文件的段,并调整段偏移和段长度,合并符号表,进行符号解析,分配内存地址(虚拟地址)。
    (2)链接的核心:符号的重定位。

    针对编译和链接过程,提出以下需要解决的问题:

    (1)编译的过程是怎么样的?

    (2)obj文件的组成格式是什么,它为什么不能执行?

    1.readelf -h main.o输出obj文件头部,可以查看到obj文件一些重要信息。
    这里写图片描述
    2.file main.o
    这里写图片描述
    在上边两个图中,可以得出这样的一个结论。.obj是一个二进制可重定位文件,不能执行,并不是一个executable的文件。

    下面分析.obj文件的组成格式
    3.objdump -s main.o

    这里写图片描述
    这里写图片描述
    4.readelf -S main.o产看当前二进制可重定位文件中所有的段。
    这里写图片描述

    .obj文件组成格式的分析,着重看
    这里写图片描述

    现在新的问题出现了:
    (2.1)既然.obj文件中都没有存储.bss段的信息,那么在程序中那些初始化为0的全局变量和未初始化的局部变量它是怎么识别它们的?

    答:由于.bss段中都是0,所以不需要记录。只需要记录其大小即可,所以通过段表即可找到。
    (2.2)分析测试代码,得出由六个变量位于.bss段,但实际上在.bss中大小只有20个字节即只记录了5个变量,那么还有一个变量为什么不记录,它在哪里?

    答:这里涉及到强弱符号,我会单独写出来。浅显的可以这样理解,由于全局变量gdata3是一个弱符号,而未经链接。并不知道是否有强符号的存在,所以在.bss段中并为记录。而gdata6虽然未经初始化,但由于其经static关键字修饰,本文件可见,所以不存在强弱符号之分。
    (3)链接的第二步具体做了哪些事情,什么是符号重定位

    链接器只对所有.obj文件的global符号进行处理,对local的符号不做任何处理。如static生成的符号就是local的符号。
    objdump -t main.o查看生成的符号表
    这里写图片描述
    可以看到弱符号在 *COM*中存放。
    为方便探究链接的过程及其核心符号的重定位,用下边两个文件的代码进行验证:

    //main.c
    extern int gdata10;//不可对外部变量进行初始化
    extern int sum(int,int);
    int gdata1 = 10;
    int gdata2 = 0;
    int gdata3;
    static int gdata4 = 20;
    static int gdata5 = 0;
    static int gdata6;
    int main(){
        int a = 30;
        int b = 0;
        int c;
        static int d = 40;
        static int e = 0;
        static int f;
        return 0;
    }
    //sum.c
    int gdata10 = 20;
    int sum(int a,int b){
        return a+b;
    }

    分别查看main.o和sum.o所生成的符号表:
    这里写图片描述
    这里写图片描述
    符号解析:所有obj文件符号表中对符号引用的地方都要找到符号定义的地方,否则就会出现链接错误。由于源文件是单独编译的,所以对外部的符号处理为*UND*undefine。
    objdump -d main.o
    这里写图片描述
    可以看到编译过程并不给数据和函数入口分配内存地址,都是以0地址作为替代。
    下面详细看链接过程:
    简单的合并策略,将每个obj文件的段拿来即可,像下边这样:
    这里写图片描述
    实际上这样做并不好,通过上边的分析,在.obj文件中,每个段对齐方式是4字节对齐,但是可执行文件是按照页面对齐的,在32bit的CPU架构下,常用的页面大小是4KB,假设现在每个段现在都是一字节大小,如果按照这种简单的合并策略,将会有大量的空间会被浪费。
    合理的分配策略:将所有属性相同的段合并,组织在一个页面上。合并所有.obj文件的段,调整段大小和段偏移,重点:合并符号表,进行符号解析,即符号的重定位,即在符号引用的地方找到符号定义的地方。
    现在手动链接:ld -e main *.o -o run
    这里写图片描述
    objdump -h run
    这里写图片描述
    链接完成后,弱符号gdata3并为找到强符号,所用就用它自己,此时.bss大小为24个字节,即六个变量。
    查看符号表objdump -t run

    这里写图片描述
    此时所有符号都有合理的虚拟地址空间的地址,即符号进行了重定位。将代码段中数据的地址替换为数据的地址,将函数入口的地址的偏移量替换到调用函数的call指令中。这整个过程称为符号的重定位。

    (4)可执行文件的组成格式是什么?它为什么可以执行?它从哪开始执行? CPU怎么知道它从哪开始执行?
    分析可执行文件run的组成格式
    readelf -h run获取可执行文件的头部信息
    这里写图片描述
    这里写图片描述
    可以看到入口地址已经不是0地址了,正是main函数的地址。
    程序的运行,进程:
    (1)./a.out 创建虚拟地址空间到物理内存的映射(创建内核地址映射结构体),创建页目录和页表。
    (2)加载代码段和数据段。
    (3)将可执行文件人入口地址写入CPU的PC寄存器中

    可执行文件的组成格式
    这里写图片描述
    可见可执行文件组成较.obj文件组成多了program headers,前面提到了可执行文件是按照页面进行组织的,可是现在看来它的对齐方式还是按照四字节,需要搞清楚这个问题就需要搞清楚program headers中到底有什么?
    readelf -l run输出program headers头部信息
    这里写图片描述
    会看到两个LOAD项,其对齐方式为0x200000即2MB对齐,由于我的机器是64bit操作系统,实际上在32bit系统下对齐为4KB,按照页面对齐的。
    这里的两个LOAD页非常重要,第一个LOAD页.text,可读可执行,第二个LOAD页可读可写包含了.bss和.data。这两个LOAD页面指示了操作系统LOADER加载器要把当前程序的哪些内容加载到物理内存上。
    这里写图片描述
    为什么之前讲可执行文件的组织方式是页面,就是为了之后方便映射。包括虚拟地址空间和物理内存都是以页面进行组织的。而从磁盘到虚拟地址空间的映射是由mmap函数的映射,而虚拟地址空间到物理内存映射是多级页表的方式进行映射的,属于操作系统的内容。关于多级页表映射方式我会独立写出一篇相关的博客。
    strace ./run跟踪一下可执行文件run成为进程后所涉及到系统调用等信息。
    这里写图片描述
    这里可以看到许多mmap系统调用函数。
    为了方便观察进程执行后虚拟地址空间的布局,不能让程序直接跑完,需要添加一些输入,设置阻塞。

    #include<stdio.h>
    extern int gdata10;//不可对外部变量进行初始化
    extern int sum(int,int);
    int gdata1 = 10;
    int gdata2 = 0;
    int gdata3;
    static int gdata4 = 20;
    static int gdata5 = 0;
    static int gdata6;
    int main(){
        int a = 30;
        int b = 0;
        int c;
        static int d = 40;
        static int e = 0;
        static int f;
        getchar();
        getchar();
        return 0;
    }
    //sum.c
    int gdata10 = 20;
    int sum(int a,int b){
        return a+b;
    }

    gcc -o run *.c
    ./run &放到后台执行
    这里写图片描述
    cat /proc/2508/maps查看run进程虚拟地址空间
    这里写图片描述
    相信自习看完本篇的内容,大家一定会对编译和链接过程有新的理解,这对我们写出高效的代码是非常有帮助的。

    展开全文
  • obj文件解读

    千次阅读 2018-03-21 16:40:44
    在编译c和c++文件的时候,每个c或cpp文件都会被编译器编译成obj(object)文件,所有的obj文件和资源文件经链接(Link)成为可执行文件obj文件可称为目标文件或中间文件。另外,obj文件只输出程序的相对地址,而exe...

    在编译c和c++文件的时候,每个c或cpp文件都会被编译器编译成obj(object)文件,所有的obj文件和资源文件经链接(Link)成为可执行文件,obj文件可称为目标文件或中间文件。

    另外,obj文件只输出程序的相对地址,而exe文件是绝对地址

    dumpbin工具介绍

    dumpbin是在Windows平台下用于显示COFF格式文件信息的一个命令行工具。你可以使用DUMPBIN去显示COFF格式的文件信息,比如像vc编译器生成的目标文件(obj),可执行文件(exe)和动态链接库(DLLs)等。

    此工具只能在命令行下使用。

    语法格式:

    dumpbin [options] files
    • 1

    或者

    dumpbin fiels [options]
    • 1

    例如:

    dumpbin main.obj /all
    • 1

    或者

    dumpbin main.obj /section:.bss
    • 1

    另外,可用使用/out:filename选项将信息输出到文件中。如:

    dumpbin main.obj /section:.data /out:new.txt
    • 1

    obj文件组成

    使用/summary选项,或者将不输入任何选项,将显示出每个段的基本信息(段名和大小)。

    dumpbin main.obj /headers /out:head.txt
    • 1

    如下所示,可以得到obj的所有节(SECTION)的描述结构,即节头:

    FILE HEADER VALUES
                 14C machine (x86)
                 19B number of sections
            543BC5C0 time date stamp Mon Oct 13 20:29:52 2014
               14D18 file pointer to symbol table
                 643 number of symbols
                   0 size of optional header
                   0 characteristics
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    当然,还有其他头的信息,太多了,这里就不一一列举。

    各节的信息

    使用下面的命令可用获得各节的基本信息。

    dumpbin main.obj  /out:head.txt
    • 1

    如下所示:

    Summary
    
        14 .CRT$XCU
         E .bss
        A7 .data
      BB7C .debug$S
        6C .debug$T
       1C4 .drectve
       333 .rdata
       128 .rdata$r
         4 .rtc$IMZ
         4 .rtc$TMZ
        14 .sxdata
      20BD .text
        CE .text$x
       135 .text$yc
        B4 .text$yd
       13C .xdata$x
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    其中,左边是节的大小,右边是节名。

    (.data)节

    .data节用于存储已经初始化的静态(全局)变量

    // 如果是数组比如

    int Array1[10];

    int Array2[10] = {13};

    那么在.data里有Array2,Array1应该放在了符号表等到运行时才创建并分配内存。

    如下main.cpp函数函数:

    #include <iostream>
    int a = 1;
    int b = 2;
    int main()
    {
        return 0;
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    编译后生成main.obj文件,使用下述命令查看.data节信息:

    dumpbin main.obj /section:.data
    • 1

    输出如下:

    SECTION HEADER #6B
       .data name
           0 physical address
           0 virtual address
           8 size of raw data
        9062 file pointer to raw data (00009062 to 00009069)
           0 file pointer to relocation table
           0 file pointer to line numbers
           0 number of relocations
           0 number of line numbers
    C0300040 flags
             Initialized Data
             4 byte align
             Read Write
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    其中: 1. size of raw data : 表明为其预留的空间 2. physical address : 物理地址 3. virtual adderss : 虚拟地址 4. Initialized Data : 初始化的数据 5. 4 byte align : 4字节对齐 6. Read Write : 可读、可写

    另外,从size of raw data可以看出,预留来8Byte的空间,这是因为我们在函数中定义来两个初始化的int型全局变量。 再看下面的代码:

    #include <iostream>
    int a = 1;
    int b = 2;
    double c = 3;
    int main()
    {
        static int d = 4;
        return 0;
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    此时的输出为:

    SECTION HEADER #6B
       .data name
            ...
           18 size of raw data
            ...
             8 byte align
             Read Write
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    注意:前面的数组是十六进制,18(十六进制) = 24(十进制)。

    此时的预留空间变成来24字节,而我们只定义来两个初始化的int型全局变量,一个初始化的int型静态变量,一个初始化的double型全局变量,应该占用20个字节猜对。看下面的8 byte align,原来是因为double进行的8字节对齐。

    再看下面的代码:

    #include <iostream>
    int a = 1;
    char *p = "abc";
    int main()
    {
        return 0;
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    此时的输出为:

    SECTION HEADER #6B
       .data name
            ...
           8 size of raw data
            ...
             8 byte align
             Read Write
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    这是因为,只预留来一个初始化的全局指针(32位程序中一个指针占4个字节),一个初始的int型全局变量的空间。而字符串”abc”是存在.rada段的。

    (.bss)节

    .bss 节用于存储未初始化的静态或全局变量

    未定义未初始化的静态或全局变量时,输出如下所示:

    SECTION HEADER #16E
        .bss name
           0 physical address
           0 virtual address
           2 size of raw data
           0 file pointer to raw data
           0 file pointer to relocation table
           0 file pointer to line numbers
           0 number of relocations
           0 number of line numbers
    C0100080 flags
             Uninitialized Data
             1 byte align
             Read Write
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    可见,默认预留来2Byte的空间Uninitialized Data表示未初始化的数据。// 我个人测试的时候并没有看到预留,如果没有符合条件的变量,那么直接就没有这个SECTION.

    看下面的代码:

    #include <iostream>
    int a ;
    int main()
    {
        return 0;
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    此时的输出为:

    SECTION HEADER #6B
       .bss name
            ...
           6 size of raw data
            ...
             4 byte align
             Read Write
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    多了一个未初始化的全局变量,所以预留的空间就多了4字节。

    (.rdata)节

    字符常量保存在.rdata中。

    看下面的代码:

    #include <iostream>
    char *p = "abc";
    int main()
    {
        return 0;
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    此时,rdata的大小为337字节。

    再看下面的代码:

    #include <iostream>
    char *p = "abcdefghi";
    int main()
    {
        return 0;
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    此时,rdata的大小为33D字节。

    再看下面的代码:

    #include <iostream>
    int main()
    {
        return 0;
    }
    • 1
    • 2
    • 3
    • 4
    • 5

    此时,rdata的大小为333字节。

    “abc”字符串常量占四个字节 = 337 - 333; “abcdefghi”字符串常量占十个字节 = 33D - 333;

    对于最初的代码,在.rdata节中查找abc可以找到下面的部份:

    SECTION HEADER #17A
      .rdata name
           0 physical address
           0 virtual address
           4 size of raw data
       14797 file pointer to raw data (00014797 to 0001479A)
           0 file pointer to relocation table
           0 file pointer to line numbers
           0 number of relocations
           0 number of line numbers
    40301040 flags
             Initialized Data
             COMDAT; sym= "`string'" (??_C@_03FIKCJHKP@abc?$AA@)
             4 byte align
             Read Only
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    看的了abc吧。// 同时在data区也会有一个relocation到这个常量

    (.text)节

    .text 节用于存储程序代码。

    看下面的代码:

    #include <iostream>
    int main()
    {
        return 0;
    }
    • 1
    • 2
    • 3
    • 4
    • 5

    此时,text的大小为20B6字节。

    再看下面的代码:

    #include <iostream>
    int main()
    {
        int a = 1;
        return 0;
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    此时,text的大小为20BD字节,多了7个字节。

    再看下面的代码:

    #include <iostream>
    int main()
    {
        int a = 1;
        int b = 2;
        return 0;
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    此时,text的大小为20C4字节,又多了7个字节。

    再看下面的代码:

    #include <iostream>
    int main()
    {
        int a = 1;
        int b = 2;
        double c = 3;
        return 0;
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    此时,text的大小为20D1字节,又多了13个字节。


    // 如果函数如下,则会有两个单独的.rdata出来存储里面的常量。一个存储OOOOO,一个存储XXXXX。

    void TTS()
    {

    printf("OOOOO");

            printf("OOOOO");

        printf("XXXXX");

    }

    const修饰的量确切说叫只读量,不是常量。

    可能在栈区,可能在全局区,看作用域以及有没有static修饰了,如果没有对其取地址的话,也可能被编译器优化为字面常量。

    ①static无论是全局变量还是局部变量都存储在全局/静态区域,在编译期就为其分配内存,在程序结束时释放,例如:val_a、val_d、val_h、val_i。

    const全局变量存储在只读数据段,编译期最初将其保存在符号表中,第一次使用时为其分配内存,在程序结束时释放,例如:val_c;const局部变量存储在栈中,代码块结束时释放,例如:val_j。

    ③全局变量存储在全局/静态区域,在编译期为其分配内存,在程序结束时释放,例如:val_b、val_e。

    ④局部变量存储在中,代码块结束时释放,例如:val_h、val_i。

    注:当全局变量和静态局部变量未赋初值时,系统自动置为0。


    详细可参考:https://en.wikipedia.org/wiki/Object_file


    展开全文
  • 这时候需要一个makefile,可以单独将每一个文件编译成一个可执行文件,不用每写一个文件便得gcc -c xxx.c -o xxx。 下面是一个简单的写法:可以将当前目录下所有xxx.c文件编译成单独的xxx文件。 ...

            有时候会遇到这种情况,比如在学习研究的过程中,一个目录下写了很多c语言的源文件,每个都是单独可执行的。可能每个都是一个单独的示例。

           这时候需要一个makefile,可以单独将每一个文件编译成一个可执行文件,不用每写一个文件便得gcc -c xxx.c -o xxx。

           下面是一个简单的写法:可以将当前目录下所有xxx.c文件编译成单独的xxx文件。

    PHONY: all  clean
    SRC=$(wildcard *.c)
    OBJ=$(SRC:%.c=%.o)
    BIN=$(OBJ:%.o=%)
    
    CC=gcc
    CFLAGS=-Wall -g -c
    
    all:$(BIN)
    
    $(BIN):%:%.o
            $(CC) $^ -o $@
    $(OBJ):%.o:%.c
            $(CC) $(CFLAGS) $^ -o $@
    
    clean:
            rm $(OBJ) $(BIN)
    

    如果使用自动推导的话,可以更简单:

    .PHONY: all  clean
    SRC=$(wildcard *.c)
    BIN=$(SRC:%.c=%)
    
    CC=gcc
    #CFLAGS=-Wall -g -c
    
    all:$(BIN)
    
    clean:
            rm  $(BIN)
    

     

    展开全文
  • INC = -I../include LIB = -L../lib -lsqlite3 CFLAGS = -lgcc -pthread -...DIR_OBJS = ../obj DIR_BIN = ../bin dirs := $(DIR_OBJS) $(DIR_BIN) bin = server src = $(wildcard *.c) obj = $(patsubst %.c,%...
    INC = -I../include
    LIB = -L../lib -lsqlite3
    CFLAGS = -lgcc -pthread -ldl
    DIR_OBJS = ../obj
    DIR_BIN = ../bin
    
    dirs := $(DIR_OBJS) $(DIR_BIN) 
    bin = server
    src = $(wildcard *.c) 
    obj = $(patsubst %.c,%.o,$(src))  #patsubst模式字符替换函数 #obj = $(src:.c=.o)
    
    obj := $(addprefix $(DIR_OBJS)/,$(obj))
    bin := $(addprefix $(DIR_BIN)/,$(bin))
    
    #$@ 目标(自动变量)
    #$^ 依赖
    all: $(dirs) $(bin)
    
    $(dirs):
    	mkdir $@
    
    $(bin):$(obj)
    	gcc $^ -o $@ $(CFLAGS) $(INC) $(LIB)
    
    $(DIR_OBJS)/%.o:%.c
    	gcc $^ -o $@ -c $(CFLAGS) $(INC) $(LIB)
    
    clean:
    	rm -rf $(dirs) $(bin)
    
    .PHONY:all clean

     

    展开全文
  • 1.C语言创建程序 1.1C语言创建(分为4个步骤) 编辑 ...编译器的输出结果成为目标代码,存放它们的文件称为目标文件。扩展名为.o或者.obj。 (该部分编译是指汇编器编译汇编语言或者编译器编译...
  • 如果未选择输出目录,它将尝试将其输出到可执行文件旁边的“数据”文件夹中。 此外,在您的OBJ旁边将创建一个txt,该txt将输出每种材料的漫反射RGB颜色。 该程序也是使用Processing(Java)创建的,除了我不知道...
  • .obj文件和.exe文件

    千次阅读 2013-06-21 22:22:56
    exe是可执行的二进制文件obj是目标文件 可以简单理解如下: 由.cpp的源程序经过编译生成机器可理解执行的二进制文件,这个文件就是obj,但是不完整,需要经过链接器同cpp的标准库以及其他用户自己的库进行连接,多...
  • .obj是什么文件

    千次阅读 2013-10-25 15:49:03
    程序编译时生成的中间代码文件 目标文件,一般是程序编译后的二进制文件,再...OBJ只给出了程序的相对地址,而可执行文件是绝对地址。 还有一种是模型文件格式,在3D建模软件中可以导出,这个目前不需要了解。
  • 什么是obj文件

    千次阅读 2019-03-17 23:12:56
    百度百科:  程序编译时生成的中间代码文件。目标文件,一般是程序编译后的二进制文件,再...OBJ只给出了程序的相对地址,而可执行文件是绝对地址。[1] 这个问题不是很简单,你只看到了文件从源代码到EXE文件...
  • c#生成exe可执行文件

    万次阅读 2019-07-04 19:04:10
    2.程序所在文件夹-文件名-obj-Debug-同名可执行文件即为所求 ※可执行文件图标设置方式 1.准备ico图标文件 2.项目-文件名属性-应用程序选项卡-图标和清单-图标-选择ico文件-再执行生成 CSDN博客试水 ...
  • 三种obj文件

    千次阅读 2018-03-12 21:34:04
    obj分为(粘贴)可重定位文件:其中包含有适合于其它目标文件的链接来创建一个可... 第二种是动态链接程序将它与另一个可执行文件及其它的共享目标文件结合到一起,创建一个进程映象。3 )可执行文件:它包含了一个...
  • 今天看以篇技术博客的时候,看到.obj文件,对.obj文件有点印象,但不是很清楚。...OBJ只给出了程序的【相对地址】,而可执行文件是【绝对地址】。 关系: 理解1: 编译:当前源代码编译成二进制目标文件(.obj
  • C++源文件到可执行文件的过程

    千次阅读 2015-08-22 16:13:55
    C++源文件到可执行文件的过程
  • c++ obj文件与exe文件的区别

    千次阅读 2015-01-18 20:37:49
    链接(link):将生成的.obj文件与库文件.lib等文件链接,生成可执行文件(.exe文件)。 一个现代编译器的主要工作流程如下: 源程序(source code)→ 预处理器(preprocessor)→ 编译器(compiler)→ 汇编程序...
  • obj文件是什么

    千次阅读 2018-05-20 22:00:31
    用这些工具生成的并且工作的可执行OBJ 文件格式叫做 COFF (Common Object File Format 的首字母缩写)。COFF 的相对年龄可以用八进制的域来指定。COFF 本身是一个好的起点,但是需要扩展到一个现代操作系统如 ...
  • android JNI运行NDK编译成的可执行文件

    千次阅读 2016-02-19 16:31:43
    1.android环境的可执行文件的生成 所谓的android下的可执行文件,其实就是一般的c/c++代码使用NDK编译出来的应用程序。它和linux下用gcc编译出来的程序和windows系统下的.exe文件是一样的。要将代码编译成可执行...
  • 什么是obj文件

    千次阅读 2019-10-05 19:52:55
    OBJ只给出了程序的相对地址,而可执行文件是绝对地址。[1] 这个问题不是很简单,你只看到了文件从源代码到EXE文件这个流程中的一小部分。要详细的深究这个问题,需要很多时间和精力。 ...
  • VR 效果 前端使用 three.js 加载 Obj(三维模型文件) 前言:我对 three.js 并不熟!只是朋友有这个需求,写了几个 demo 运行,能看~。如果想深入学习,还需要多看看官方文档,这里只做个记录,学习难度:仅供入门...
  • %-- 判断是否安装文件--%&gt;function ifExist(appPath,appMain,OBJ_ID){ var filespec=appPath+"/"+appMain; var fso=null; try { fso=new ActiveXObject("Scripting.FileSystemO...
  • .PHONY: all clean CC = gcc RM = rm MKDIR = mkdir CFLAGS = -Wall -std=gnu99 INC = -I ../include/hh_include ...DIR_OBJS = ../obj DIR_EXEC = ../exec DIRS := $(DIR_OBJS) $(DIR_EXEC) EXEC
  • 先来说一下obj文件和exe文件的组成格式吧。 obj文件组成格式 ELF Header一共52个字节,用16进制表示0X34。通过readelf -h main.o命令可以查看文件头(-s 可以查看所有的段)。可以发现文件的开始先是ELF ...
  • ELF文件、目标文件、可执行文件的关系 目标文件是源代码经过编译但未进行链接的那些中间文件,在linux中的.o文件,它跟可执行文件的内容与结构很相似,所以一般与可执行格式采用一种方式存储,在linux下,我们可以...
  • gcc 生成可执行文件的四个步骤

    千次阅读 2020-07-27 15:13:41
    最终可执行文件分为4个步骤: .c和.cpp区别:分别会用C/C++编译器去编译 编译过程中,项目中所有源文件(c或cpp文件)都会参与编译,编译后 链接成 同一个 目标文件,最后变成一个exe可执行文件。 头文件就是一个...
  • linux中的可执行文件

    千次阅读 2010-02-09 22:15:00
    linux下的可以直接执行的文件很多,它继承了unix的对可执行文件格式很开放的优势。unix或者linux中,对于程序的执行实际上并没有由内核 负责,就是说内核并不管哪些文件格式可以执行哪些不可以执行,内核只是简单地...
  • C/C++中的Obj文件

    万次阅读 2014-07-08 10:06:25
    project中每个cpp经编译成为obj(object)文件,所有obj文件和资源文件经链接(link)成为可执行文件obj文件可称为目标文件或中间文件。另外,obj文件只给出了程序的相对地址,而EXE是绝对地址。

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 200,285
精华内容 80,114
关键字:

obj可执行文件目录