linux相关的知识点
2013-08-28 13:03
239 查看
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模式.....
相关文章推荐
- Linux内存管理和进程调度相关知识点
- Linux驱动设计中相关知识点记录
- linux内核开发相关知识点
- linux 内核相关的知识点
- Linux文件属性相关知识点学习总结
- 找工作笔试面试那些事儿(16)---linux相关知识点(1)
- 相关Linux安全方面的知识点
- ARM-Linux驱动相关头文件知识点
- 文件系统与linux相关知识点
- ARM-Linux驱动相关头文件知识点
- Linux相关的小知识点
- ARM-Linux驱动相关头文件知识点
- Linux C语言编程-Linux系统环境--Linux上时间的相关操作---知识点总结
- 获取linux的文件系统相关信息的知识点
- 与音频相关的技术知识点总结(Linux方向的开发)
- linux应用开发相关知识点
- 找工作笔试面试那些事儿(16)---linux相关知识点(1)
- 与音频相关的技术知识点总结(Linux方向的开发)
- Linux相关知识点
- ARM-Linux驱动相关头文件知识点