【Linux】基础开发工具使用 --- gcc

  • 阿里云国际版折扣https://www.yundadi.com

  • 阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

    目录

    预处理

    编译

    汇编

    链接

    函数库

    协助记忆


    🧋GCCGNU Compiler Collection是由GNU开发的编程语言编译器。GNU编译器套件包括C、C++、 Objective-C、 FortranJavaAdaGo语言前端也包括了这些语言的库如libstdc++libgcj等。说那么多就是一个编译器。平时写完的程序就是需要编译之后才能运行。

    🧋之前讲过程序的预处理但之前限制于环境问题无法讲得透彻与直观。在 Linux 中学习 gcc 后我们终于可以清楚地观察到程序转换至可执行文件时的过程了。

    🧋我们都知道程序要尽量四个步骤才能转换成可执行文件根据 gcc 的不同选项我们可以得到不同阶段下的文件。

    预处理

    gcc -E -o printf.i printf.c   //-o后跟着的始终为要生成的文件
    

    🧋选项“-E”,该选项的作用是让 gcc 在预处理结束后停止编译过程选项 “-o” 之后总是跟着生成的目标文件输入这串命令gcc 会自动将程序编译到相应的阶段此时的文件后缀为  .i  

     🧋可以看到注释的部分被删去并且多出来八百多行的代码就是源程序文件将头文件展开后的结果。

    编译

    gcc -S -o printf.s printf.i
    

    🧋带上选项 "-S" , gcc 自动将文件编译到编译环节结束此时的文件的内容已变成了汇编语言同时文件的后缀为 .s

      1   .file "printf.c"                                                                                                                                         
      2   .section  .rodata
      3 .LC0:
      4   .string "hello world"
      5   .text
      6   .globl  main
      7   .type main, @function
      8 main:
      9 .LFB0:
     10   .cfi_startproc
     11   pushq %rbp
     12   .cfi_def_cfa_offset 16
     13   .cfi_offset 6, -16
     14   movq  %rsp, %rbp
     15   .cfi_def_cfa_register 6
     16   movl  $.LC0, %edi
     17   call  puts
     18   movl  $.LC0, %edi
     19   call  puts
     20   movl  $.LC0, %edi
     21   call  puts
     22   movl  $.LC0, %edi
     23   call  puts
     24   movl  $0, %eax
     25   popq  %rbp
     26   .cfi_def_cfa 7, 8
     27   ret
     28   .cfi_endproc
     29 .LFE0:
     30   .size main, .-main
     31   .ident  "GCC: (GNU) 4.8.5 20150623 (Red Hat 4.8.5-44)"
     32   .section  .note.GNU-stack,"",@progbits
    
    

     汇编

    gcc -c -o printf.o printf.s

    🧋使用 “-c” 选项使文件编译到汇编结束停止经过汇编后文件已由原来的汇编代码转换成二进制文件了后缀为 .o 直接看的话会发现就是一堆乱码。

    🧋并且这个文件目前仍无法运行若强制访问也会被拒绝。

    [Alpaca@VM-12-9-centos ~]$ ./printf.o
    -bash: ./printf.o: Permission denied
    

    链接

    gcc -o printf printf.o   //从.o文件开始编译
    gcc -o printf printf.c   //从头开始编译

    🧋这一步结束后整个编译环节就算结束了即从头到尾编译因此不用带选项就能达到目的效果。生成的文件就可以直接执行了。

    [Alpaca@VM-12-9-centos ~]$ ./printf
    hello world
    hello world
    hello world
    hello world
    

    函数库

    🧋在链接的时候我们所用到的函数并不完全是我们自己的因此需要与库建立联系从而可以使用库里面的函数。

    🧋函数库又分成了动态库静态库两种动态库又叫共享库其提供的能力是被所有人共享的就像学校外的网吧一样你给了钱就能上网但万一有一天网吧倒闭了所有的学生都不能去那家网吧上网了。

    🧋而静态库则是将你所需要的库中的代码拷贝到自己本地的文件中。就像自己的电脑即便外面的网吧倒闭了你仍然可以照常上网

    [Alpaca@VM-12-9-centos ~]$ ldd printf
    	linux-vdso.so.1 =>  (0x00007ffdf3584000)
    	libc.so.6 => /lib64/libc.so.6 (0x00007f1d8a320000)
    	/lib64/ld-linux-x86-64.so.2 (0x00007f1d8a6ee000)
    
    [Alpaca@VM-12-9-centos ~]$ file printf
    printf: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=ab832f77ec91a8a75cf4d749ef046741e5abf2bc, not stripped

    🧋我们有两种方法来判断这个可执行文件是动态链接的还是静态链接的第一就是使用 ldd 来查询函数的所属关系当文件是 lib 开头后缀为 .so 则表明是依赖的是动态库若后缀为 .a 则说明其依赖的是静态库。第二种方法就是使用 file 命令可以细致地观察文件的属性在这里便可以看到该文件是由动态库链接而成的。

    gcc -static -o printf-static printf.c

    🧋 Linux 下是默认使用动态链接的但我们可以使用这个命令进行静态链接。之后查询出的文件的数据类型就表明其是由静态链接构成的了。

    [Alpaca@VM-12-9-centos ~]$ file printf-static
    printf-static: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, for GNU/Linux 2.6.32, BuildID[sha1]=9444d246f27ba1fed466fb, not stripped
    

    🧋但由此我们可以明显地看出二者不同链接方式之间的区别静态链接生成的文件所占的空间远大于动态链接的更加地浪费空间。所以正常情况下还是使用动态链接较好。

    [Alpaca@VM-12-9-centos ~]$ ll
    -rwxrwxr-x 1 Alpaca Alpaca   8361 Jan 11 21:54 printf
    -rwxrwxr-x 1 Alpaca Alpaca 861288 Jan 11 23:45 printf-static
    

    协助记忆

    🧋预处理、编译、汇编三个阶段所对应的选项分别是 “E” "S" "c" , 刚好就是键盘左上角那个 “Esc” 只不过中间的 s 需要改成大写。同时其所对应的文件后缀为 “.i” 、“.s” 、“.o” 就是 “iso” 。只要稍微用一些方法来记忆之间的区别相信很快就能熟练起来。

    好了这次gcc的介绍就到这里结束了关注博主共同进步

  • 阿里云国际版折扣https://www.yundadi.com

  • 阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
    标签: linux