linux下C程序从编写到执行完整过程

vim掉电模式

一般编写代码过程中,电脑或者服务器可能会出现挂机现象,linux下智能保存程序文件,生成.swp临时文件,该文件为隐藏文件。

vim一般操作

set nu/nonu 	 						//显示行号/不显示行号
:32 		    						//跳转到32行
gn 选中后 n 向下寻找 N向上寻找相同单词 	//高亮所选单词
%s/ABC/abc/g 带上g代表全部替换 			// 将ABC替换成abc
%  					//{},()匹配
gcc -c  			//调试
gdb a.out  			//gdb模式
b20  				//设置断点
s    				//单步调试

C程序完整过程

1.编译

A.编译的概念

编译程序读取源程序(字符流),对之进行词法和语法的分析,将高级语言指令转换为功能等效的汇编代码,再由汇编程序转换为机器语言,并且按照操作系统对可执行文件格式的要求链接生成可执行程序。

B.编译的过程

  1. C源程序预编译处理(.c)
  2. 编译、优化程序(.s、.asm)
  3. 汇编程序(.obj、.o、.a、.ko)
  4. 链接程序(.exe、.elf、.axf等)

C.gcc命令

gcc -E hello.c -o hello.i

2.优化

预处理

作用:解决定义可能出现的问题,排除伪指令。

三大方面:

  1. 宏定义指令,如#define Name TokenString,#undef以及编译器内建的一些宏,如__DATE__,FILE, LINE, TIME,FUNCTION 等。
  2. 条件编译指令,如#ifdef,#ifndef,#else,#elif,#endif等。
  3. 头文件包含指令,如#include "FileName"或者#include 等。

其他优化

  1. 删除公共表达式
  2. 循环优化(代码外提、强度削弱、变换循环控制条件、已知量的合并等)
  3. 复写传播
  4. 无用赋值的删除等等

3.汇编

过程分析:

把汇编语言代码翻译成目标机器指令的过程。 经过这一处理而得到相应的目标文件。目标文件中所存放的也就是与源程序等效的目标的机器语言代码。

gcc命令

gcc –c hello.s –o hello.o 

4.链接

产生原因:

通过汇编程序产生的目标文件不能立即被执行,需要一些相关函数或者变量的调用。例如,函数的调用需要定义声明编写,如果多个文件需要用到同一函数(如print函数),不仅造成系统内存资源浪费,还造成程序累赘。若将常用的函数集中封装在一个库内,通过调用库内函数直接使用。链接程序随之产生。

gcc命令

gcc –c hello.s –o hello.o 

链接处理:

1.静态链接

-static静态链接
--static静态编译          不需要库可执行

2.动态链接

特点:可执行文件比较短小,节约一些内存
找不到通过环境变量告诉系统库位置或者直接告诉位置

3.动态库

这类库的名字一般是libxxx.a;利用静态函数库编译成的文件比较大,因为整个函数库的所有数据都被整合进目标代码中即编译后的执行程序不需要外部的函数库支持,因为所有使用的函数都已经被编译进可执行文件了
静态库制作:

gcc -c file1.c
gcc -c file2.c
....
gcc -c fileN.c
ar -rcs  libname.a   file1.o  file2.o  ... fileN.o

4.静态库

这类库的名字一般是libxxx.so,动态库又称共享库;相对于静态函数库,动态函数库在编译的时候并没有被编译进目标代码中,你的程序执行到相关函数时才调用函数库里的相应函数,因此动态函数库所产生的可执行文件比较小

动态库制作:

gcc -shared  -fpic  -o libname.so  file1.c  file2.c ... fileN.c

5.编译生成:

gcc main.c -o  test_lib   -L lib_path  -lname

6.出错分析

编译出错:undeclared等等语法错误
链接出错:undefined reference(找不到链接里的函数,链接出错) -wall//ld(链接出错标志) returned 1 exit status

5.编译执行

a.编译:

gcc main.c

错误main.c:14:20: error: crypto.h: No such file or directory-I 指定头文件的路径

b.链接:

gcc -static  main.c -o app -L./libs -lcrypto -lfunc
/tmp/ccfrMcUo.o: In function `main':
main.c:(.text+0xa): undefined reference to `crypt0'
collect2: ld returned 1 exit status

-L 指定库的路径 -l 指定库的名字 -I 指定头文件路径
动态库和静态库同时存在,默认是使用动态库。如果要用静态库,加上-static链接选项。

c.运行:

./app 
./app: error while loading shared libraries: 
libfunc.so: cannot open shared object file: No such file or directory

LD_LIBRARY_PATH: 告诉系统执行程序的时候,除了/lib, /usr/lib以外还到哪里找动态库。
PATH: 告诉系统执行的Linux命令查找的路径

6.Linux 进行动态链接

当用户启动一个应用程序时,内核首先将 ELF 映像加载到用户空间虚拟内存中,然后内核会注意到一个称为 .interp 的 ELF部分,它指明了将要被使用的动态链接器(/lib/ld-linux.so),这与脚本文件的解释器定义(#!/bin/sh)很相似。

ld-linux.so 本身就是一个 ELF共享库,但它是静态编译的并且不具备共享库依赖项。当需要动态链接时,内核会引导动态链接(ELF解释器),该链接首先会初始化自身,然后加载指定的共享对象(已加载则不必)。接着它会执行必要的再定位,包括目标共享对象所使用的共享对象。

LD_LIBRARY_PATH 环境变量定义查找可用共享对象的位置。定义完成后,控制权会被传回到初始程序以开始执行。

再定位是通过一个称为 Global Offset Table(GOT)和 Procedure Linkage Table(PLT)的间接机制来处理的。这些表格提供了 ld-linux.so在再定位过程中加载的外部函数和数据的地址。这意味着无需改动需要间接机制(即,使用这些表格)的代码:只需要调整这些表格。一旦进行加载,或者只要需要给定的函数,就可以发生再定位(稍候在用 Linux 进行动态加载 小节中会看到更多的差别)。

再定位完成后,动态链接器就会允许任何加载的共享程序来执行可选的初始化代码。该函数允许库来初始化内部数据并备之待用。这个代码是在上述ELF 映像的 .init 部分中定义的。在卸载库时,它还可以调用一个终止函数(定义为映像的 .fini部分)。当初始化函数被调用时,动态链接器会把控制权转让给加载的原始映像。

你可能感兴趣的:(liunx开发学习笔记)