程序员的自我修养
2019-02-26 19:35:22 95 举报
AI智能生成
《程序员的自我修养》读书笔记
作者其他创作
大纲/内容
程序员的自我修养
运行库
内存
内核空间
应用程序不能访问
用户空间
栈:用于维护函数调用的上下文
堆:容纳应用程序动态分配的内存区域
可执行文件映像:可执行文件的内存映射
保留区:受保护的内存区域的总称
向操作系统申请内存空间,再按需分配给程序
入口函数
初始化程序运行环境,然后调用main函数
main函数执行完毕后进行清理工作
I/O
文件:广义上的概念,包括设备、命令行、流等
文件描述符/句柄
用户通过它操作文件
打开文件表
一个指针数组,指向内核的打开文件对象
FILE结构
C语言中进行文件操作的结构体
打开文件对象
内核的文件对象,用户无法随意读写
初始化
在用户空间建立stdin、stdout、stderr及其对应的FILE结构
C/C++运行库
标准函数库
启动
多线程
全局构造和析构
装载与动态链接
可执行文件的装载
装载就是把程序从外部存储器读取到内存中的某个位置
虚拟地址空间
由操作系统管理,通过MMU映射到物理地址空间
注意和虚拟内存技术区分
扩展方式
PAE(Physical Address Extension)
AWE(Address Windowing Extensions)
XMS(eXtended Memory Specification)
装载方式
覆盖装入
将模块按依赖关系组织成树状结构,装载时可以覆盖不需要依赖的模块的内存空间
页映射
将物理存储空间分为若干大小一致的“页”
装载的过程
建立进程
创建虚拟地址空间
在页映射机制下就是创建映射函数所需的数据结构
读取可执行文件头,建立虚拟空间和可执行文件的映射关系
将文件中的一个或多个段映射到虚拟空间的VMA中
设置指令寄存器为进程的入口地址
页错误
CPU访问了空页面时产生页错误,并将控制权交给操作系统
操作系统找到空页所在的VMA,找出可执行文件的对应内容,然后在物理内存分配一个页面并建立其和虚拟页的映射关系
虚拟空间的分布
可执行文件中权限相同的段(section)合并成一个段(segment)进行映射
Segment是系统映射可执行文件的单位,用程序头来描述
堆和栈
在虚拟空间中以VMA形式存在
栈的初始化
将命令行参数数量、参数字符串的指针和环境变量字符串的指针入栈
将初始化信息中的参数信息传递给入口函数main()
段地址对齐
由于页是映射的最小单位,所以对segment的长度和起始地址有所限制
Linux装载ELF的过程 & Windows装载PE的过程
动态链接
基本思想:将链接过程推迟到运行时再执行
优势
节省空间
动态加载模块
可扩展性
兼容性
共享对象的最终装载地址在编译时是不确定的
固定装载地址
装载时重定位
PIC(Position-independent Code)
共享模块的全局变量问题
数据段地址无关性
延迟绑定
目的:提升动态链接的性能
当函数首次被使用时才进行绑定(符号查找、重定位等),否则不绑定
相关结构
.interp段
给出动态链接器的路径
.dynamin段
保存动态链接器所需要的信息
动态符号表(.dynsym)
模块间的符号导入/导出的信息
重定位表
在运行时对导入符号的引用进行修正,需要重定位
堆栈初始化信息
动态链接步骤
链接器自举
动态链接器作为特殊的共享对象,不能依赖其他共享对象
链接器完成自身所需的全局和静态变量的重定位
自举代码中不能调用函数
装载共享对象
全局符号表:合并了所有被加载的共享对象的符号表(包括动态链接器)
符号优先级
全局符号介入:共享对象的全局符号被同名符号覆盖
重定位&初始化
动态链接器执行共享对象的.init段(如果有),但不执行可执行文件的.init段
基本实现
Linux
(动态)共享对象,扩展名为 .so
Windows
动态链接库,扩展名为 .dll
模块
可执行文件和共享对象可以看成程序的不同模块
动态链接器
与普通共享对象一样被映射到地址空间
动态链接器的实现(Linux)
路径:/lib/ld-linux.so.2(软链接)
动态链接器本身是静态链接的
ld.so的装载地址是无效装载地址0x00000000
显示运行时链接(运行时装载)
程序在运行时控制加载指定模块,不需要时可以卸载
使用动态装载库,其本质和共享对象没有区别
动态链接器API
dlopen():打开一个动态库
dlsym():找到所需符号
dlerror():判断上一次调用是否成功
dlclose():卸载一个模块
Linux共享库
共享库在文件结构上和共享对象没有区别,广义上可以当成同一样东西
共享库版本
兼容更新 / 不兼容更新
命名规范
例子:libname.so.x.y.z
lib:前缀
name:库命
so:后缀
x:主版本号
y:次版本号
z:发布版本号
SO-NAME
只保留主版本号的一个命名机制,在Linux上通过软链接指向共享库的最新版本
目的:使依赖于某个共享库的模块使用SO-NAME,而不是详细版本号
符号版本
基本思路:每个导入导出的符号都有个相关联的版本号
系统路径
FHS标准
/lib:系统中最关键和基础的共享库
/usr/lib:非系统运行时所需要的关键共享库(主要是开发时使用)
/usr/local/lib:和操作系统并不十分相关的库(第三方应用的库)
环境变量
LD_LIBRARY_PATH:共享库查找路径
LD_PRELOAD:指定预先装载的共享库或者目标文件
LD_DEBUG:打开动态链接器的调试功能
创建和安装
GCC
-shared
-fPIC
清除符号信息
这些信息一般在调试时使用
strip清除工具
安装
ldconfig命令
构造和析构函数
共享库脚本
共享库可以是符合一定格式的链接脚本,实现将几个现有共享库组合成一个“新共享库”
Windows下的动态链接
基础知识
计算机结构
重要硬件:CPU、内存和IO芯片
南北桥、PIC总线
SMP与多核
层次结构
接口
API
System call Interface
Hardware Specification
操作系统内核
开发库和运行库
CPU
分时系统
多任务系统
抢占式分配
硬件驱动
文件系统
地址映射
分段机制和分页机制
线程
访问权限
优先级
任务——Linux
线程安全
用户线程和内核线程
静态链接
编译&链接简述
程序构建
1. 预处理
执行预处理指令并删除注释
2. 编译
各种词法、语法分析及优化,得到汇编代码
3. 汇编
将汇编代码翻译成机器指令
4. 链接
模块的拼接
编译过程
扫描 -> 语法分析 -> 语义分析 -> 源代码优化 -> 代码生成 -> 目标代码优化
链接过程
地址和空间分配、符号决议和重定位等
链接目标文件(Object File)和库,形成可执行文件
目标文件
类型
Linux:ELF
文件头
描述文件属性
代码段
指令
数据段
初始化的变量
.bss段
未初始化的变量,或初值为0的变量
重定位的信息
字符串表
保存字符串
符号表
与Symbol相关的信息
其他段
段表
保存段的基本属性
调试信息
Windows:PE-COFF
和ELF格式都是从COFF格式发展而来
分析目标文件的程序
gcc
objdump
objcopy
size
符号:链接的接口
函数签名
符号修饰
强符号&弱符号
空间地址的分配
相似段合并
符号地址确定
符号解析与重定位
重定位入口:要被重定位的地方
入口偏移:表示入口在段中的位置
指令修正
COMMON块
作用:处理多个不同类型的弱符号
需要COMMON块的根本原因:链接器无法判断符号类型
C++相关工作
重复代码消除
全局构造与析构
ABI(Application Binary Interface)
链接过程控制
命令参数
目标文件中的指令
链接脚本
静态库
可以看成一组经过压缩的目标文件的集合
BFD库
通过统一的接口处理不同的文件格式
弊端
浪费内存和磁盘空间,模块在内存中有多个重复副本
更新不方便,每个模块的改动都需要重新链接整个程序
系统调用
简介
概念:操作系统提供给应用程序的一套接口,使程序可以访问系统资源,也可以做一些需要系统支持的行为
Linux使用0x80号中断作为系统调用入口,Windows使用0x2E号中断
使用不便,没有很好的包装
各个操作系统之间的系统调用不兼容
原理
特权级别
用户态
内核态
中断
解释:一个硬件或软件发出的请求,要求CPU暂停当前工作去处理更重要的事
属性
中断号(从0开始)
中断处理程序
Windows API
Windows提供给应用程序的最底层接口,以DLL导出函数的形式暴露
Windows上的系统调用(也称系统服务)并不开放,隱藏在API下层
0 条评论
回复 删除
下一页