Skip to content

Instantly share code, notes, and snippets.

@niconegoto
Last active November 7, 2019 16:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save niconegoto/07a12958f4e263290af29b7b548f7a29 to your computer and use it in GitHub Desktop.
Save niconegoto/07a12958f4e263290af29b7b548f7a29 to your computer and use it in GitHub Desktop.
プログラムはなぜ動くのか#10

終わった時にこれに答えられるようになっていよう…!

  • ネイティブコードの命令にその機能を表す英語の略称をつけたものを何と言いますか?
  • アセンブリ言語のソースコードをネイティブコードに変換することを何と呼びますか?
  • ネイティブコードをアセンブリ言語のソースコードに逆変換することを何と言いますか?
  • アセンブリ言語のソーフファイルの拡張子は一般的になに?
  • アセンブリ言語のプログラムにおけるセグメントとは何?
  • アセンブリ言語のジャンプ命令は何のために使われますか?

ニーモニック

コンパイルされたネイティブコードはそれだけみても理解が難しい。 そのため、機能をあらわす英語の略語をネイティブコードにつけることにした。 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
  • アセンブリ言語のプログラムにおけるセグメントとは何? プログラムを構成する命令やデータをまとめたグループのこと
  • アセンブリ言語のジャンプ命令は何のために使われますか? プログラムの流れを任意のアドレスに写す
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment