《erlang虛擬機器(vm)簡介》一文中介紹的暫存器和指令引數型別是學習erlang vm相關知識的基礎,也是理解本文內容的前提,這裡就不贅述了。
先看將要分析的例項的erlang源**:
%% mytest.erl
-module(mytest).
-compile(export_all).
%% 返回atom
t1() ->
ok.%% 呼叫bif
t2(a) ->
integer_to_list(a).
%% 加法運算
t3(a) ->
a + 10.
%% 呼叫內部函式
t4(a) ->
t3(a).
%% 函式分支
t5(0) -> 0;
t5(a) -> a + 1.
%% 尾遞迴
t6(, result) -> result;
t6([h | t], result) ->
h1 = h + 1,
t6(t, [h1 | result]).
erlc +"'s'" test.erl
生成彙編檔案:
%% test.s
. %% version = 0
, ,,,
,,
,]}...
%% 返回atom
. %% label就是標號,或者稱為**標籤,
%% 在跳轉時,這是乙個程式的入口點
. ]}.
,,0}.
. %% move指令,將原子「ok」送暫存器0
,}.%% 返回
return.
%% 呼叫bif
%% t2(a) ->
%% integer_to_list(a).
. .
]}.,,1}.
. ]}.
%% 呼叫bif integer_to_list
}.%% 加法運算
%% t3(a) ->
%% a + 10.
. .
]}.,,1}.
. ]}.
%% 呼叫guard bif,+操作符也是乙個bif函式,
%% 引數為[,],然後把結果送r0,即r0累加立即數10,
%% 如果執行出錯,則跳轉到label 0(這裡是丟擲錯誤)
%% 後面的1是幹什麼用的?(見註1)
,1,[,],}.
return.
%% 呼叫內部函式
. .
]}.,,1}.
. %% 跳轉到label 6,即呼叫函式t3
}.%% 函式分支
%% t5(0) -> 0;
%% t5(a) -> a + 1.
. .
]}.,,1}.
. %% 測試r0是否等於0
,[,]}.
%% 如果測試成功則返回,否則跳到label 11
return.
. ]}.
%% 執行加法運算
,1,[,],}.
return.
%% 尾遞迴
%% t6(, result) -> result;
%% t6([h | t], result) ->
%% h1 = h + 1,
%% t6(t, [h1 | result]).
. .
]}.,,2}.
. %% 測試r0是否是乙個非空list,如果不是則跳轉到
,}.%% r0儲存的是乙個list指標
%% 從list(r0)頭部取出乙個元素送r2,剩餘的送r3,
%% 相當於:[h|t] = r0, r2 = h, r3 = t
,,}.
]}.%% r2 + 1 結果送 r0
%% 後面的4是幹什麼用的?(見註1)
,4,[,],}.
%% 測試堆空間至少有2 words,4為live
%% 這裡傳入的live值有什麼作用?為了gc嗎?
.%% htop[0] = r0, htop[1] = r1, r1 = &htop[0]
,,}.
%% r3送r0,r3即是上面剩餘的list
,}.%% 目前已經為下一次的呼叫準備好了r0和r1這兩個引數
%% 呼叫自已
%% 生成opcode時,call_only會合併上面的move一起生成move_call_only_xrf x(3) x(0) mytest:t6/2 ???
}.. %% 測試r0是否為空list,如果不為空則跳轉到報錯
,}.%% 將r1送r0,這是函式的最後返回結果
,}.return.
%% 以下兩個函式,***,不解釋。
. .
.,,0}.
. ,}..}.
. .
.,,1}.
. ,}.
,}..
}.
注1:很多函式呼叫的指令後面都會有乙個數字,不太理解這個數字是幹什麼用的。google了一會,沒找到答案。可能它是乙個位址值,作為被呼叫函式的執行空間的起始位址。但這只是乙個猜測,即使是這樣,這個值又是怎麼樣計算出來的?
現以加法為例查詢一下這個數字的**。
在ops.tab中查詢gc_bif,有如下結果:
#
# optimize addition and subtraction of small literals using
# the i_increment/4 instruction (in bodies, not in guards).
#gc_bif2 p live u$bif:erlang:splus/2 int=i reg=d dst => \
gen_increment(reg, int, live, dst)
gc_bif2 p live u$bif:erlang:splus/2 reg=d int=i dst => \
gen_increment(reg, int, live, dst)
再從beam_load.c中找到如下結果:
static genop*原來它是乙個live值。gen_increment(loaderstate* stp, genoparg reg, genoparg integer,
genoparg live, genoparg dst)
小猜
被呼叫的函式只能使用live值以上的暫存器,這樣就不會覆蓋正在使用的暫存器值,使用這種方法,也省去了使用棧。但是,這種方法不會導致暫存器不夠用嗎?或許只有簡單函式的呼叫才做了這樣的優化。
ARM跳轉指令B的反彙編分析
為說明跳轉指令b的反彙編分析方法,這裡以一段 為例 text global start start b step1 step1 b step1 反彙編 如下 00000000 start 0 eaffffff b 4 4 e59ff000 ldr pc,pc,0 c 8 eafffffe b 8 c...
彙編中的指令
跳轉指令用於實現程式流程的跳轉,在 arm 程式中有兩種方法可以實現程式流程的跳 1 使用專門的跳轉指令。2 直接向程式計數器 pc 寫入跳轉位址值。通過向程式計數器 pc 寫入跳轉位址值,可以實現在 4gb 的位址空間中的任意跳轉,在跳轉之前結合使用 mov lr pc 等類似指令,可以儲存下一條...
彙編的各種指令
不怎麼用就忘記了,以後每學到乙個新的指令就記錄下來 如何在64位win10系統搭載彙編環境 1 什麼是debug?debug是dos,windows都提供的實模式,程式的除錯工具,使用他,可以檢視cpu各種暫存器中的內容,記憶體中的情況和在機器碼級跟蹤程式的執行。2 我們用到的debug功能 r命令...