linux相关的知识点

来源:互联网 发布:娱乐圈爆料知乎天涯 编辑:程序博客网 时间:2024/05/17 22:20

1.在linux C文件的gcc编译过程

编译——>可执行文件

      -E(预编译)                        -S(汇编)                   -c                                  ld

.c—————————>.i——————————>.s————————>.o————————> ELF文件(可执行文件) ,默认名为a.out

                                                                                                        目标文件

(1)预编译过程 $gcc -E  test.c  -o test.i

a)处理#开头的指令

#include “” <>,把include的头文件copy到当前行

#define的宏简单替换

处理条件编译(#ifdef  #ifndef #if)

b)替换NULL为0

c)删除注释

 

(2)汇编 $gcc -S test.c -o test.s

 

(3)链接

静态编译:首先创建静态库,在主文件编译生成.o之后,在链接时把函数的实现复制过来.(编译后的可执行文件会比动态编译大很多)

step1:$gcc -c struct.c //生成目标文件struct.o

step2:$ar cqs libstruct.a struct.o (顺序不能乱)//创建静态库

step3:$gcc main.c -static -L . -l struct -o main//链接静态库,生成可执行文件

动态编译:首先创建动态库,在主程序文件编译生成.o之后,在链接时记录函数的地址,当运行时才会根据地址查找函数

step1:$gcc struct.c -fPIC -shared -o libstruct.so//创建动态库

step2:$gcc main.c -L . -l struct -o main//链接动态库,生成可执行文件

step3: Linux动态库的默认搜索路径是/lib和/usr/lib。动态库被创建后,一般都复制到这两个目录中。当程序执行时需要某动态库,并且该动 态库还未加载到内存中,则系统会自动到这两个默认搜索路径中去查找相应的动态库文件,然后加载该文件到内存中,这样程序就可以使用该动态库中的函数,以及 该动态库的其它资源了。在Linux 中,动态库的搜索路径除了默认的搜索路径外,还可以通过三种方法来指定,一下只介绍一种,其他可以去找百度

          设置库文件的环境路径

         1)在bashrc或profile文件里用LD_LIBRARY_PATH定义,然后用source加载。

         2)把库路径添加到ld.so.conf文件中,然后用ldconfig加载。

         3)ldconfig /home/user/lib,仅能暂时性使用,若下次ldconfig时此目录下的动态链接库就不能被共享了


以上两者的优缺点:

动态编译优点是可执行文件本身体小,编译速度快;

              缺点是哪怕一个简单的程序,只要使用到动态库一两条命令,也要附带一个相对比较庞大的动态库,

             若机子上没有安装需要链接的动态库,动态编译的执行文件就不能执行了

静态编译的优点和缺点正好和动态编译的互补.


自动链接标准C库


上面使用gcc的一些参数解析:

-shared:指定生成动态链接库。

-static:指定静态链接。

-fPIC:表示编译为位置独立的代码,用于编译共享库。目标文件需要创建成位置无关码,概念上就

是在可执行程序装载它们的时候,它们可以放在可执行程序的内存里的任何地方。

-L .:表示要连接的库在当前目录中。

-l:指定链接时需要的动态库。(编译器查找动态连接库时有隐含的命名规则,即在给出的名字前面加

上lib,后面加上.so来确定库的名称)。

当Linux静态库和Linux动态库同名时, gcc命令将优先使用动
态库。


 

2.Linux地址空间划分

32位机(cpu 的位数为32)地址空间大小为4G(32位机的寻址空间为0x0~0xFFFFFFFF,大小为4G)该地址空间为虚拟地址空间.

 

在linux系统,将其中的0~3G称为用户空间(user space),3~4G称为内核空间(kernel space). 如下图所示,

每个进程的地址空间都是0~4G,每个进程3~4G的地址空间都是相同的.

 

4G —————-—— 0xFFFFFFFF

        kernel Space
3G ———————- 0xC0000000

         stack
      ---------------------- 这个分割不是严格的,why?

         heap
      _____________
 
         data
     ______________

         text
0G _____________0x0

(1)地址映射(va->pa)

内核空间的地址映射,是简单的线性映射:物理地址 = 虚拟地址 - PAGE_OFFSET   (PAGE_OFFSET = 0xc0000000)

用户空间的地址映射,是通过分页机制完成,可以深入研究!!!!!奋斗奋斗奋斗

 

(2)用户空间和内核空间的通信:系统调用

 

(3)用户空间和内核空间的区别?

其实区别是很多,如打印函数,在内核空间用printk,在用户空间用printf;

待补充!!!!!奋斗奋斗奋斗

 

(4)如何判断一个驱动是内核空间驱动还是用户空间驱动? 判断标准是什么?

用户空间的驱动是通过系统调用来完成对硬件的访问.

判断标准就是系统调用

 

(5)用户空间

3G ———————-———————————————0xC0000000

         stack(局部变量、函数参数)
      ------------------------------------------------------------------
这个分割不是严格的,why?

         heap(malloc/free 动态内存分配
)
      ________________________________________
                   

         data ( BSS:初始化为0或未初始化的全局变量

                   data:已初始化且不为0全局变量、static局部变量

                   rodata:const修饰的全局变量

                 )
      _________________________________________

         text
0G _________________________________________0x0


其中data,text段在编译的时候已经确定了,而stack,heap在程序运行时才确定,并且栈和堆的界限不是严格的!
堆是从低地址向高地址扩展;栈是高地址向低地址延伸,一般从3G开始,向低地址延伸。

下面程序中a、b、c、d、e、f、g七个变量分别位于哪个section(段)中?

 int a; int b = 0 ; const int c = 3 ; int d = 4; void foo(long e) { const int f; static int g; // …. }

 a,b在BSS段,c在rodata段,d,g在data段,e,f在栈段

 

 

可以用以下C程序来打印各个Section的地址

#include <errno.h> #define NULL (void *)0 int main(int argc, char *argv[]) {     int a1;     int a2;     static int b;     int *p = (int *)malloc(sizeof(*p));     if (NULL == p) {         perror("malloc()");         return -ENOMEM;     }     printf("stack addr: 0x%08x\n", &a1);     printf("stack addr: 0x%08x\n", &a2);     printf("heap  addr: 0x%08x\n", p);     printf("data  addr: 0x%08x\n", &b);     printf("text  addr: 0x%08x\n", main);     return 0; }

 

 

3.构建一个简单的linux系统,并要在构建的系统上跑madplay

思路:

                cpu
                ||
                ||   bus
=================================
|          |         |         |
disk                DDR       

(1). linux系统程序获取

    system放在disk上,启动计算机时要loader到DDR上才能让系统跑起来
    要操作disk需要有driver,而driver本身又在disk上

    此时就引出Bios
    Bios是对一些硬件进行初始化??????

    MBR


(2). linux系统启动过程说明

    (a) Bios --> Bootloader --> kerner-->
    其中Bios是主板厂商做的,是在主板上的一个芯片,flash Memery

    (b) Bootloader 我们选择用grub

(3). 构建步骤

    具体的步骤如下,因为要用虚拟机,虚拟一个硬盘,然后在物理机上将系统装入虚拟硬盘
    1.虚拟机用 qemu
    2.用qemu-imag 创建一个虚拟硬盘
    3.modprobe
    4.qemu-nbd -c ...
    5.分区
    6.格式化
    7.mount
    8.grub

    9.kernel
    10.rootfs(知道/下的多数目录的作用...)
    11.init (内核代码init/main.c 有关于init指定/默认的路径)
            (自己写一个init程序,注意静态编译 和 动态编译: ...)
            (gcc 默认...)

busy-box
bash + (sysvinit)[function:..] + coreutils

 

4.OS组成:MM,PM,FS,IO,system call

 

Part1:MM

(1)MMU

概念:内存管理单元,cpu协处理器,和主chip物理上是一起,逻辑上是分开的

作用:地址转化(虚拟地址va->物理地址pa); 地址保护(可以根据mmap的attribute);地址扩展
有MMU后可以实现多进程
,怎么理解?

 

P1: 地址转化(虚拟地址va->物理地址pa)

有使用虚拟存储器的机器上,虚拟地址被直接送到内存总线上,使具有相同地址的物理存储器被读写;

而在使用了虚拟存储器的情况下,虚拟地址不是被直接送到内存地址总线上,而是送到存储器管理单元MMU,

把虚拟地址映射为物理地址。

 

P2: 地址保护(可以根据mmap的attribute)

待补充!!!!!奋斗奋斗奋斗

 

P3:可以看以下例子,来理解地址扩展

32位机器并启用MMU,有256M的物理内存,因为启用了MMU因此它可以运行4G的程序,但是不能一次性调入到内存运行

(必须要有可以存4G 程序的外部存储器,如磁盘,flash)

 

通常采用分页机制, 虚拟内存单位为页,物理内存单位为页帧,页和页帧大小必须相同,该例子页的大小为4K

对应4G虚拟内存和256M的物理内存,有1M个页和64K个页帧.

——————4G

     4k

___________                                           ___________ 256M

     4K                                                                 4k

___________                                           ___________

     .....                                                               ......

___________                                           ___________

     4K                                                                  4k

___________  0                                        ___________ 0

虚拟内存4G = 1M * 4K                              物理内存256M = 64K * 4K

 

P4 :看一下说明来理解有MMU后可以实现多进程

现代的多用户多进程操作系统,需要MMU,才能达到每个用户进程都拥有自己独立的地址空间的目标。

使用MMU,操作系统划分出一段地址区域,在这块地址区域中,每个进程看到的内容都不一定一样。

例如MICROSOFT WINDOWS操作系统将地址范围4M-2G划分为用户地址空间,(linux 0~3G划分为用户地址空间)

进程A在地址0X400000(4M)映射了可执行文件,进程B同样在地址0X400000(4M)映射了可执行文件,

如果A进程读地址0X400000,读到的是A的可执行文件映射到RAM的内容,而进程B读取地址0X400000时,则读到的是B的可执行文件映射到RAM的内容

 

 

(2)mmap

 


Part2: PM

在 kernel空间: 线程就是进程
在用户空间: 线程间共用同一内存资源
                    进程间内存资源是独立的(一个进程有一个mmap)

 

(1) 进程状态及其切换(process 3 status)
 
                waiting
                /      \^
               /        \
wake up /          \wait resource
             /             \sleep
            /               \   
          >/     time out  
start————————>ready<——————————>runing————>end
                  schedul(2)        

(2)1process <--> PCB

    when entry CPU PCB change to stak struct.
    
    struct PCB
    {
        next_instruction  *pc;
        pagetable_physics_addr *pagetable_p;
        pid;
        parent process;
        child  process;
        .....
    };
    
(3) schedul进程调度

    
    get PCB -> give the physics address of page table to the MMU register ->

(4)进程间的通信

(a)IPC:内部进程间的通信(Binder IPC:在android system中,camera client和camera server之间的通信方式为Binder)
(b)外部进程间的通信

 

(5)线程

(a). creat pthread

attente pthread_create() the last argument

is type : void *
we want to pass multi argument ,so we use a type that struct

 (b). a problem happened when the process is died but his pthread not run.

pthread_join()

 (c).pthread 同步互斥
what is 同步? what is 互斥?
pv原语
lock()/unlock()
 实现?

(d) API

 

 

Part3: 系统调用(system call function) 和 库函数(lib call function) ------linux

(1). what is system call?

系统调用是在内核实现的一系列函数.

常见的system call:open(); read(); write(); ioctl(); mmap();soket();要了解更多可以百度 or Google......



(2). system call function和lib call function的区别和共同点

(a) system call function in kernel level
      lib call function in lib level


(b) #调用lib function
    动态编译:直接调用lib库函数
                      跳转到函数实现处(在编译时,记录函数地址,函数名就是地址)
    静态编译:在编译的时候就把函数的实现copy过来

    #system call
     将其转化为指令:a. cpu模式的切换,从用户模式切换到内核模式
                               b. ....

(c). 为什么两类函数用起来是一样的?

    区分system call and lib function call 不是由编译器来区分这两类函数
    由一个库(glib库)

(3). 为什么将大多数函数的实现放在lib,不放在kernel里?

    效率
    system call:将其转化为指令,期间要切换cpu模式.....

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


 

 

 

 

 

 

 

 

 

原创粉丝点击