終わった時にこれに答えられるようになっていよう…!
- ネイティブコードの命令にその機能を表す英語の略称をつけたものを何と言いますか?
- アセンブリ言語のソースコードをネイティブコードに変換することを何と呼びますか?
- ネイティブコードをアセンブリ言語のソースコードに逆変換することを何と言いますか?
- アセンブリ言語のソーフファイルの拡張子は一般的になに?
- アセンブリ言語のプログラムにおけるセグメントとは何?
- アセンブリ言語のジャンプ命令は何のために使われますか?
コンパイルされたネイティブコードはそれだけみても理解が難しい。
そのため、機能をあらわす英語の略語をネイティブコードにつけることにした。
add``cmp
などの略語のことをニーモニックと呼び、ニーモニックを用いるプログラミング言語のことをアセンブリ言語と呼ぶ。
アセンブリ言語をネイティブ言語に変換することをアセンブルする、といい、その逆を逆アセンブルする、という。(アセンブリ言語になる動きは逆アセンブルする、というのでややわかりづらい気もする)
以下のソースコードを gcc -S sample.c
すると
int AddNum(int a, int b)
{
return a + b;
}
void MyFunc()
{
int c ;
c = AddNum(123,456);
}
以下のアセンブリ言語が出力される。
.section __TEXT,__text,regular,pure_instructions
.build_version macos, 10, 15 sdk_version 10, 15
.globl _AddNum ## -- Begin function AddNum
.p2align 4, 0x90
_AddNum: ## @AddNum
.cfi_startproc
## %bb.0:
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset %rbp, -16
movq %rsp, %rbp
.cfi_def_cfa_register %rbp
movl %edi, -4(%rbp)
movl %esi, -8(%rbp)
movl -4(%rbp), %esi
addl -8(%rbp), %esi
movl %esi, %eax
popq %rbp
retq
.cfi_endproc
## -- End function
.globl _MyFunc ## -- Begin function MyFunc
.p2align 4, 0x90
_MyFunc: ## @MyFunc
.cfi_startproc
## %bb.0:
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset %rbp, -16
movq %rsp, %rbp
.cfi_def_cfa_register %rbp
subq $16, %rsp
movl $123, %edi
movl $456, %esi ## imm = 0x1C8
callq _AddNum
movl %eax, -4(%rbp)
addq $16, %rsp
popq %rbp
retq
.cfi_endproc
## -- End function
.subsections_via_symbols
アセンブリ言語は
- オペコード ネイティブコードに変換される
- 擬似命令 アセンブラ自体に対する命令(アセンブルしてもネイティブコードに変換されない)
で構成されている。
アセンブリ言語の命令は
オペコード
+ オペランド
という構文になっている。
オペコード が動詞、オペランドが目的語
mov a,b aにbの値を格納する
add a,b AとBを加算してaに結果を保存
push a aの値をスタックに保存
pop a スタックから値を取り出してAに格納する
call a aという関数を呼び出す
ret 処理を関数の呼び出し元に戻す
%edi
とかはレジスタ
コンパイラが実行速度を早くしたりサイズを小さくするために行う処理 cに代入したもののそれを使っていないのでいらないやん、となって消し去った。
おそらく、addやmovのオペランドの順番が逆になっている。
pushq %rbp -> (1)
.cfi_def_cfa_offset 16
.cfi_offset %rbp, -16
movq %rsp, %rbp -> (2)
.cfi_def_cfa_register %rbp
subq $16, %rsp
movl $123, %edi
movl $456, %esi ## imm = 0x1C8
callq _AddNum
movl %eax, -4(%rbp)
addq $16, %rsp -> (3)
popq %rbp
retq
(1) 関数呼び出しの前に値が保存されているかもなので、一旦スタックに格納して最後にpopする。
(2)%rsp
を %rbp
にいれている理由は、スタックのアドレスを管理しているrspの値をmovのパラメータとして使えない決まりがあるため -> なぜ??
(3)なんで16を足すのか
-> クリーンアップ処理
なんで16を足すのかクリーンアップ処理
スタックの出し入れ単位8byteの2倍(本だと4byteになっている)
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset %rbp, -16
movq %rsp, %rbp
.cfi_def_cfa_register %rbp
movl %edi, -4(%rbp) -> (1)
movl %esi, -8(%rbp)
movl -4(%rbp), %esi
addl -8(%rbp), %esi
movl %esi, %eax -> (2)
popq %rbp
retq
(1) 引数をスタックから取り出している
(2) Cでは戻り値を %eax
レジスタで返すきまり
引数はスタックで、戻り値はレジスタで返す!!
グローバル変数はソースコードのどこからでも参照できるが、ローカル変数は関数内でしか参照できない グローバル変数は領域が常に確保されている ローカル変数はレジスタやスタックを使って一時的に用意している(最初はレジスタを使うが、足りなくなるとスタックを使う)
void MySub(){
}
void MyFunc(){
int i;
for (i=0;i<10;i++){
MySub();
}
}
.section __TEXT,__text,regular,pure_instructions
.build_version macos, 10, 15 sdk_version 10, 15
.globl _MySub ## -- Begin function MySub
.p2align 4, 0x90
_MySub: ## @MySub
.cfi_startproc
## %bb.0:
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset %rbp, -16
movq %rsp, %rbp
.cfi_def_cfa_register %rbp
popq %rbp
retq
.cfi_endproc
## -- End function
.globl _MyFunc ## -- Begin function MyFunc
.p2align 4, 0x90
_MyFunc: ## @MyFunc
.cfi_startproc
## %bb.0:
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset %rbp, -16
movq %rsp, %rbp
.cfi_def_cfa_register %rbp
subq $16, %rsp
movl $0, -4(%rbp)
LBB1_1: ## =>This Inner Loop Header: Depth=1
cmpl $10, -4(%rbp)
jge LBB1_4
## %bb.2: ## in Loop: Header=BB1_1 Depth=1
callq _MySub
## %bb.3: ## in Loop: Header=BB1_1 Depth=1
movl -4(%rbp), %eax
addl $1, %eax
movl %eax, -4(%rbp)
jmp LBB1_1
LBB1_4:
addq $16, %rsp
popq %rbp
retq
.cfi_endproc
## -- End function
.subsections_via_symbols
jge より大きいか等しい(SD = OF)
void MySub1(){
}
void MySub2(){
}
void MySub3(){
}
void MyFunc(){
int a = 123;
if (a>100){
MySub1();
}
else if (a < 50){
MySub2();
}
else {
MySub3();
}
}
.section __TEXT,__text,regular,pure_instructions
.build_version macos, 10, 15 sdk_version 10, 15
.globl _MySub1 ## -- Begin function MySub1
.p2align 4, 0x90
_MySub1: ## @MySub1
.cfi_startproc
## %bb.0:
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset %rbp, -16
movq %rsp, %rbp
.cfi_def_cfa_register %rbp
popq %rbp
retq
.cfi_endproc
## -- End function
.globl _MySub2 ## -- Begin function MySub2
.p2align 4, 0x90
_MySub2: ## @MySub2
.cfi_startproc
## %bb.0:
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset %rbp, -16
movq %rsp, %rbp
.cfi_def_cfa_register %rbp
popq %rbp
retq
.cfi_endproc
## -- End function
.globl _MySub3 ## -- Begin function MySub3
.p2align 4, 0x90
_MySub3: ## @MySub3
.cfi_startproc
## %bb.0:
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset %rbp, -16
movq %rsp, %rbp
.cfi_def_cfa_register %rbp
popq %rbp
retq
.cfi_endproc
## -- End function
.globl _MyFunc ## -- Begin function MyFunc
.p2align 4, 0x90
_MyFunc: ## @MyFunc
.cfi_startproc
## %bb.0:
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset %rbp, -16
movq %rsp, %rbp
.cfi_def_cfa_register %rbp
subq $16, %rsp
movl $123, -4(%rbp)
cmpl $100, -4(%rbp)
jle LBB3_2
## %bb.1:
callq _MySub1
jmp LBB3_6
LBB3_2:
cmpl $50, -4(%rbp)
jge LBB3_4
## %bb.3:
callq _MySub2
jmp LBB3_5
LBB3_4:
callq _MySub3
LBB3_5:
jmp LBB3_6
LBB3_6:
addq $16, %rsp
popq %rbp
retq
.cfi_endproc
## -- End function
.subsections_via_symbols
int counter = 100;
void MyFunc(){
counter *= 2;
}
void MyFunc2(){
counter *= 2;
}
movq %rsp, %rbp
.cfi_def_cfa_register %rbp
movl _counter(%rip), %eax
shll $1, %eax
movl %eax, _counter(%rip)
counterの値を読み出す ⬇︎ shll は指定されたビット数分論理右シフトする(つまり2倍) ⬇︎ counterに格納する
書き込む前にマルチスレッドだと処理が切り替わる可能性がある
ロック
をつかえば特定の範囲が完了するまで処理が切り替わるのをふせげる
#最後に
- ネイティブコードの命令にその機能を表す英語の略称をつけたものを何と言いますか? ニーモニック
- アセンブリ言語のソースコードをネイティブコードに変換することを何と呼びますか? アセンブルする
- ネイティブコードをアセンブリ言語のソースコードに逆変換することを何と言いますか? 逆アセンブルする
- アセンブリ言語のソーフファイルの拡張子は一般的になに? .asm
- アセンブリ言語のプログラムにおけるセグメントとは何? プログラムを構成する命令やデータをまとめたグループのこと
- アセンブリ言語のジャンプ命令は何のために使われますか? プログラムの流れを任意のアドレスに写す