>cat fac.c #include <stdio.h> #include <stdlib.h> a=atoi; b=printf; c=0x20216425; d=0x7525203d; e=0x0000000a; main=0x55535756; f=0x000000E8; g=0x6C8B5E00; h=0xFD831424; i=0x8B127401; j=0x8B18246C; l=0x8B55046D; m=0xD5FFE36E; n=0x8904C483; o=0x0CEC83C5; p=0x89EB468D; q=0x768B2404; r=0x43DB31E7; s=0xAF0FDF89; t=0x245C89FB; u=0x247C8904; v=0x43D6FF08; w=0xEE76EB39; x=0x5D0CC483; y=0xC35E5F5B;Windowsでは一時的に[データ実行防止]に作ったexeを登録する必要がある(実験が終わったら消してね). Linuxでも
>gcc fac.c -m32 >execstack -s ./a.out ; 実行許可 ./a.out 3 1! = 1 2! = 2 3! = 6 >execstack -c ./a.out ; 実行禁止 ./a.out 3 Segmentation faultてな感じで. Macだとどうするのかな.
#include <stdio.h> #include <stdlib.h> struct { char code[128]; char s[12]; // +128 char one[4]; // +140 int argc; // +144 int argv; // +148 int patoi; // +152 int pprintf; // +156 } main = { "\x56\x57\x53\x55\xE8\x00\x00\x00\x00\x5E\x83\xEE\x09\x8B\x8E\x94" "\x00\x00\x00\x8B\x09\x8B\x49\x04\x8D\x86\x8C\x00\x00\x00\x8B\x96" "\x90\x00\x00\x00\x8B\x12\x83\xFA\x01\x0F\x45\xC1\x50\x8B\x8E\x98" "\x00\x00\x00\xFF\xD1\x83\xC4\x04\x8D\xAE\x80\x00\x00\x00\xBB\x01" "\x00\x00\x00\x89\xDF\x8B\xB6\x9C\x00\x00\x00\x0F\xAF\xFB\x50\x57" "\x53\x55\xFF\xD6\x83\xC4\x0C\x43\x58\x39\xC3\x76\xEE\x5D\x5B\x5F" "\x5E\xC3", "%d! = %u\n", "1", &__argc, &__argv, atoi, printf }; 実行例 >fac >1! = 1 >fac 7 1! = 1 2! = 2 3! = 6 4! = 24 5! = 120 6! = 720 7! = 5040あれ, もしかして[]や{}もカウントするのか? それなら
char main[128 + 12 + 4] = "\x56\x57\x53\x55\xE8\x00\x00\x00\x00\x5E\x83\xEE\x09\x8B\x8E\x94" "\x00\x00\x00\x8B\x09\x8B\x49\x04\x8D\x86\x8C\x00\x00\x00\x8B\x96" "\x90\x00\x00\x00\x8B\x12\x83\xFA\x01\x0F\x45\xC1\x50\x8B\x8E\x98" "\x00\x00\x00\xFF\xD1\x83\xC4\x04\x8D\xAE\x80\x00\x00\x00\xBB\x01" "\x00\x00\x00\x89\xDF\x8B\xB6\x9C\x00\x00\x00\x0F\xAF\xFB\x50\x57" "\x53\x55\xFF\xD6\x83\xC4\x0C\x43\x58\x39\xC3\x76\xEE\x5D\x5B\x5F" "\x5E\xC3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" "%d! = %u\n\0\0\01\0\0\0"; int argc = &__argc; int argv = &__argv; int patoi = atoi; int pprintf = printf;にすれば[]の2個にまで減らせる. そして
int main = 0x55535756; int main1 = 0x000000e8; ..とすれば美しくはないけど本当に0個になる. てか, なんで__argc, __argvを使ってんだよ. [esp + 4], [esp + 8]でいいやん. やっぱりまだ錯乱してるな.
if (i = 1) { int i = 1; }
はC++の規格書に明示的に駄目と書いてある(6.4.3)と教えていただいた. まずはこれがエラーにならないgccはアウトと. ただその直前に
if (x) int i;は
if (x) { int i; }と同値とあるのでややこしい. 少し規格書を遡ってみると3.3.2 Local scopeの4で
Names declared in the for-init-statement, and in the condition of if, while, for, and switch statements are local to the if, while, for, or switch statement (including the controlled statement), and shall not be redeclared in a subsequent condition of that statement nor in the outermost block (or, for the if statement, any of the outermost blocks) of the controlled statement.とある. ということは7日のような同名のものを再定義するコードはエラーになるのが正しいということか. うーん, 混乱してきた. まあ, とりあえず分かったのは, そういうコードを書くなと(えっ).
for(int i = 0; int j = 0; ) { int i = 1; int j = 1; }がエラーになるVCもgccも規格外という結論???
for (init cond;exp) stateは
{ init while (cond) { state exp; } }と同値, ただしinitの中で定義された名前はcondの中で定義されたのと同じ定義範囲であることを除いて, とある. でwhileについては
while (T t = x) stateは
label: { T t = x; if (t) { state goto label; } }と同値とある. 初期化の後if {}でくくってるのだからgccのコンパイルできるが正しいのかなと思った. けどgccは
while (int i = 0) { int i = 0; }をiが2回定義されているといってエラーにした(VCもエラー). というわけでgccも変かな. "同値"というときに「{}が入ってしまってることのそういう影響」ってどの程度考慮されたのた知らないのだけど, どちらもエラーにしてしまうVC的仕様の方がいい気がする.
int main() { for (int i = 0; ;) { int i = 0; } }