#pragma
プログラムに関するすべての情報はソースコード上にあるのが好きだ。プロジェクトのプロパティ(あるいはmakefile)に情報が分散されているのは好きじゃないので、コンパイラやリンカへのオプションはできるだけpragmaを使おうと努めている。
でまあ、またちょっと調べたりしたのでメモ。特に、暗黙的な関数呼び出しを生成してしまうオプションの操作についてまとめる。
- 「バッファセキュリティチェック」で__security_check_cookie関数の呼び出しを制御できる
- 「基本ランタイムチェック」で_RTC_CheckEsp等の関数の呼び出しを制御できる
- 「基本ランタイムチェック」を操作するには#pragma runtime_checksを使う
- 「組み込み関数を使用する」で一部関数をインライン化できる
- 「組み込み関数を使用する」を操作するには#pragma intrinsicと#pragma function を使う
_RTC_CheckEsp / _RTC_CheckStackVars関数の呼び出しを抑止
before
void enables_stackframe_verification() { 012D1040 push ebp 012D1041 mov ebp,esp 012D1043 sub esp,0Ch 012D1046 mov dword ptr [ebp-0Ch],0CCCCCCCCh 012D104D mov dword ptr [ebp-8],0CCCCCCCCh 012D1054 mov dword ptr [ebp-4],0CCCCCCCCh char c[2] = {0}; 012D105B mov byte ptr [c],0 012D105F xor eax,eax 012D1061 mov byte ptr [ebp-7],al memset(&c, 1, sizeof(c)); 012D1064 push 2 012D1066 push 1 012D1068 lea ecx,[c] 012D106B push ecx 012D106C call memset (12D1630h) 012D1071 add esp,0Ch } 012D1074 push edx 012D1075 mov ecx,ebp 012D1077 push eax 012D1078 lea edx,[ (12D1094h)] 012D107E call _RTC_CheckStackVars (12D16E0h) 012D1083 pop eax 012D1084 pop edx 012D1085 add esp,0Ch 012D1088 cmp ebp,esp 012D108A call _RTC_CheckEsp (12D16B0h) 012D108F mov esp,ebp 012D1091 pop ebp 012D1092 ret 012D1093 nop
after
#pragma runtime_checks("s", off) void disables_stackframe_verification() { 012D10B0 push ebp 012D10B1 mov ebp,esp 012D10B3 push ecx char c[2] = {0}; 012D10B4 mov byte ptr [c],0 012D10B8 xor eax,eax 012D10BA mov byte ptr [ebp-3],al memset(&c, 1, sizeof(c)); 012D10BD push 2 012D10BF push 1 012D10C1 lea ecx,[c] 012D10C4 push ecx 012D10C5 call memset (12D1630h) 012D10CA add esp,0Ch } 012D10CD mov esp,ebp 012D10CF pop ebp 012D10D0 ret
元に戻すときは restore を指定する。
#pragma runtime_checks("s", restore)
組み込みの関数を使用する
これが通常のmemset呼び出し。
...
memset(&c, 1, sizeof(c));
012D10BD push 2
012D10BF push 1
012D10C1 lea ecx,[c]
012D10C4 push ecx
012D10C5 call memset (12D1630h)
...
#pragma intrinsicを使うと関数がインライン化される。ただし宣言時に初期化するコードには影響しない。
#pragma intrinsic(memset) void intrinsic_memset() { 012D10E0 push ebp 012D10E1 mov ebp,esp 012D10E3 push ecx char c[2] = {0}; 012D10E4 mov byte ptr [c],0 012D10E8 xor eax,eax 012D10EA mov byte ptr [ebp-3],al memset(&c, 1, sizeof(c)); 012D10ED mov ecx,1010101h 012D10F2 mov word ptr [c],cx } 012D10F6 mov esp,ebp 012D10F8 pop ebp 012D10F9 ret
関数呼び出しにしたいときは #pragma function を使う。
#pragma function(memset)
__security_check_cookie関数の呼び出しを抑止する
「バッファセキュリティチェック」で /GS- を指定すればよい。#pragma strict_gs_check(off) でうまくいくかと思ったが、これはなぜか機能しなかった。
参考と使ったコード
#include <windows.h> void enables_stackframe_verification() { char c[2] = {0}; memset(&c, 1, sizeof(c)); } #pragma runtime_checks("s", off) void disables_stackframe_verification() { char c[2] = {0}; memset(&c, 1, sizeof(c)); } #pragma intrinsic(memset) void intrinsic_memset() { char c[2] = {0}; memset(&c, 1, sizeof(c)); } #pragma function(memset) void enables_check_stack() { char c[100]; memset(&c, 1, sizeof(c)); } #pragma strict_gs_check(off) void disables_check_stack() { char c[100]; memset(&c, 1, sizeof(c)); } int main() { enables_stackframe_verification(); disables_stackframe_verification(); intrinsic_memset(); enables_check_stack(); disables_check_stack(); return 0; }