さらに、DLLだけでなく普通のexeファイルもこれに依存していることが分かりました。
そこで私は思いました。
o O (MS…VC?私が使っているのはgccなのに?というか、このファイルって多くのWindowsに存在するの?)
というわけで、C言語とgccでこのMSVCRT.DLLに依存しない実行ファイルが作れないか、調査してみることにしました。
ちょっと調べると、
MinGW GCCでlibcとしてmsvcrt.dll以外を使うまとめ - 自分についてのまとめサイト
というサイトが見つかりました。
o O (やったか?)
でも、よく見ると他のmsvcが入ったDLLを使っていました。これでは意味ないです。
次に、標準ライブラリを無効にしてコンパイルすることにしました。
多分、普通のWin32 APIは使ってもよいと思う[要出典]ので、GetStdHandle関数を使えば標準入出力もできます。
すると、__mainに対してundefined referenceが出ました。
-lgccを付けると、atexitという標準ライブラリに依存してしまい、ダメでした。
ということは、なんとかこの__mainという関数をでっちあげないといけなそうです。
試行錯誤の結果、結局 だけで実行できるようで、main関数の戻り値もきちんと%ERRORLEVEL%に反映されているようです。
ただし、argc,argvを用いてコマンドラインを受け取ることは、現時点ではできないようです。(今後の課題)
また、通常のC言語では、stdin,stdoutはテキストモードですが、Win32 APIを用いるとバイナリモード相当になるようです。
今日の成果
・MSVCRT.DLLに依存しない実行ファイルでHello, worldを表示できた
#include
int main(void) {
HANDLE hStdout=GetStdHandle(STD_OUTPUT_HANDLE);
const char* hw="Hello, world\r\n";
DWORD written=0;
WriteFile(hStdout,hw,lstrlen(hw),&written,NULL);
return 0;
}
int __main(void) {
return 0;
}
#include
int main(int argc,char* argv[]) {
HANDLE hStdin=GetStdHandle(STD_INPUT_HANDLE);
HANDLE hStdout=GetStdHandle(STD_OUTPUT_HANDLE);
DWORD written=0;
DWORD read=0;
char buffer[1024]={0};
for(;;) {
if(!ReadFile(hStdin,buffer,sizeof(buffer),&read,NULL) || read==0)break;
WriteFile(hStdout,buffer,read,&written,NULL);
}
return 0;
}
int __main(void) {
return 0;
}
今回のHello, worldは3,072バイトと、サイズも小さくなっています。(どちらもstrip済)でも、これはおまけ程度ですね。
まだKERNEL32.DLLには依存していますが、さすがにこれはほとんどのWindowsに入っていますよね…[要出典]
今後の課題
・argc,argvに対応
・標準ライブラリの実装(signalとかsetjmpとか、ほとんど使わなそうなものは一部切り捨てていい?)
成果物を添付ファイルにしました。
オフトピック
待てよ…もしもVisual C++のライブラリを使っているなら、fopen_sとかも使えるのではないのか…?
使えないということは、別物なんじゃないのか?
使えないということは、別物なんじゃないのか?