0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

V8の最適化されていない機械語を理解する

Last updated at Posted at 2025-01-18

はじめに

今更ですが、V8のソースコード読解とデバッグをはじめてしばらく経過したので、ちょっとつまずいた部分などをメモしていきます。なお、V8(d8)のバージョンは、13.3.0をソースコードからビルドしました。

仮想マシンの実装方法

Ignitionで生成されたバイトコードがどのように実行されているかを確認しようとしたのですが、 https://github.com/v8/v8/tree/main/src/interpreter
のフォルダにあるファイルにブレークポイントを設定しても、実行されている形跡がありません。

調べているうちに、どうやら、このコードは、V8がコンパイルされたときに、すぐに実行され、ビルドした環境の機械語のみが直接、V8に組み込まれるようでした。

組み込まれたソースコードの一覧は、d8 --log-code などと打つと、v8.logファイルに組み込まれた機械語の関数一覧が表示されます。

該当行は、ログファイルの行先頭にcode-creationと書かれていて、その次に、Builtinまたは、BytecodeHandlerと書かれています。

v8.log
...
new,MemoryChunk,0xbdd00000000,262144
code-creation,Builtin,2,142921,0x7fff7f2c0000,1028,DeoptimizationEntry_Eager
...
code-creation,BytecodeHandler,0,191851,0x7fff7fd90d40,304,Wide
...

BytecodeHandlerですが、これは、Ignitionが生成したバイトコードの命令と対応しているようです。バイトコードが読み取られた後に、BytecodeHandlerのアドレスが、ある関数テーブルにあり、バイトコードの命令を指す最初の1バイトが直接BytecodeHandlerのアドレスを指し示すようになっているようです。

v8.log
code-creation,BytecodeHandler,0,191851,0x7fff7fd90d40,304,Wide
code-creation,BytecodeHandler,0,191874,0x7fff7fd90e80,304,ExtraWide
code-creation,BytecodeHandler,0,191897,0x7fff7fd90fc0,560,DebugBreakWide
code-creation,BytecodeHandler,0,191919,0x7fff7fd91200,560,DebugBreakExtraWide
code-creation,BytecodeHandler,0,191942,0x7fff7fd91440,664,DebugBreak0

以下は、デバッガによる関数テーブル先頭からのメモリの内容です。

-exec x/500x 0x55555572d820
0x55555572d820:	0x7fd90d40	0x00007fff	0x7fd90e80	0x00007fff
0x55555572d830:	0x7fd90fc0	0x00007fff	0x7fd91200	0x00007fff
0x55555572d840:	0x7fd91440	0x00007fff	0x7fd91700	0x00007fff
0x55555572d850:	0x7fd91940	0x00007fff	0x7fd91b80	0x00007fff
0x55555572d860:	0x7fd91dc0	0x00007fff	0x7fd92000	0x00007fff
0x55555572d870:	0x7fd92240	0x00007fff	0x7fd92480	0x00007fff
0x55555572d880:	0x7fd925c0	0x00007fff	0x7fd92780	0x00007fff
0x55555572d890:	0x7fd92980	0x00007fff	0x7fd92b40	0x00007fff
...

BytecodeHandlerの置かれたアドレスと関数テーブルのアドレスが一致していることが確認できました。

InterpreterEntryTrampolineの実装

次に、Builtinですが、これは、個々の関数毎色々役割があります。BytecodeHandlerから呼ばれるものが多いですが、個々のBytecodeHandlerを呼び出すCallerとしての役割である、InterpreterEntryTrampolineの機械語について見ておくとよいでしょう。

InterpreterEntryTrampoline
   # 0xf may be JSFunction::kSharedFunctionInfoOffset
   # r11 is shared_function_info
   0x7fff7f30cec0:	mov    r11d,DWORD PTR [rdi+0xf]
   0x7fff7f30cec4:	add    r11,r14
   # ResetSharedFunctionInfoAge
   # 0x2b is SharedFunctionInfo::kAgeOffset
   0x7fff7f30cec7:	mov    WORD PTR [r11+0x2b],0x0
   # GetSharedFunctionInfoBytecodeOrBaseline
   0x7fff7f30cece:	mov    r10d,DWORD PTR [r11+0x3]
   ## CheckSharedFunctionInfoBytecodeOrBaseline
   0x7fff7f30ced2:	test   r10b,0x1
   0x7fff7f30ced6:	je     0x7fff7f30cef2
   0x7fff7f30ced8:	mov    r12,QWORD PTR [r13+0x26e8]
   0x7fff7f30cedf:	shr    r10d,0x9
   0x7fff7f30cee3:	shl    r10d,0x4
   0x7fff7f30cee7:	mov    r12,QWORD PTR [r12+r10*1+0x8]
   0x7fff7f30ceec:	or     r12,0x1
   0x7fff7f30cef0:	jmp    0x7fff7f30cf0e
   0x7fff7f30cef2:	shr    r10d,0x9
   0x7fff7f30cef6:	mov    r12,QWORD PTR [r13+0x218]
   0x7fff7f30cefd:	mov    r12,QWORD PTR [r12+r10*8]
   0x7fff7f30cf01:	movabs r10,0x80ffffffffffff
   0x7fff7f30cf0b:	and    r12,r10
   0x7fff7f30cf0e:	mov    r10d,DWORD PTR [r12-0x1]
   0x7fff7f30cf13:	cmp    r10d,0xd59
   0x7fff7f30cf1a:	jne    0x7fff7f30cf42
   0x7fff7f30cf20:	mov    r10d,DWORD PTR [r12+0x1b]
   0x7fff7f30cf25:	and    r10,0xf
   0x7fff7f30cf29:	cmp    r10d,0xa
   0x7fff7f30cf2d:	je     0x7fff7f30cf3c
   0x7fff7f30cf2f:	mov    edx,0x16
   0x7fff7f30cf34:	call   QWORD PTR [r13+0x57b0] # Abort
   0x7fff7f30cf3b:	int3   
   0x7fff7f30cf3c:	je     0x7fff7f30d185
   0x7fff7f30cf42:	cmp    r10d,0x20a5
   0x7fff7f30cf49:	jne    0x7fff7f30cf57
   0x7fff7f30cf4b:	mov    r12d,DWORD PTR [r12+0x7]
   0x7fff7f30cf50:	or     r12,QWORD PTR [r13+0x210]
   0x7fff7f30cf57:	mov    r10d,DWORD PTR [r12-0x1]
   0x7fff7f30cf5c:	cmp    r10d,0x941
   0x7fff7f30cf63:	jne    0x7fff7f30d10b
   ############################################################
   # LoadParameterCountFromJSDispatchTable
   # r13+0x26f8 is ExternalReference::js_dispatch_table_address
   0x7fff7f30cf69:	mov    r10,QWORD PTR [r13+0x26f8]
   0x7fff7f30cf70:	mov    r8,r15
   0x7fff7f30cf73:	shr    r8d,0x9
   0x7fff7f30cf77:	shl    r8d,0x4
   0x7fff7f30cf7b:	movzx  r8d,WORD PTR [r10+r8*1+0x8]
   # 0x1f is BytecodeArray::kParameterSizeOffset
   0x7fff7f30cf81:	cmp    r8w,WORD PTR [r12+0x1f]
   0x7fff7f30cf87:	je     0x7fff7f30cf96
   0x7fff7f30cf89:	mov    edx,0x9a
   0x7fff7f30cf8e:	call   QWORD PTR [r13+0x57b0] # Abort
   0x7fff7f30cf95:	int3   
   # LoadFeedBackVector ???
   0x7fff7f30cf96:	mov    ebx,DWORD PTR [rdi+0x17]
   0x7fff7f30cf99:	mov    ebx,DWORD PTR [r14+rbx*1+0x3]
   0x7fff7f30cf9e:	add    rbx,r14
   0x7fff7f30cfa1:	mov    ecx,DWORD PTR [rbx-0x1]
   0x7fff7f30cfa4:	cmp    ecx,0x801
   0x7fff7f30cfaa:	je     0x7fff7f30cfb2
   0x7fff7f30cfac:	lea    rbx,[r14+0x11]
   0x7fff7f30cfb0:	jmp    0x7fff7f30cfc1
   # ResetFeedbackVectorOsrUrgency
   # 0xc is FeedbackVector::kOsrStateOffset
   0x7fff7f30cfb2:	mov    r10b,BYTE PTR [rbx+0xc]
   # 0x8 is Immediate(~FeedbackVector::OsrUrgencyBits::kMask)
   0x7fff7f30cfb6:	and    r10b,0xf8
   0x7fff7f30cfba:	mov    BYTE PTR [rbx+0xc],r10b
   # 0x7 may be FeedbackVector::kInvocationCountOffset
   0x7fff7f30cfbe:	inc    DWORD PTR [rbx+0x7]
   0x7fff7f30cfc1:	push   rbp
   0x7fff7f30cfc2:	mov    rbp,rsp
   0x7fff7f30cfc5:	push   rsi # kContextRegister
   0x7fff7f30cfc6:	push   rdi # kJavaScriptCallTargetRegister
   0x7fff7f30cfc7:	push   rax # kJavaScriptCallArgCountRegister
   # 0x27 is BytecodeArray::kHeaderSize(0x28) - kHeapObjectTag(1)
   # r9 is kInterpreterBytecodeOffsetRegister
   0x7fff7f30cfc8:	mov    r9d,0x27 
   # r12 is kInterpreterBytecodeArrayRegister
   0x7fff7f30cfce:	push   r12
   0x7fff7f30cfd0:	mov    ecx,r9d
   0x7fff7f30cfd3:	add    ecx,ecx
   0x7fff7f30cfd5:	rol    rcx,0x20
   0x7fff7f30cfd9:	xor    rcx,0x515151
   0x7fff7f30cfe0:	ror    rcx,0x20
   # 
   0x7fff7f30cfe4:	push   rcx
   # rbx is FeedbackVector
   0x7fff7f30cfe5:	push   rbx
   0x7fff7f30cfe6:	mov    ecx,DWORD PTR [r12+0x1b]
   0x7fff7f30cfeb:	mov    rax,rsp
   0x7fff7f30cfee:	sub    rax,rcx
   0x7fff7f30cff1:	cmp    rax,QWORD PTR [r13-0x70]
   0x7fff7f30cff5:	jb     0x7fff7f30d1fe
   0x7fff7f30cffb:	lea    rax,[r14+0x11]
   0x7fff7f30cfff:	jmp    0x7fff7f30d002
   0x7fff7f30d001:	push   rax
   0x7fff7f30d002:	sub    rcx,0x8
   0x7fff7f30d006:	jge    0x7fff7f30d001
   0x7fff7f30d008:	movsxd rcx,DWORD PTR [r12+0x23]
   0x7fff7f30d00d:	test   ecx,ecx
   0x7fff7f30d00f:	je     0x7fff7f30d016
   0x7fff7f30d011:	mov    QWORD PTR [rbp+rcx*8+0x0],rdx
   0x7fff7f30d016:	cmp    rsp,QWORD PTR [r13-0x60]
   0x7fff7f30d01a:	jb     0x7fff7f30d0c8
   # load the head address of byte code handler table
   0x7fff7f30d020:	mov    r15,QWORD PTR [r13+0x4f78]
   # r12 + r9 will be the offset to the bytecode. 
   # read the bytecode to jump to bytecode handler.
   0x7fff7f30d027:	movzx  r10d,BYTE PTR [r12+r9*1]
   # r15 is a head of function pointer
   # r10 is an offset to the bytecode handler to be called. 
   0x7fff7f30d02c:	mov    rcx,QWORD PTR [r15+r10*8]
   ############################################################
=> 0x7fff7f30d030:	call   rcx
   ############################################################
   0x7fff7f30d032:	mov    r12,QWORD PTR [rbp-0x20]
   ## if it is 0, will abort.
   0x7fff7f30d036:	mov    r9d,DWORD PTR [rbp-0x28]
   
   0x7fff7f30d03a:	test   r9d,0x10000000
   0x7fff7f30d041:	je     0x7fff7f30d050
   0x7fff7f30d043:	mov    edx,0x4
   # Abort
   0x7fff7f30d048:	call   QWORD PTR [r13+0x57b0]
   0x7fff7f30d04f:	int3   
   ##########
   0x7fff7f30d050:	shr    r9d,1
   # r12 + r9d should be the next bytecode to be executed. 
   0x7fff7f30d053:	movzx  ebx,BYTE PTR [r12+r9*1]
   0x7fff7f30d058:	mov    r8,r9
   0x7fff7f30d05b:	mov    rcx,QWORD PTR [r13+0x1e90]
   0x7fff7f30d062:	cmp    bl,0x3
   0x7fff7f30d065:	ja     0x7fff7f30d084
   0x7fff7f30d067:	inc    r9d
   0x7fff7f30d06a:	test   bl,0x1
   0x7fff7f30d06d:	movzx  ebx,BYTE PTR [r12+r9*1]
   0x7fff7f30d072:	jne    0x7fff7f30d07d
   0x7fff7f30d074:	add    rcx,0xd0
   0x7fff7f30d07b:	jmp    0x7fff7f30d084
   0x7fff7f30d07d:	add    rcx,0x1a0
   0x7fff7f30d084:	cmp    bl,0xb3
   0x7fff7f30d087:	je     0x7fff7f30d0ad
   0x7fff7f30d08d:	cmp    bl,0xb9
   0x7fff7f30d090:	je     0x7fff7f30d0ad
   0x7fff7f30d096:	cmp    bl,0x92
   0x7fff7f30d099:	jne    0x7fff7f30d0a0
   0x7fff7f30d09b:	mov    r9,r8
   0x7fff7f30d09e:	jmp    0x7fff7f30d0a8
   0x7fff7f30d0a0:	movzx  r10d,BYTE PTR [rcx+rbx*1]
   0x7fff7f30d0a5:	add    r9d,r10d
   0x7fff7f30d0a8:	jmp    0x7fff7f30d020
   0x7fff7f30d0ad:	mov    rbx,QWORD PTR [rbp-0x20]
   0x7fff7f30d0b1:	movzx  ebx,WORD PTR [rbx+0x1f]
   0x7fff7f30d0b5:	mov    rcx,QWORD PTR [rbp-0x18]
   0x7fff7f30d0b9:	cmp    rbx,rcx
   0x7fff7f30d0bc:	cmovl  rbx,rcx
   0x7fff7f30d0c0:	leave  
   0x7fff7f30d0c1:	pop    rcx
   0x7fff7f30d0c2:	lea    rsp,[rsp+rbx*8]
   0x7fff7f30d0c6:	push   rcx
   0x7fff7f30d0c7:	ret    
   ############################################################
   0x7fff7f30d0c8:	mov    r10d,0x4c
   0x7fff7f30d0ce:	mov    QWORD PTR [rbp-0x28],r10
   0x7fff7f30d0d2:	xor    eax,eax
   0x7fff7f30d0d4:	mov    rbx,QWORD PTR [r13+0x40f8] # rbx=0x7ffff4c6
   0x7fff7f30d0db:	call   0x7fff7f744540 # CEntry_Return1_ArgvOnStack_NoBuiltinExit
   # _ZN2v88internal18Runtime_StackGuardEiPmPNS0_7IsolateE
   0x7fff7f30d0e0:	mov    r12,QWORD PTR [rbp-0x20]
   0x7fff7f30d0e4:	mov    r9d,0x27
   0x7fff7f30d0ea:	lea    rax,[r14+0x11]
   0x7fff7f30d0ee:	mov    ecx,r12d
   0x7fff7f30d0f1:	add    ecx,ecx
   0x7fff7f30d0f3:	rol    rcx,0x20
   0x7fff7f30d0f7:	xor    rcx,0x515151
   0x7fff7f30d0fe:	ror    rcx,0x20
   0x7fff7f30d102:	mov    QWORD PTR [rbp-0x28],rcx
   0x7fff7f30d106:	jmp    0x7fff7f30d020
   0x7fff7f30d10b:	push   rbp # // Caller's frame pointer.
   0x7fff7f30d10c:	mov    rbp,rsp
   0x7fff7f30d10f:	push   0x2e
   0x7fff7f30d111:	push   rdi
   0x7fff7f30d112:	push   rdx
   0x7fff7f30d113:	add    eax,eax
   0x7fff7f30d115:	rol    rax,0x20
   0x7fff7f30d119:	xor    rax,0x515151
   0x7fff7f30d11f:	ror    rax,0x20
   0x7fff7f30d123:	push   rax
   0x7fff7f30d124:	push   r15
   0x7fff7f30d126:	push   rdi
   0x7fff7f30d127:	mov    eax,0x1
   0x7fff7f30d12c:	mov    rbx,QWORD PTR [r13+0x3c78] # 0x7ffff4c3d720:CompileLazy
   0x7fff7f30d133:	call   0x7fff7f744540
   0x7fff7f30d138:	mov    rcx,rax
   0x7fff7f30d13b:	pop    r15
   0x7fff7f30d13d:	pop    rax
   0x7fff7f30d13e:	test   eax,0x10000000
   0x7fff7f30d143:	je     0x7fff7f30d152
   0x7fff7f30d145:	mov    edx,0x4
   0x7fff7f30d14a:	call   QWORD PTR [r13+0x57b0]
   0x7fff7f30d151:	int3   
   0x7fff7f30d152:	shr    eax,1
   0x7fff7f30d154:	pop    rdx
   0x7fff7f30d155:	pop    rdi
   0x7fff7f30d156:	cmp    QWORD PTR [rbp-0x8],0x2e
   0x7fff7f30d15b:	je     0x7fff7f30d16a
   0x7fff7f30d15d:	mov    edx,0x60
   0x7fff7f30d162:	call   QWORD PTR [r13+0x57b0]
   0x7fff7f30d169:	int3   
   0x7fff7f30d16a:	mov    rsp,rbp
   0x7fff7f30d16d:	pop    rbp
   0x7fff7f30d16e:	mov    r10,QWORD PTR [r13+0x26e8]
   0x7fff7f30d175:	mov    ecx,DWORD PTR [rcx+0x3]
   0x7fff7f30d178:	shr    ecx,0x9
   0x7fff7f30d17b:	shl    ecx,0x4
   0x7fff7f30d17e:	mov    rcx,QWORD PTR [r10+rcx*1]
   0x7fff7f30d182:	jmp    rcx
   0x7fff7f30d184:	int3  
   ###################################################
   0x7fff7f30d185:	push   rbp
   0x7fff7f30d186:	mov    rbp,rsp
   0x7fff7f30d189:	push   0x2e
   0x7fff7f30d18b:	push   rdi
   0x7fff7f30d18c:	push   rdx
   0x7fff7f30d18d:	add    eax,eax
   0x7fff7f30d18f:	rol    rax,0x20
   0x7fff7f30d193:	xor    rax,0x515151
   0x7fff7f30d199:	ror    rax,0x20
   0x7fff7f30d19d:	push   rax
   0x7fff7f30d19e:	push   r15
   0x7fff7f30d1a0:	push   rdi
   0x7fff7f30d1a1:	mov    eax,0x1


マーク「=>」のある0x7fff7f30d030のcall rcxから各BytecodeHandlerが呼ばれます。このrcxは前の命令を見ると、[r15+r10*8]のメモリを読み取っています。このr15が関数テーブルの先頭を指しています。r10は、その前の命令を見ると、[r12+r9*1]を読み取っていて、このアドレスは実は、現在読み込もうとしているバイトコードの命令の1バイト目を指しています。

この機械語を生成するソースコードはこちら(https://github.com/v8/v8/blob/main/src/builtins/x64/builtins-x64.cc#L1106) にありますが、ソースコードだけを読んでもなかなか分かりにくいところです。

なお、このTrampolineから全てのHandlerが呼ばれるわけではなく、BasicBlockの先頭の命令のみが呼ばれます。それ以外の命令に関しては、各命令列のHandlerから直接jmp命令を経由して鎖のように呼ばれます。

LdaZeroの実装

幾つかのHandlerの機械語を確認して、BytecodeHandlerがどのように実装されているかを見てみましょう。

LdaZero (0x0c)の命令は、アキュミュレータレジスタに0をロードする命令です。この命令の解釈には以下のような機械語が実装されていました。

LdaZero
   0x7fff7fd925c0:	lea    rbx,[rip+0xfffffffffffffff9]        # 0x7fff7fd925c0
   0x7fff7fd925c7:	cmp    rbx,rcx
   0x7fff7fd925ca:	je     0x7fff7fd925d9
   0x7fff7fd925cc:	mov    edx,0x88
   0x7fff7fd925d1:	call   QWORD PTR [r13+0x57b0]
   0x7fff7fd925d8:	int3   
   0x7fff7fd925d9:	push   rbp
   0x7fff7fd925da:	mov    rbp,rsp
   0x7fff7fd925dd:	push   0x24
   0x7fff7fd925df:	sub    rsp,0x20
   0x7fff7fd925e3:	mov    r10,rsp
   0x7fff7fd925e6:	sub    rsp,0x8
   0x7fff7fd925ea:	and    rsp,0xfffffffffffffff0
   0x7fff7fd925ee:	mov    QWORD PTR [rsp],r10
   #################################################
   0x7fff7fd925f2:	mov    QWORD PTR [rbp-0x10],r12
   0x7fff7fd925f6:	mov    QWORD PTR [rbp-0x18],r15
   0x7fff7fd925fa:	mov    QWORD PTR [rbp-0x28],rax
   0x7fff7fd925fe:	mov    QWORD PTR [rbp-0x20],r9
   #################################################
   0x7fff7fd92602:	mov    esi,0x20e
   0x7fff7fd92607:	mov    rdx,QWORD PTR [r13+0x1b98]
   0x7fff7fd9260e:	mov    edx,DWORD PTR [rdx+0x6627]
   0x7fff7fd92614:	add    rdx,r14
   0x7fff7fd92617:	mov    rdi,r12
   0x7fff7fd9261a:	mov    rax,QWORD PTR [r13+0x1e98]
   0x7fff7fd92621:	test   spl,0xf
   0x7fff7fd92625:	je     0x7fff7fd92628
   0x7fff7fd92627:	int3   
   0x7fff7fd92628:	lea    r10,[rip+0x10]        # 0x7fff7fd9263f
   0x7fff7fd9262f:	mov    QWORD PTR [r13+0xa8],r10
   0x7fff7fd92636:	mov    QWORD PTR [r13+0xa0],rbp
   0x7fff7fd9263d:	call   rax
   0x7fff7fd9263f:	mov    QWORD PTR [r13+0xa0],0x0
   0x7fff7fd9264a:	mov    rsp,QWORD PTR [rsp]
   0x7fff7fd9264e:	mov    r10,rsp
   0x7fff7fd92651:	sub    rsp,0x8
   0x7fff7fd92655:	and    rsp,0xfffffffffffffff0
   0x7fff7fd92659:	mov    QWORD PTR [rsp],r10
   0x7fff7fd9265d:	xor    esi,esi
   0x7fff7fd9265f:	mov    rdx,QWORD PTR [r13+0x1b98]
   0x7fff7fd92666:	mov    edx,DWORD PTR [rdx+0x662b]
   0x7fff7fd9266c:	add    rdx,r14
   0x7fff7fd9266f:	mov    rdi,QWORD PTR [rbp-0x28]
   0x7fff7fd92673:	mov    rax,QWORD PTR [r13+0x1e98]
   0x7fff7fd9267a:	test   spl,0xf
   0x7fff7fd9267e:	je     0x7fff7fd92681
   0x7fff7fd92680:	int3   
   0x7fff7fd92681:	lea    r10,[rip+0x10]        # 0x7fff7fd92698
   0x7fff7fd92688:	mov    QWORD PTR [r13+0xa8],r10
   0x7fff7fd9268f:	mov    QWORD PTR [r13+0xa0],rbp
   0x7fff7fd92696:	call   rax
   0x7fff7fd92698:	mov    QWORD PTR [r13+0xa0],0x0
   0x7fff7fd926a3:	mov    rsp,QWORD PTR [rsp]
   #################################################
   0x7fff7fd926a7:	mov    rbx,QWORD PTR [rbp-0x20]
   0x7fff7fd926ab:	lea    r9,[rbx+0x1]
   0x7fff7fd926af:	mov    r12,QWORD PTR [rbp-0x10]
   0x7fff7fd926b3:	movzx  r8d,BYTE PTR [r12+rbx*1+0x1]
   #################################################
   0x7fff7fd926b9:	mov    r10d,0xffffffff
   0x7fff7fd926bf:	cmp    r8,r10
   0x7fff7fd926c2:	jbe    0x7fff7fd926d1
   0x7fff7fd926c4:	mov    edx,0x2
   0x7fff7fd926c9:	call   QWORD PTR [r13+0x57b0]
   0x7fff7fd926d0:	int3   
   0x7fff7fd926d1:	cmp    r8b,0xbf
   0x7fff7fd926d5:	jae    0x7fff7fd926eb
   0x7fff7fd926d7:	mov    r15,QWORD PTR [rbp-0x18]
   0x7fff7fd926db:	mov    rcx,QWORD PTR [r15+r8*8]
   0x7fff7fd926df:	mov    rbp,QWORD PTR [rbp+0x0]
   0x7fff7fd926e3:	xor    eax,eax
   0x7fff7fd926e5:	add    rsp,0x30
   0x7fff7fd926e9:	jmp    rcx
   0x7fff7fd926eb:	cmp    r8b,0xce
   0x7fff7fd926ef:	ja     0x7fff7fd92737
   0x7fff7fd926f1:	mov    r11,QWORD PTR [rbp+0x0]
   0x7fff7fd926f5:	mov    QWORD PTR [r11+r8*8-0x6a8],0x0
   0x7fff7fd92701:	add    r9,0x1
   #################################################
   0x7fff7fd92705:	movzx  ebx,BYTE PTR [r12+rbx*1+0x2]
   0x7fff7fd9270b:	mov    r10d,0xffffffff
   0x7fff7fd92711:	cmp    rbx,r10
   0x7fff7fd92714:	jbe    0x7fff7fd92723
   0x7fff7fd92716:	mov    edx,0x2
   0x7fff7fd9271b:	call   QWORD PTR [r13+0x57b0]
   0x7fff7fd92722:	int3   
   0x7fff7fd92723:	mov    r15,QWORD PTR [rbp-0x18]
   0x7fff7fd92727:	mov    rcx,QWORD PTR [r15+rbx*8]
   0x7fff7fd9272b:	mov    rbp,QWORD PTR [rbp+0x0]
   0x7fff7fd9272f:	xor    eax,eax
   0x7fff7fd92731:	add    rsp,0x30
   0x7fff7fd92735:	jmp    rcx
   0x7fff7fd92737:	mov    rdx,QWORD PTR [r13+0x1b98]
   0x7fff7fd9273e:	mov    edx,DWORD PTR [rdx+0x663b]
   0x7fff7fd92744:	add    rdx,r14
   0x7fff7fd92747:	call   0x7fff7f46c780
   0x7fff7fd9274c:	int3   
   0x7fff7fd9274d:	int3   
   0x7fff7fd9274e:	int3   

先ず、0x7fff7fd925f2から始まる機械語に着目してみましょう。r9r12がスタックに格納されています。この関数がInterpreterEntryTrampolineから呼ばれることがあることに着目すると、r9r12を足し合わせたメモリに現在のバイトコード(0x0c)が格納されています。

このr9r12が、0x7fff7fd926a7から始まる命令列で再びレジスタに読み込まれています。そして、0x7fff7fd926b3で、movzx r8d,BYTE PTR [r12+rbx*1+0x1]しているということは、これは、LdaZeroの次の命令列を読みだそうとしていることを意味します。なお、LdaZeroは、1バイト命令のため、これはオペランドの読み込みでは無く、次の命令のロードとなります。この後、この値が、0x7fff7fd926d10x7fff7fd926ebで、0xbfと0xceの間にある値かどうか確認しています。先ず、0xbfより小さい場合、0x7fff7fd926e9jmp rcxで次のBytecodeHandlerに遷移します。そして、肝心のLdaZeroの処理ですが、0x7fff7fd926e3で、eaxを0にしています。実は、raxはアキュミュレータレジスタを格納するために使用されており、これが実質的に、LdaZeroの処理を指します。

次の命令列が、0xbfと0xceの間にある場合はどうでしょうか。実は、この範囲の命令は、全てstor0,stor1などのアキュミュレータレジスタからX番目レジスタに値を移す命令です。以下の部分の処理ですが、これはX番目のレジスタに0を格納するということを意味します。

0x7fff7fd926f1:	mov    r11,QWORD PTR [rbp+0x0]
0x7fff7fd926f5:	mov    QWORD PTR [r11+r8*8-0x6a8],0x0

アキュミュレータ以外のレジスタ値は、[rbp+0x0]の指すメモリ上に列を成して格納されているということです。

つまり、LdaZeroのBytecodeHandlerの処理の中で、次の命令がStor系の命令の場合は、アキュミュレータに0を格納するという点を省略して、直接それ以外のレジスタに値を格納しています。

こんな感じで、BytecodeHandlerの中で、レジスタが何を指すか理解することにより、仮想マシンについて理解を進めることができます。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?