mcommit's message

ソフトウェア開発の仕事をしているsimotinといいます。記事の内容でご質問やご意見がありましたらお気軽にコメントしてください\^o^/

レジスタの値を取得するi386のアセンブラ関数を書いてみた

前回書いたPINE64+の続きとして、とりあえずBROMの処理が終わった状態でCPUがどうなっているか知りたいのですが、難航しています。

mcommit.hatenadiary.com

BROMのコードのダンプを見た結果、コプロセッサの設定とかをしていることは分かりましたがどうも追いきれないところもあるのでとりあえずCPUのレジスタの値をUARTでダンプ出力とかしてみたいと思いました。

レジスタを直接触るためにはアセンブラでコードを書く必要があり、少しハードルはあがります。
といってもARMのABIを理解して、出力したいレジスタからMOV命令で汎用レジスタにコピーするだけなのでそこまでは難しくはないはずです。

が、とりあえず練習もかねてi386で試してみました。

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 elf reg.asm
$ gcc main.c reg.o
のような感じです。nasmを使う場合は -f でフォーマットを指定する必要があります。

getがなんとなく書けたのでついでにsetも書きたい。それができたらARMv7版も書いてみよう。