stub.cと連携するRISC-Vアセンブリ
MinCaml の stub.cと連携する必要があるので、ra と fp(s0レジスタ) の退避方法と、print_int を呼び出す方法を確認しておく。 print_4649.S
code:print_4649.S (asm)
.text
.globl min_caml_start
min_caml_start:
// スタックへ ra と fp(s0) を退避
addi sp, sp, -16
sw ra, 8(sp)
sw s0, 0(sp)
// 新しい fp(s0) を設定
addi s0, sp, 16
// 4649 を print する
li a0, 4649
call min_caml_print_int
call min_caml_print_newline
// スタックから ra と fp(s0) を復帰
lw ra, 8(sp)
lw s0, 0(sp)
addi sp, sp, 16
ret
stub.c
code:stub.c
extern int min_caml_start(char *, char *);
int main( int argc, char *argv[] ) {
char *hp, *sp;
sp = alloca(1000000); hp = malloc(4000000);
if (hp == NULL || sp == NULL) {
fprintf(stderr, "malloc or alloca failed\n");
return 1;
}
fprintf(stderr, "sp = %p, hp = %p\n", sp, hp);
min_caml_start(sp, hp);
return 0;
}
void min_caml_print_int(long n) {
printf("%ld", n);
}
void min_caml_print_newline() {
printf("\n");
}
ちゃんと動いてそう
code:sh
$ riscv32-unknown-elf-gcc print_4649.S stub.c
$ spike /opt/riscv/pk/riscv32-unknown-elf/bin/pk a.out
bbl loader
sp = 0x7ff0bb20, hp = 0x25a40
4649
spとfp(s0) の退避と復帰
こんな感じにspとfpを退避する(RISC-Vでは s0 が fp として使われる)
code:print_4649.S (asm)
.text
.globl min_caml_start
min_caml_start:
// スタックへ ra と fp(s0) を退避
addi sp, sp, -16
sw ra, 8(sp)
sw s0, 0(sp)
// 新しい fp(s0) を設定
addi s0, sp, 16
// (メイン処理)
// スタックから ra と fp(s0) を復帰
lw ra, 8(sp)
lw s0, 0(sp)
addi sp, sp, 16
ret
print_int の呼び出し
引数を a0 a1 a2 ... レジスタに渡して call min_caml_print_int を呼ぶ
code:print_4649.S (asm)
...
// 4649 を print する
li a0, 4649
call min_caml_print_int
...
疑似命令liの置換後のすがた
疑似命令 li は以下のような命令列に置換される
code:asm
# before
li a0, 4649
# after
lui a0, 0x1 # a0 = 0x1 << 12 (a0 = 4096)
add a0, a0, 553 # a0 = a0 + 553 (a0 = 4096 + 553 = 4649)