您的位置:首页 > 运维架构 > Linux

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模式.....
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: