VC++にみるアンマネージコード(ネイティブコード)のコンパイル

《 初回公開:2019/11/24 , 最終更新:未 》

.NET Frameworkの周辺」でマネージコードのコンパイルについてかるくふれた。
今回は、アンマネージコードのコンパイルについてみてみる。

【 目次 】

コンパイルとビルド

コンパイルとビルド、実行ファイルができるまでの流れ。

コンパイル obj lib ビルド リンカー

コンパイラ
C/C++で書かれたファイルをアセンブラ言語のファイルに変換する処理のこと
ソースファイルの数だけ作成
obj
オブジェクトファイルまたはバイナリファイルと呼ばれる。
オブジェクトファイルの中身をオブジェクトコードと呼ぶ
リンカ
複数のオブジェクトファイルを1つにまとめる作業を
コンパイル
ソースコードをコンパイル⇒オブジェクトファイル
リンク
オブジェクトファイルobj(+ライブラリーlib)をリンク⇒実行ファイルexe

ライブラリー

コンパイラのオプションを適当に指定してビルド

静的リンクライブラリ(static link library)
ライブラリのソースコードを事前にコンパイルしオブジェクトコードの状態で配布する方式を静的リンクライブラリといいます。
動的リンクライブラリ(dynamic link library)
実行時にリンクを行う方式

オブジェクトファイル,オブジェクトコードとリンカーの再配置

  • オブジェクトファイル - Wikipedia

    オブジェクトファイル (object file) またはオブジェクトコード (object code) とは、コンパイラがソースコードを処理した結果生成される、コード生成の結果であるバイナリコードを含む中間的なデータ表現のファイルである。
    中身は、機械語バイナリとそれに付随するシンボルテーブルやリロケーションテーブルといった付加情報であり、さらにデバッグ支援情報や近年はリンク時最適化等のための高度な情報が含まれる場合もある。
    オブジェクトファイル群をリンクすることによって最終的な実行ファイルやライブラリが作成される。
    ...
    オブジェクトファイルにはオブジェクトコードだけでなく、リンカが実行ファイルやライブラリを作成するときに使用するリロケーション情報、プログラム内のシンボル情報、デバッグ情報などが含まれる。

  • 先輩教えて!プログラミングのabc(第1回)---コンパイルとビルドって何が違うの(中) | 日経 xTECH(クロステック)

    もう一つリンクの重要な役割は,参照しているアドレスの確定である。
    コンパイルした結果は,実行モジュールのどの位置に配置されるか決まっていない。
    逆に言えば場所を変更できる,つまり再配置可能な状態にある。
    これをリロケータブル・オブジェクトと呼ぶ注3)。
    UNIXでは「.o」,Windowsでは「.obj」という拡張子で表現されることが多い。

そもそもコンパイラとは(コンパイラがやっている事は)

Translator(翻訳)
Translatorとは、一つのプログラミング言語(Source Language: 原始言語)で書かれたプログラムを入力として取り、別の言語(Object Language or Target Language: 目的言語)のプログラムとしてつくり出すプログラムです。
コンパイラ
原始言語が FORTRAN, C, Pascal などの高水準言語で、目的言語がアセンブリ言語や機械語といったような低水準言語である時、そのような Translator をコンパイラ(Compiler) と呼びます。
アセンブラ
原始言語がアセンブリ言語で目的言語が機械語であるものをアセンブラ(Assembler)
プリプロセッサ
ある高水準言語から別の高水準言語に変換するものをプリプロセッサ(Preprocessor) と呼びます。

コンパイラのPhase (構造)

コンパイラは、フェーズと呼ばれる幾つかの行程を経て高級言語を低水準言語に翻訳します。

  • 字句解析 (Lexical Analyzer)

    Source Program とコンパイラとのインターフェース。
    Source Program を 1文字ずつ組み込み、字句(トークン) と呼ぶ一連の単位に刻んでいきます。

  • 構文解析 (Syntax Analyzer)

    A+B といったような式がまとまった文などを解析します。
    構文構造は、トークンが言語仕様によって許されているパターンと合致するかどうか検査します。
    トークンを葉とするような Parse Tree (解析木)と呼ばれるツリー構造にはめ込みます。

  • 中間コード生成 (Intermediate Code Generation)

    中間コードを機械語命令の列に変換します。

  • 最適化 (Optimization)

    オブジェクト・プログラムのコードサイズを小さくし、実行スピードを速くするために中間コードの変換を施します。

  • コード生成 (Code Generation)

    中間コードを機械語命令の列に変換します。

Cプログラムの作成と実行

  1. ソースプログラム(ソースコード)をテキストエディタで作成し1個のソースファイルとして保存する。
  2. 実行可能プログラムファイルの作成:OS上で実行可能な機械語プログラムに翻訳する。
    • プリプロセス(前処理):ソースプログラムを 整形しコンパイル用のソースプログラムを作る。
    • コンパイル:前処理済のソースプログラムを機械語に翻訳しオブジェクトファイルを作成。
    • リンク:オブジェクトファイルに既存のライブラリから使 う機械語プログラムを取り込んで結合。
  3. 実行:OSを使って実行可能ファイルをメモリーに読み込んで実行する 。

VC++のコンパイルとリンク

コマンドラインでVC++のコンパイル

  • コンパイルとリンク方法 - Web/DB プログラミング徹底解説

    また、GetLastNameA のように、関数名の最後に A または W が付いている場合はそれはそれぞれ次のように解釈します。
    A は、Non-Unicode ビルド用の関数であることを示します。ANSI ビルドなどと言われます。 W は Unicode ビルド用の関数です。
    Windows の API はほぼ全てマクロとして実装されており、同じ API を使っているつもりでもコンパイルの仕方によって (コンパイルオプションによって)、 ANSI ビルド用のコード、あるいは Unicode ビルド用のコードとしてコンパイルされます。
    何も指定しないと、ANSI ビルドになります。
    ANSI ビルドは、内部的にマルチバイトキャラクタと Unicode との変換が発生するため、効率が悪い上に文字化けの原因にもなります。 DLL や EXE ファイルのサイズが気にならないなら、常に Unicode ビルドを行うと良いでしょう。
    補足: 別の機会に詳述しますが、Unicode ビルドを行う場合、UNICODE と _UNICODE の二つの定数を指定します。
    ...
    ここで C ランタイムライブラリや kernel32.lib はデフォルトでリンクされますからそれらを明示的に指定する必要はありません。

上記の記事によりコマンドラインよりコンパイルを試してみる。

ANSI ビルド

cl /c test.cpp
link advapi32.lib test.obj

Unicode ビルド

cl /DUNICODE /D_UNICODE /c test.cpp
link advapi32.lib test.obj

「ANSI ビルド」と「Unicode ビルド」については

依存ライブラリーの確認は

dumpbin /SYMBOLS test.obj | findstr External

以下のソースをコンパイルするとエラーになってしまった。

#include <iostream>
using namespace std;
void main()
{
    cout << "Hello, world, from Visual C++!" << endl;
}

何故だか調べる気力が無いが、コンパイラオプション/EHscが必要らしい。

コンパイラオプション等

その他のVC++に関する参考URL

VisualStudioIDEでC++

マイクロソフトソフトのC言語関係のリファレンス

windows api 一覧

ページのトップへ戻る