beam文件是erlang编译器生成的文件格式,可以直接加载到erlang vm中运行的文件格式。
一. 文件格式
beam文件的文件布局如下:
文件由一个文件头加各种块构成,块的结构由块头加自定义结构组成。在beam文件中atom块,code块,字符串块,导入表,导出表,是必须出现的块。其它可选(意思是你没用到beam文件就不会出现这些块)。
接下来逐一介绍这些块:
1. 文件头
4字节 | 4字节 | 4字节 |
"FOR1" | Size | "BEAM" |
"FOR1": 符合EA IFF 85 文件格式
Size:文件剩余大小,也就说文件大小=Size + 8
"BEAM":beam文件
2. Atom块
4字节 | 4字节 | 4字节 | 1字节 | N1字节 | 1字节 | N2字节 | ... |
"Atom" | Size | Count | N1 | 原子 | N2 | 原子 | ... |
Atom:原子块标识
Size:原子表大小
Count:原子个数
N1:第一个原子长度
原子:第一个原子,ascii码
N2:第二个原子长度
原子:第二个原子
然后一直到Count个原子. (ps:第一个原子一定是模块名)
3. Code块
4字节 | 4字节 | 4字节 | 4字节 | 4字节 | 4字节 | 4字节 | 4字节 |
"Code" | Size | sub-size | version | opcode-max | lables | fun-count | code |
"Code":代码块标识
size:剩余块长度
sub-size:头部扩展使用(目前用来计算代码开始位置,因为sub-size到code距离16字节,所以这里目前一定是16)
version:指令集版本
opcode-max:代码中使用最大opcode,目前是153
labels:代码label的个数(可生成.S文件查看具体信息)
fun-count:代码中函数个数
code:代码
(ps. 当一个erlang vm发现version跟自己不同或者beam文件的opcodemax大于自己时,不会加载这个beam文件)
4. 字符串块
4字节 | 4字节 | 4字节 |
"StrT" | Size | string |
"StrT":字符串块标识
size:剩余字符串块的大小
string:具体字符串
(ps. 若有人能告诉我什么样的数据会放在字符串表,不胜感激)
5. 导入表
4字节 | 4字节 | 4字节 | 4字节 | 4字节 | 4字节 | 4字节... |
"ImpT" | Size | n | M | F | A | M … |
"ImpT":导入表标识
size:剩余导入表大小
n:导入表中有n个函数记录
MFA:一条记录由一个MFA标识,由于原子已经在原子块中定义,所以这里
只需要保存是第几个原子。
6. 导出表
4字节 | 4字节 | 4字节 | 4字节 | 4字节 | 4字节 | 4字... |
"ExpT" | Size | n | F | A | L | F... |
"ExpT":导出表标识
size:剩余导出表大小
n:导出表记录个数
F:函数原子id
A:参数个数
L:函数代码位置
7. 本地函数表
4字节 | 4字节 | 4字节 | 4字节 | 4字节 | 4字节 | 4字... |
"LocT" | Size | n | F | A | L | F... |
"LocT":本地函数标识
size:剩余表大小
n:表中记录个数
F:函数名原子id
A:参数个数
L:代码位置
(ps. 跟导出表布局一样)
8. Attributes 表
4字节 | 4字节 | 4字节 |
"Attr" | Size | data |
"Attr":表标识
size:剩余表大小
data:数据(erlang扩展格式方式存放)
9. 编译信息块
4字节 | 4字节 | 4字节 |
"Cinf" | Size | data |
"CInf":编译信息块标识
size:剩余块大小
data:编译选项数据(erlang扩展格式存放)
10. abstract_code 块
4字节 | 4字节 | 4字节 |
"AbsT" | Size | data |
"AbsT":块标识
size:剩余块大小
data:数据(编译时加debug_info选项会用到这个块,可以从中解析出源码)
11. 匿名函数表
4字节 | 4字节 | 4字节 | 4字节 | 4字节 | 4字节 | 4字节 | 4字节 | 4字节 | 4字节.. |
"FunT" | Size | n | F | A | L | index | free | olduiq | F... |
"FunT":表标识
size:剩余表大小
n:函数个数
F:函数名原子id
A:参数个数(包含自由变量)
L:代码位置
index:表中第几个函数
free:匿名函数中自由变量的个数
olduiq:唯一标识(ps. 不知道确切含义,貌似是模块中函数的hash值,若有明白的,请告诉我)
12. 文字块
4字节 | 4字节 | 4字节 | 4字节 |
"LitT" | Size | uncompress-size | data |
"LitT":文字块标识
size:块剩余大小
uncompress-size:未压缩时数据的大小
data:压缩的数据
(ps. 这里压缩采用zlib压缩,可以用zlib:uncompress解压数据,解压后的数是长度+erlang扩展格式+长度+扩展格式+.....)
13. 其它块
beam文件还会存在一些跟调试相关的块,如何Line块,Trac块,但这些块中具体意义还不了解,所以不做介绍。
二. 实例分析
如上图所示:标识了这个例子中出现的一些块。
以下是自己写的beam文件格式解析工具:
程序地址:https://gitcafe.com/QuietBoy/erlBeam
三. 参考资料
1. beam文件格式
https://synrc.com/publications/cat/Functional%20Languages/Erlang/BEAM.pdf
http://www.erlang.se/~bjorn/beam_file_format.html
(ps. 虽然资料比较老,但是很多还是没变...)。