プログラムは正しく書いたつもりでも思ったように動かない、最適化の為に細部の挙動まで知りたい、よくそんな時にアセンブラコードを出力する。
VC++ では /FAs を使えばアセンブラコードとソースコードを織り交ぜて出力してくれるが、gcc には見当たらないので非常に読みづらかったり。
で、何かそれを実現する方法が無いか探そうと思ったけれども、ppu-gcc/spu-gcc はデバッグオプション(-g)を付けた場合に行数を出力してくれてるようなので、こりゃ自分で書いた方が早いと思い、作ってみた。デバッグ込みで多分 1 時間くらい。
mas (Mix an Assembler code and Source codes)
使い方としてはこんな感じ:
// hello.c
#include <stdio.h>
int main(int argc, char * argv[])
{
return printf("Hello World!\n");
}
x86の例(抜粋):
$ gcc -gstabs+ -S hello.c
$ mas hello.s
.globl _main
_main:
.stabd 46,0,0
;#include <stdio.h>;
;
;int main(int argc, char * argv[])
;{
; return printf("Hello World!\n");
pushl %ebp
movl %esp, %ebp
pushl %ebx
subl $20, %esp
call L3
"L00000000001$pb":
L3:
popl %ebx
;}
leal LC0-"L00000000001$pb"(%ebx), %eax
movl %eax, (%esp)
call L_printf$stub
;
addl $20, %esp
popl %ebx
leave
ret
PowerPCの例(抜粋):
$ gcc -g -S hello.c
$ mas hello.s
main:
.quad .L.main,.TOC.@tocbase,0
.previous
.type main, @function
.L.main:
.LFB2:
;#include <stdio.h>
;
;int main(int argc, char * argv[])
;{
stdu 1,-128(1)
.LCFI0:
mflr 0
.LCFI1:
std 31,120(1)
.LCFI2:
std 0,144(1)
.LCFI3:
mr 31,1
.LCFI4:
mr 0,3
std 4,184(31)
stw 0,176(31)
; return printf("Hello World!");
ld 3,.LC1@toc(2)
bl printf
nop
mr 0,3
;}
mr 3,0
ld 11,0(1)
ld 0,16(11)
mtlr 0
ld 31,-8(11)
mr 1,11
blr
よくよく考えてみると perl で書いたら正規表現で置換するだけだから、ものの数分で出来た気がする。
ぐぐってみると、たまに行数付きのフォーマット(.file/.loc)で出力されたプログラムを見つけるんだけれど、ppu-gcc/spu-gcc じゃない普通の gcc でこのフォーマットを出力するにはオプションに何を指定したらいいんだろう?
Xcode 2.4.1 付属の gcc では -g -S としても .file/.loc が出力されないんだよなあ。
追記: .stabs/.stabd 形式に対応した ので、Xcode でも ok。