前回書いたPINE64+の続きとして、とりあえずBROMの処理が終わった状態でCPUがどうなっているか知りたいのですが、難航しています。
BROMのコードのダンプを見た結果、コプロセッサの設定とかをしていることは分かりましたがどうも追いきれないところもあるのでとりあえずCPUのレジスタの値をUARTでダンプ出力とかしてみたいと思いました。
レジスタを直接触るためにはアセンブラでコードを書く必要があり、少しハードルはあがります。
といってもARMのABIを理解して、出力したいレジスタからMOV命令で汎用レジスタにコピーするだけなのでそこまでは難しくはないはずです。
が、とりあえず練習もかねてx86で試してみました。
ABI的にポインタで渡す変数がスタックトップの次にあることを前提としています。関数側ではEBPの設定とかしないようにしたので、スタックトップはリターンアドレスになります。抜けるときもret命令だけで問題ありません。
reg.asm
section .text global get_eax global get_ecx global get_edx global get_ebx global get_ebp global get_esi global get_edi global get_esp global get_eip get_eax: mov ebx, [esp+0x04] mov [ebx], eax ret get_ecx: mov eax, [esp+0x04] mov [eax], ecx ret get_edx: mov eax, [esp+0x04] mov [eax], edx ret get_ebx: mov eax, [esp+0x04] mov [eax], ebx ret get_ebp: mov eax, [esp+0x04] mov [eax], ebp ret get_esi: mov eax, [esp+0x04] mov [eax], esi ret get_edi: mov eax, [esp+0x04] mov [eax], edi ret get_esp: mov eax, [esp+0x04] mov [eax], esp sub [eax], dword 0x08 ret get_eip: mov eax, [esp] mov ebx, [esp+0x04] mov [ebx], eax ; return address on stack frame. ret
呼び出す側は、
main.c
#include <stdio.h> #include <stdint.h> extern void get_eax(uint32_t *reg); extern void get_ecx(uint32_t *reg); extern void get_edx(uint32_t *reg); extern void get_ebx(uint32_t *reg); extern void get_ebp(uint32_t *reg); extern void get_esi(uint32_t *reg); extern void get_edi(uint32_t *reg); extern void get_esp(uint32_t *reg); extern void get_eip(uint32_t *reg); int main(int argc, char **argv) { uint32_t eax, ecx, edx, ebx, esp, ebp, esi, edi, eip; get_eax(&eax); get_ecx(&ecx); get_edx(&edx); get_edx(&ebx); get_ebp(&ebp); get_esi(&esi); get_edi(&edi); get_esp(&esp); get_eip(&eip); printf("eax: [%08X]\n", eax); printf("ecx: [%08X]\n", ecx); printf("edx: [%08X]\n", edx); printf("ebx: [%08X]\n", ebx); printf("ebp: [%08X]\n", ebp); printf("esi: [%08X]\n", esi); printf("edi: [%08X]\n", edi); printf("esp: [%08X]\n", esp); printf("eip: [%08X]\n", eip); return 0; }
のような感じで、ポインタ引数で受け取ることを想定した関数にしてみました。
※最初戻り値で作ってみたのですが、戻り値だとEAXが取れなくなってしまいます。
まだ全関数のデバッグはできていませんが、問題なく動いていそうです。
ビルドは、
のような感じです。nasmを使う場合は -f でフォーマットを指定する必要があります。
$ nasm -f elf reg.asm
$ gcc main.c reg.o
getがなんとなく書けたのでついでにsetも書きたい。それができたらARMv7版も書いてみよう。