AT&T は Gas (GNU Assembler) の出力構文であるため、あまり長く考えるべきではありません。C で記述し、-S スイッチを使用してアセンブラー出力を生成するだけです。
例:
ソースファイルabc.cに次のプログラムを入力すると
main(){
int a = 7;
int b = 3;
int c = 2;
return (double)a/(double)b*(double)c;
}
次に、それを使用してコンパイルしますgcc -S abc.c
次のアセンブリ ソース コードを取得します。
.file "abc.c"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl $7, -4(%rbp)
movl $3, -8(%rbp)
movl $2, -12(%rbp)
cvtsi2sd -4(%rbp), %xmm0
cvtsi2sd -8(%rbp), %xmm1
movapd %xmm0, %xmm2
divsd %xmm1, %xmm2
movapd %xmm2, %xmm1
cvtsi2sd -12(%rbp), %xmm0
mulsd %xmm1, %xmm0
cvttsd2si %xmm0, %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Debian 4.6.3-1) 4.6.3"
.section .note.GNU-stack,"",@progbits
それが何をするかは十分に明確であるはずです:スタックに3つのint用のスペースを確保し、それらに定数値を格納し、それらをdoubleに変換し(cvtsi2sd)、除算を実行します(注意:a/b
順番に書きますdiv b, a
、結果は2番目のレジスタに入ります)。などなど。明らかなのは、コンパイラが古い FPU 8087 命令セットをわざわざ使用しないことです。現在では、FPU スタックをいじらずに浮動小数点計算を実行する簡単な方法があるからです。質問はターゲットシステムについて何も言っていないので、コンパイラがそのような計算を実行するのと同じようにします。
一部の人々にとってはまだ不明確である可能性があるため(私の答えは反対票を投じられました)、gcc出力で少し並べ替えを行い(無駄なものを移動しないようにするため)、コメントを追加しました。唯一の落とし穴は、div の引数の順序です。どのレジスターにデータを入れて結果を取得するかは、リーダー次第です。
.file "abc.c"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
# Load integer 7 (variable a), convert it to double
movl $7, -4(%rbp)
cvtsi2sd -4(%rbp), %xmm0
# Load integer 3, (variable b) convert it to double
movl $3, -8(%rbp)
cvtsi2sd -8(%rbp), %xmm1
# Load integer 2, (variable c) convert it to double
movl $2, -12(%rbp)
cvtsi2sd -12(%rbp), %xmm2
# a / b -> written "div b, a" result goes in a (%xmm0)
divsd %xmm1, %xmm0
# b * c -> result goes in c (%xmm2)
mulsd %xmm0, %xmm2
# convert result back to integer
cvttsd2si %xmm2, %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Debian 4.6.3-1) 4.6.3"
.section .note.GNU-stack,"",@progbits
Linux では、execute をコンパイルして結果を表示できます (int に切り捨てられ、プロセス結果であるため 256 に切り捨てられます)。
gcc abc.s ; ./a.out ; echo $?
答えをより完全にするために、古いFPUを使用して同等のプログラムを簡単に作成できます(FPUの切り捨てモードを設定する必要がなかったため、最も近い整数に切り捨てられた4ではなく5が得られる場合があります):
.file "abc.c"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
# Load integer 7 (variable a), convert it to double
movl $7, -4(%rbp)
# Load integer 3, (variable b) convert it to double
movl $3, -8(%rbp)
# Load integer 2, (variable c) convert it to double
movl $2, -12(%rbp)
fild -12(%rbp)
fild -8(%rbp)
fild -4(%rbp)
# a / b -> written "div b, a" result goes in a (%mm0)
fdivp %st(0), %st(1)
# b * c -> result goes in c (%mm2)
fmulp %st(0), %st(1)
# convert result back to integer
fist -4(%rbp)
movl -4(%rbp), %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Debian 4.6.3-1) 4.6.3"
.section .note.GNU-stack,"",@progbits