C言語の返り値
返り値を格納するレジスタ
AMDの仕様書22頁目の記述によると返り値が整数型の場合はraxに入れるらしい。(利用可能とは?利用できない場合があるのか?)
- If the class is INTEGER, the next available register of the sequence %rax,
%rdx is used.- If the class is SSE, the next available vector register of the sequence %xmm0,
%xmm1 is used.
(機械語訳)- クラスがINTEGERの場合
戻り値の型がINTEGERクラス(整数型またはポインタ型)の場合、次の利用可能なレジスタを順に使用する:
%rax → %rdx
4. クラスがSSEの場合
戻り値の型がSSEクラス(浮動小数点型またはSIMD型)の場合、次の利用可能なベクトルレジスタを順に使用する:
%xmm0 → %xmm1
実際に確認してみる
test.c
#include <stdio.h>
int foo() {
return 8;
}
int main() {
int a = foo();
printf("return = %d\n",a);
return 0;
}
gcc -S -masm=intel test.c -o test.s
test.s のコード
stackexam.c
.file "test.c"
.intel_syntax noprefix
.text
.globl foo
.def foo; .scl 2; .type 32; .endef
.seh_proc foo
foo:
push rbp
.seh_pushreg rbp
mov rbp, rsp
.seh_setframe rbp, 0
.seh_endprologue
mov eax, 8
pop rbp
ret
.seh_endproc
.section .rdata,"dr"
.LC0:
.ascii "return = %d\12\0"
.text
.globl main
.def main; .scl 2; .type 32; .endef
.seh_proc main
main:
push rbp
.seh_pushreg rbp
mov rbp, rsp
.seh_setframe rbp, 0
sub rsp, 48
.seh_stackalloc 48
.seh_endprologue
call __main
call foo
mov DWORD PTR -4[rbp], eax
mov eax, DWORD PTR -4[rbp]
mov edx, eax
lea rax, .LC0[rip]
mov rcx, rax
call printf
mov eax, 0
add rsp, 48
pop rbp
ret
.seh_endproc
.def __main; .scl 2; .type 32; .endef
.ident "GCC: (MinGW-W64 x86_64-ucrt-posix-seh, built by Brecht Sanders, r3) 14.2.0"
.def printf; .scl 2; .type 32; .endef
fooを抜ける前にeax
に8
を格納している。
(intが4バイトだからrax
の下位32ビットで足りると判断されてeax
になったのか?)
mov eax, 8
pop rbp
ret
実験
アセンブリの変更
変更前.s
mov eax, 8
変更後.s
mov eax, 10
実行
確かに結果が変わりました。
C:\Users\nanashi\test>gcc test.s -o test.exe
C:\Users\nanashi\test>test
return = 10
C:\Users\nanashi\test>
動作環境
Windows10 10.0.19045.5737
gcc version 14.2.0
MSDOS(同日追記)
C
アセンブラ
考察
16ビットのMSDOSでは予想通りaxに入れる模様。
このax→eax→raxとビット数は変わっても根本の仕様は変わらない
ようだ。