初めに
running変数にvolatileをつけた場合とつけない場合で比較する
比較するC言語ソース
volatile無し
test1.s
#include <stdio.h>
#include <signal.h>
int running = 1; // ★ここを変更して比較
// Ctrl+Cハンドラ
void handler(int sig) {
running = 0;
printf("Handler called!\n");
}
int main() {
signal(SIGINT, handler); // 修正箇所
while (running); // 最適化で無限ループに
printf("Exited gracefully\n");
return 0;
}
volatile有り
test2.s
#include <stdio.h>
#include <signal.h>
volatile int running = 1; // ★ここを変更して比較
// Ctrl+Cハンドラ
void handler(int sig) {
running = 0;
printf("Handler called!\n");
}
int main() {
signal(SIGINT, handler); // 修正箇所
while (running); // 最適化で無限ループに
printf("Exited gracefully\n");
return 0;
}
アセンブリ
gcc -S -O2 -masm=intel test1.c -o test1.s
gcc -S -O2 -masm=intel test2.c -o test2.s
volatile無し
test1.s
.file "test1.c"
.intel_syntax noprefix
.section .rdata,"dr"
LC0:
.ascii "Handler called!\0"
.text
.p2align 4,,15
.globl _handler
.def _handler; .scl 2; .type 32; .endef
_handler:
LFB12:
.cfi_startproc
mov DWORD PTR _running, 0
mov DWORD PTR [esp+4], OFFSET FLAT:LC0
jmp _puts
.cfi_endproc
LFE12:
.def ___main; .scl 2; .type 32; .endef
.section .rdata,"dr"
LC1:
.ascii "Exited gracefully\0"
.section .text.startup,"x"
.p2align 4,,15
.globl _main
.def _main; .scl 2; .type 32; .endef
_main:
LFB13:
.cfi_startproc
push ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
mov ebp, esp
.cfi_def_cfa_register 5
and esp, -16
sub esp, 16
call ___main
mov DWORD PTR [esp+4], OFFSET FLAT:_handler
mov DWORD PTR [esp], 2
call _signal
mov eax, DWORD PTR _running
.p2align 4,,10
L3:
test eax, eax
jne L3
mov DWORD PTR [esp], OFFSET FLAT:LC1
call _puts
xor eax, eax
leave
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
.cfi_endproc
LFE13:
.globl _running
.data
.align 4
_running:
.long 1
.ident "GCC: (MinGW.org GCC-6.3.0-1) 6.3.0"
.def _puts; .scl 2; .type 32; .endef
.def _signal; .scl 2; .type 32; .endef
volatile有り
test2.s
.file "test2.c"
.intel_syntax noprefix
.section .rdata,"dr"
LC0:
.ascii "Handler called!\0"
.text
.p2align 4,,15
.globl _handler
.def _handler; .scl 2; .type 32; .endef
_handler:
LFB12:
.cfi_startproc
mov DWORD PTR _running, 0
mov DWORD PTR [esp+4], OFFSET FLAT:LC0
jmp _puts
.cfi_endproc
LFE12:
.def ___main; .scl 2; .type 32; .endef
.section .rdata,"dr"
LC1:
.ascii "Exited gracefully\0"
.section .text.startup,"x"
.p2align 4,,15
.globl _main
.def _main; .scl 2; .type 32; .endef
_main:
LFB13:
.cfi_startproc
push ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
mov ebp, esp
.cfi_def_cfa_register 5
and esp, -16
sub esp, 16
call ___main
mov DWORD PTR [esp+4], OFFSET FLAT:_handler
mov DWORD PTR [esp], 2
call _signal
.p2align 4,,10
L3:
mov eax, DWORD PTR _running
test eax, eax
jne L3
mov DWORD PTR [esp], OFFSET FLAT:LC1
call _puts
xor eax, eax
leave
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
.cfi_endproc
LFE13:
.globl _running
.data
.align 4
_running:
.long 1
.ident "GCC: (MinGW.org GCC-6.3.0-1) 6.3.0"
.def _puts; .scl 2; .type 32; .endef
.def _signal; .scl 2; .type 32; .endef
比較
動作
Ctrl+cを押した後の画面
volatile無し
volatile有り
分析
アセンブリ差分の比較
volatile無し
一度eaxに入れた1を使い廻しているため、running
に0が入っても無限ループから抜けることができない
無限ループ.s
mov eax, DWORD PTR _running
.p2align 4,,10
L3:
test eax, eax
jne L3
volatile有り
毎回メモリからrunningの値を読み込んでいる。
無限ループ.s
.p2align 4,,10
L3:
mov eax, DWORD PTR _running
test eax, eax
jne L3
※test eax, eaxはeax
が0かどうかを調べている
eax
が0の場合はゼロフラグZF
が1となる。
その後jne L3
にてZF
が0でない場合はループを続ける。
メモリの読み込み回数が最適化で減らされ不具合が起きてしまった。(敢えて起こした)
動作環境
windows7 Version6.1.7601
GCC-6.3.0-1
(帰省中につき一時的に昔のパソコンを使用している。windows7が懐かしい。。。)