http://blog.csdn.net/Lux_Veritas/article/details/11934083
http://www.cnblogs.com/catch/p/3857964.html mmap/munmap工具使用 #include <unistd.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <stdio.h>
main()
{
int *p=mmap(NULL,
getpagesize(), //页的大小
PROT_READ|PROT_WRITE, //读写权限
MAP_ANONYMOUS|MAP_SHARED,,);
*p=;
*(p+)=;
*p(p+)=;
printf("%d\n",p[]);
munmap(p,); //释分配的页 } --------------------------------------
#include <sys/mman.h>
#include <stdlib.h>
#include <stdio.h>
main()
{
int *p=mmap(NULL,
getpagesize(),
PROT_READ, //测试只读权限
MAP_ANONYMOUS|MAP_SHARED,,);
*p=;
*(p+)=;
*p(p+)=;
printf("%d\n",p[]);
munmap(p,); //释分配的页 } 段错误
------------------------------------------------------
总结:
选择择什么样的管理方法
C++:
STL :操作方便
new :操作方便
智能指针 C:
malloc :小而多数据(类型多,数据多)
brk/sbrk : (同类型的数据,动态移动指针)
mmap/munmap: 控制内存的访问权限,使用文件映射,控制内存的共享(进程数据间共享) brk/sbrk,mmap/munmap 效率最高的
------------------------------------------------------------------- 编程工具与动态库
.GCC
.MAKE
.GDB
.其他工具
.共享库 gcc:
-o: 输出的文件名
-O,-O0,-O1,-O2,-O3 :编绎优化
-g,-g0,-g1,-g2,-g3 :产生调试信息 越来越大,调试信息越多
-W :取消警告
-Wall 显示所有警告
-Werror:把警告当错误
-c :只编绎不链接:
-E :预编绎 gcc map.c -E -omain.i
-S :汇编 编绎过程:-e -> -c ->-S :自动调用连接器
连接器 :ld -D 在命令行定义宏
在代码中定义宏
在命令令行定义宏
-x 指定编译的语言类型号
c++,c,s,none
gcc -x assembler map.s
gcc -x none map.c //自动 -std: c99,c89
gcc -std=c99 gcc.c -DNUM=
gcc -std=c89 gcc.c -DNUM= ----------------------------------
eg:
gcc.c
int printf(const char *,...);
main()
{
printf("%d\n",NUM); } gcc gcc.c -omain -DNUM= //在命令定义宏 EG2
int add(int * restrict a)
restrict:值放到寄存器,提搞速度,c99可以编绎通过,c89不可以
-----------------------------------
文件扩展名:
.c: c文件
.cpp:c++
.CC:c++
.h 头文件
.hpp 头文件
.a
.o 目标文件
.so :动态链接库
.i 预编绎文件
.s 汇编 示例:
gcc map.c -omain -O
gcc map.c -omain -O0
gcc map.c -omain -O1
gcc map.c -omain -O2
gcc map.c -omain -O3 gcc map.c -omain -w
gcc map.c -omain -Wall
gcc map.c -omain -Werror
---------------------------------------------- 三 .静态库的编绎
.编绎过程(*.a)
1.1.编绎成目标文件
-static 可选
gcc -c -static <code>
1.2.归档成静态库
ar工具
ar -r 静态库文件 被归档的文件
ar -r ku.a ku1.o ku2.o
ar -t ku.a //查看有那些目标文件 nm工具:(查看函数符号表)
nm ku.a
nm 表态库/动态库/目标文件/执行文件 总结:
什么是库?
.函数封装的的二进制已经编译的归档中
.ar归档工具
.才用库方式管理代码优点
容易组织代码
复用
保护代码版
.静态库的静态的含义:
编译好的程序运行时候不依赖库
库作用为程序的一部分编译连接
.表态库本质:
就是目标文件的集合(归档文件) .-static 可选 .库的规范与约定
库命令名规则
lib<库名>.a.主版本号.次版本号.批号
lib<库名>.a eg:
ar -r libdemo1.a optool.o graphic.o 库的使用规则:标准使用方法
-l:库名
-L:库目录
gcc main.c -omain -ldemo2 -L. //静态库
//在当前目录搜索libdemo2.a这个文件
. eg: ku1.c
int add(int ,a int b)
{
return a+b; } ku2.c
int sub( int a,int b)
{ return a-b; } callku.c
main()
{ int r=add(,);
int s=sub(,); } gcc -static -c ku1.c
ku1.o gcc -static -c ku2.c
ku2.o ar -r ku.a ku1.o ku2.o gcc callku.c ku.a -omain //非标准库调用 //ku.a静态库
----------------------------------------------------------- 四.动态库的编绎
.什么是动态库?(共享库)
动态库是可以执行,静态库不能执行
但动态库没有main,不能独立执行
动态库不会连接成程序的一部分
程序执行时候,必须需要动态库文件 .工具
ldd 察看程序使用的动态库(只可以查看可执行文件)
eg:
ldd main nm 查看库中的函数符号 readelf -h main 查看执行程序头信息 elf格式 [root@monitor ~]# readelf -h a.out
ELF Header:
Magic: 7f 4c
Class: ELF64
Data: 's complement, little endian
Version: (current)
OS/ABI: UNIX - System V
ABI Version:
Type: EXEC (Executable file)
Machine: Advanced Micro Devices X86-
Version: 0x1
Entry point address: 0x400500
Start of program headers: (bytes into file)
Start of section headers: (bytes into file)
Flags: 0x0
Size of this header: (bytes)
Size of program headers: (bytes)
Number of program headers:
Size of section headers: (bytes)
Number of section headers:
Section header string table index: .动态库的编译
3.1.编绎
-c -fpic(可选) gcc -c -fpic iotool.c
gcc -c -fpic graphic.c .gcc -shared -odemo3.so iotool.o graphic.o 非标准动态库名
.gcc -shared -olibdemo4.so iotool.o graphic.o 标准动态库名 4使用动态库
gcc 代码 动态库文件名
gcc code -l库名 -L动态库所在路径
3.2
gcc -c -fpic iotool.c
gcc -c -fpic graphic.c
gcc -shared -olibdemo4.so iotool.o graphic.o
gcc main.c -ldemo4 -L. -omain ldd main
结果:
linux-gate.so.
libdemo4.so=>not found
libc.so.
/lib/ld-linux.so. ./main报错 解决方法:
export LD_LIBRARY_PATH=.:~:..:~soft01 //只对当前shell有效 表示到这些目录去找 ~soft01:指定soft01用户的主目录
~ :当前用户主目录 库标准命令名规则:
lib库名.so
lib库名.a
-l 库名 -L 库所在路径 问题:
4.1.执行程序怎么加载动态库?
见(动态库的加载) 4.2.动态库没有作为执行程序的一部分,为什么连接需要指定动态库以及目标录?
连接器需要确定函数在动态库的偏移的位置 动态库的加载:
.找到动态库(系统对动态库查找规则)
.加载动态库到内存
.映射到用户的内存空间 系统对动态库查找规则
./lib :需要ROOT权限把动态库考到该目录
./usr/lib :需要ROOT权限把动态库考到该目录
.到环境变量LD_LIBRARY_PATH指定的路径中查找
如果没有root 权限,可以在LD_LIBRARY_PATH指定的路径中查找
export LD_LIBRARY_PATH=.:~:..:~soft01 缓冲机制:
把/lib:/usr/lib:LD_LIBRARY_PATH加载到内存缓存中,加速读取,不到硬盘查找 /sbin/ldconfig -v 刷新缓冲中so的搜索路径 /lib,/usr/lib
eg:
/sbin/ldconfig -v |grep "libdl.so"
-v:
用此选项时,ldconfig将显示正在扫描的目录及搜索到的动态链接库,还有它所创建的连接的名字. .使用libdl.so 库 位置:/usr/lib/libdl.so
动态库加载原理
http://www.ibm.com/developerworks/cn/linux/l-dynamic-libraries/
-----------------------------------------------------------
[root@monitor ~]# gcc test.c -m32 -o test
[root@monitor ~]# ldd test
linux-gate.so. => (0x00d28000)
libc.so. => /lib/libc.so. (0x00194000) //C语言标准库
/lib/ld-linux.so. (0x00ba3000) [root@monitor ~]# /lib/ld-linux.so. ./test -----------------------------------------------------------------
[root@monitor ~]# gcc test.c -o test
[root@monitor ~]# ldd test
linux-vdso.so. => (0x00007fff629ff000)
libc.so. => /lib64/libc.so. (0x0000003c4ec00000) //C语言标准库
/lib64/ld-linux-x86-.so. (0x0000003c4e400000) [root@monitor ~]# /lib64/ld-linux-x86-.so. ./test
------------------------------------------------------------------ 动态库中函数的查找已经封装成库libdl.so,用户写代码加载动态库
dlopen 打开一个动态库 (flag:RTLD_LAZYRTLD_NOW)
dlsym 在打开的动态库中找一个函数
dlclose 关闭动态库
dlerror eg:
dldemo.c :动态库用代码加载加载演示
#include <dlfcn.h>
main()
{
void *handle=dlopen("./libdemo4.so",RTLD_LAZY);
void (*fun)(int)=dlsym(handle,"diamond");
fun();
dllclose(handle);
} gcc -dldemo.c -omain -ldl -L/usr/lib 没有指定-ldemo4
gcc -dldemo.c -omain -ldl //-L/usr/lib 不指定也可以
./main ldd main
nm libdemo4.so 查函数列表 man:
SYNOPSIS
#include <dlfcn.h> void *dlopen(const char *filename, int flag); char *dlerror(void); void *dlsym(void *handle, const char *symbol); int dlclose(void *handle); Link with -ldl. 总结:
编绎连接动态库
使用动态库
怎么配置于让程序调用动态库
常握工具:nm ldd lddconfig objdump strip eg:
strip libdemo4.so 删除多的信息
nm libdemo4.so .工具make使用
make 编绎脚本解释
编译脚本Makefile make -f 脚本文件 目标 脚本文件:
.文本文件 demo.mk
.语法
基本单位目标target
目标名:依赖目标
\tab目标指令
\tab目标指令
\tab目标指令
\tab目标指令
...
--------------------------------------------------
demo.mk
---------------------------------------------------
demo:iotool.c graphic.c main.c
gcc iotool.c -c //以tab健开始
gcc graphic.c -c //以tab健开始
gcc iotool.o graphic.o -shared -olibdemo.so //以tab健开始
gcc main.c -ldemo -omain -L. //以tab健开始
----------------------------------------------------
make -f demo.mk demo
----------------------------------------------------
./main
---------------------------------------------------- ldconfig命令: ldconfig为在命令行中说明的目录或文件/etc/ld.so.config中指定的目录或一些可信任的目录
(象/usr/lib, /lib)中的最新的动态连接库创建必要的连接和绶存。这些绶存起来的数据会被动态
连接器ld.so 或 ld-linux.so所使用。ldconfig会检查它所遇到的动态库文件的名称与版本号,
以决定那些动态库的连接要进行更新。 ldconfig会尝试推断ELF类型库(象libc5, libc6/glibc)是基于那一个版本的C库的。当然,在创建
动态库的时候,最好是明确的指定出使用C库(使用 -lc) 一些已经存在的动态库的能提供的信息,不足以使ldconfig来推断出它们的类型。因此,/etc/ld.so.config
文件格式允许进行明确的说明。这只是对于我们不能计算出类型的ELF库才有用。文件的格式是"dirname=TYPE",
TYPE可以是libc4, libc5, libc6. (这个语法在命令行上也可以使用). 空格是的禁止的。可以
参见-p 选项。ldconfig通常只能由超级管理员使用。因为它可能会修改一些root拥有的目录和文件。 选项: -v 详细模式。打印当前版本,扫描的目录,创建的连接。 覆盖安静模式。 -n 只处理在命令行上指定的目录。不处理可信息目录(/lib, 或 /usr/lib)和在 /etc/ld.so.config
中指定的目录。暗含 -N 选项 -N 不重建绶存。除非使用了 -X 选项,否则连接还是会更新的。 -X 不更新连接。除非使用了 -N 选项,否则绶存还是会更新的。 -f conf
使用conf 代替 /etc/ld.so.conf -C cache
使用cache 代替 /etc/ld.so.cache -r root
转换到并使用root -l 库模式。手动连接单个库。 建议专家级才使用。 -p 打印在绶存中的目录和候选库。 文件: /lib/ld-linux.so.2
运行时库加载器 /etc/ld.so.conf
由逗号、空格、制表符、换行符或引号分隔的目录列表。ld将会在这些目录中查找连接库。 /etc/ld.so.cache
包含了在/etc/ld.so.conf中指定的目录中查找到所有连接库。按顺序存储。
在基于 GNU glibc 的系统上,包括所有 linux 系统,ELF 可执行二进制文件的运行自动导致程序加载器被加载并且运行。
在 linux 下,加载器是 /lib/ld-linux.so.X(X是版本号)。然后加载器搜索、加载程序所要使用的动态链接库。
被搜索的文件夹列表保存在文件 /etc/ld.so.conf 里。
在程序启动的时候搜索这些文件夹是很没有效率的,所以实际上使用缓存。ldconfig(8) 默认读取 /etc/ld.so.conf 文件,在 DLL 文件夹里创建合适的符号链接,在 /etc/ld.so.cache 里写入一个缓存。缓存大大加速了库的读取。所以,当一个 DLL 被添加、删除时,或DLL文件夹被改变时都需要运行 ldconfig 程序,当安装了一个新的 DLL 时,由软件包管理器自动运行 ldconfig。当程序启动时,装载器实际使用的是缓存。
------------------------------------------------------------------------------------------------------------------------------------------------------------
1. 库的命名习惯
一个linux DLL 有三个不同名字的文件组成
soname 文件
每当链接库接口改变时都递增版本号。soname 文件其实只是一个符号链接而已,指向他的real name 文件。
real name 文件
发行号是可选的。该文件包含实际代码。
linker name 文件
编译器以这个名字来请求指定的链接库。
当程序在内部列出所需要的链接库时,仅仅使用 soname。当你创建一个链接库时,使用 real name。安装一个新的链接库时,把它复制到一个DLL文件夹里,然后运行程序 ldconfig(8)。ldconfig 检查存在的 real name 文件,并且创建指向它的符号链接 soname 文件。ldconfig 还做一件事情就是建立 cache 文件 /etc/ld.so.cache
ldconfig 不会创建 linker name 文件,但是一般性 linker name 文件在安装链接库的时候创建。linker name 文件也只是一个符号链接,指向最新的 soname 文件或 real name 文件。建议指向 soname 文件,因为当你更新库以后,在编译器链接的时候,一般总是想使用新的库。
2. 库的放置
DLL 必须放置在文件系统的指定位置。多数开源软件遵守GNU 标准:当分发源代码的时候,库默认安装在 /usr/local/lib,命令安装在 /usr/local/bin。该标准还定义了如何重写这些默认标准以及如何调用安装程序。
Filesystem Hierarchy Standard(FHS) 规定:多数库应安装在 /usr/lib,启动时需要的库安装在 /lib,非系统库应安装在 /usr/local/lib
GNU 标准是针对开发人员的,FHS 是针对发行者的。
二、 库是如何被使用的
在基于 GNU glibc 的系统上,包括所有 linux 系统,ELF 可执行二进制文件的运行自动导致程序加载器被加载并且运行。在 linux 下,加载器是 /lib/ld-linux.so.X(X是版本号)。然后加载器搜索、加载程序所要使用的动态链接库。
被搜索的文件夹列表保存在文件 /etc/ld.so.conf 里。
在程序启动的时候搜索这些文件夹是很没有效率的,所以实际上使用缓存。ldconfig(8) 默认读取 /etc/ld.so.conf 文件,在 DLL 文件夹里创建合适的符号链接,在 /etc/ld.so.cache 里写入一个缓存。缓存大大加速了库的读取。所以,当一个 DLL 被添加、删除时,或DLL文件夹被改变时都需要运行 ldconfig 程序,当安装了一个新的 DLL 时,由软件包管理器自动运行 ldconfig。当程序启动时,装载器实际使用的是缓存。
环境变量
LD_LIBRARY_PATH
该变量里所指定的文件夹将会首先被搜索,然后才会搜索默认的 DLL 文件夹。该变量对开发和测试比较有用,但不应该为了给普通用户使用而设置。如果你不想设置该变量,在 linux 下你可以直接调用程序加载器,比如,你可以传递 PATH 参数给加载器代替该变量来运行程序:
不带参数执行加载器,可以得到更多帮助。但是,不要这样执行程序,仅供调试时使用。
LD_DEBUG
看名字就知道,是供调试使用的。该变量是dl*函数的开关,用来显示正在做的事情的详细信息。可以取值为:
files | 显示so文件的加载顺序 |
bindings | 显示关于符号帮定的信息 |
libs | 显示库搜索路径的信息 |
versions | 显示版本依赖的信息 |
help | 使用该值运行程序将会显示可用的选项 |
三、创建动态链接库
首先用 -fpic 或 -fPIC 选项创建要放入 DLL 中的目标文件。使用该选项生成的代码是位置无关的代码(DLL的必要条件)。使用 gcc 的 -Wl 选项传递 soname 参数给链接器。-Wl 选项里不能有未转义的 whitespace。使用如下命令创建 DLL:
-o library_name file_list library_list
举个例子:
gcc -fPIC -g -c -Wall b.c
gcc -shared -Wl,-soname,libmystuff.so.1 /
-o libmystuff.so.1.0.1 a.o b.o -lc
该例子首先创建了两个与位置无关的目标文件 a.o、b.o,然后生成了一个包含两者的 DLL。注意:-g 选项使代码包含调试信息,-Wall 选项用来产生警告,两者并不是创建 DLL 必须的,但是建议加上。
不要 strip 所生成的 DLL,或使用编译器参数 -fomit-frame-pointer,这样做将会无法使用调试器。
-fPIC 选项总是可以使用,但生成的代码比使用 -fpic 的要大。-fpic 选项生成的代码比较小、快,但是有平台相关的限制,当创建 DLL 时,链接器将会告诉你是否符合限制。
链接器还有一个有用的选项 -rpath,可以用来指定程序在运行时搜索DLL时的路径,使用 gcc 时可以这样传递参数给链接器:
如果你使用了这个选项,就不用考虑 LD_LIBRARY_PATH 这个环境变量了。
四、安装、使用动态链接库
1.安装在标准位置
最简单的安装方式是复制 DLL 到一个标准的 DLL 文件夹(/usr/lib等)并且运行 ldconfig(8),然后手动创建 linker name 符号链接。
2.安装在非标准位置
下面的命令将会在指定的文件夹里创建适当的 soname 符号链接。
然后手动创建 linker name 文件指向 soname 文件。
编译程序的时候使用 -l、-L 参数指定需要链接的库和库所在的位置。
除非使用 -rpath 参数指定过运行时库搜索路径,否则在运行时也必须指定。(所以在eclipse中运行称找不到liqwt.so.5)
比如可以使用如下命令添加当前工作目录到 LD_LIBRARY_PATH 来运行程序:
ldd 命令可以用来查看程序的依赖,例如:
输出的是 soname 列表