参考記事
TopCoderのスタックサイズの増やし方 – 赤コーダーになりたい
本文
kusanoさんに情報提供した際に、「スタック書き換えるからスタック上の関数スコープ変数とか全部使えなくなるよ(意訳)」みたいなことを言ったものだから、その通りの内容で記事を書いて頂く結果になりました。
しかし、よくよく考えれば、rsp以外にもrbpがある。
gccでは関数スコープ変数で可変長配列が可能なので、関数スコープ変数へのアクセスがrbpであることが保証されるはず……と思ったのですが、可変長配列が使われていない場合は-O2オプションでrbpが使われることが保証されない様でした。
だったら可変長配列を強制すれば良いのではないか、と思いまして。
allocaを入れることで、この問題は解決しました。
#define BEGIN_STACK_EXTEND(size) void * stack_extend_memory_ = malloc(size);void * stack_extend_origin_memory_;char * stack_extend_dummy_memory_ = (char*)alloca((1+(int)(((long long)stack_extend_memory_)&127))*16);*stack_extend_dummy_memory_ = 0;asm volatile("mov %%rsp, %%rbx\nmov %%rax, %%rsp":"=b"(stack_extend_origin_memory_):"a"((char*)stack_extend_memory_+(size)-1024)); #define END_STACK_EXTEND asm volatile("mov %%rax, %%rsp"::"a"(stack_extend_origin_memory_));free(stack_extend_memory_);
上記の様なマクロをあらかじめ定義しておいて……
class PairGame{public: int maxSum( int a, int b, int c, int d ) { BEGIN_STACK_EXTEND(128*1024*1024); // メインの処理 f1(a, b, 1234567, 1234567); int r = f2(c, d); END_STACK_EXTEND; return r; }};
とするだけで、問題なくいけました。
捕捉(追記)
インライン展開等によって、しばらくは書き換え前のスタックが使われる場合があることが確認されています。
ただ、その場合であっても、階層が深くなる場合、どこかのタイミングで書き換え後のスタックが使われる様になることが確認されています。
また、現時点では確認した全ての状況で上記マクロで問題なく動いていますが、上記マクロで問題なく動かないケースがあるかもしれません。
そういうケースが見つかった場合は、問題番号と不具合の生じたコードとどういう不具合であるかを、colunまでご一報頂ければ幸いです。
蛇足
今回はコンテストプログラミングの話題なのでkusanoさんの記事では触れてもらえませんでしたが、例外処理(try catch finally等)を使う場合は、セグメントレジスタの書き換えも必要だった気がします。(うろ覚え)(たしかSSではなくFSだったと思いますが…Windows環境だけだったかも? 分かりません。記憶ではFS[0]とFS[1]が……ぶつぶつ)
コメントを残す