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. 雖然資料比較老,但是很多還是沒變...)。