フリースタンディング環境

出典: フリー百科事典『ウィキペディア(Wikipedia)』
移動先: 案内検索

フリースタンディング環境(— かんきょう, freestanding environment)はC言語およびC++の実行環境の一種である。対義語はホスト環境 (hosted environment) 。ISO のC言語の仕様で規定されている。

概要

ホスト環境では、標準Cライブラリによる実行時サポートがあるのに対して、フリースタンディング環境にはそのような物がなく、標準Cライブラリの大半が使えない。ただし、どちらであっても、オペレーティングシステム上で動作している場合は、オペレーティングシステムの機能を呼び出すことは出来る。

組み込みシステムでは、通常、特に実行環境を指定しない場合は、ホスト環境を対象にしていることが多いが、フリースタンディング環境を対象にすることも多い。μITRONはオペレーティングシステムの一種であるが、現実的にはフリースタンディング環境に分類される場合が多い。

制限

フリースタンディング環境では言語仕様に以下の制限を受ける。

  • エントリーポイントはmain関数である必要はなく、関数の型および名称は処理系定義となる。GCC の場合、デフォルトは void _start(void)
  • 標準ライブラリの大部分がサポートされない。フリースタンディング環境でもサポートされる標準ライブラリを以下に挙げる。
    • C89の場合、<float.h>、<limits.h>、<stdarg.h>、<stddef.h>
    • C95の場合、C89の標準ライブラリ、<iso646.h>
    • C99の場合、C95の標準ライブラリ、<stdbool.h>、<stdint.h>
    • C11の場合、C99の標準ライブラリ、<stdalign.h>、<stdnoreturn.h>
    • C++03の場合、<exception>、<limits>、<cstdarg>、<cstddef>、<cstdlib>(abort、atexit、exitのみ)、<new>、<typeinfo>

この Hello worldGCCLinux の組み合わせで動作する。gcc -ffreestanding -nostartfiles -static -o freestanding freestanding.c でコンパイルする。exit は各種終了処理を行う stdlib.h の関数のためフリースタンディング環境では使えないが、_exit は unistd.h で定義されたシステムコールを呼び出すだけの POSIX の関数のため GCC の Linux 用フリースタンディング環境でも使える。

#include <unistd.h>

void _start(void)
{
    char msg[] = "Hello, world!\n";
    write(1, msg, sizeof(msg));
    _exit(0);
}

標準Cライブラリなし

類似概念として、コンパイラによっては標準Cライブラリなしでコンパイルすることも可能。例えば GCC の場合、-nostdlib を指定することにより、標準Cライブラリを使わなくなる。さらに制限は厳しくなる。フリースタンディング環境同様、終了処理すら行わないため、コンパイル結果を Linux で動作させる場合、エントリーポイントの最後などで OS のシステムコールの exit を呼び出してプロセスを殺す必要があり、フリースタンディング環境の場合は、GCC と Linux の組み合わせの場合、_exit(0) で終了させられるが、標準Cライブラリがないため、そのコードは OS と CPU 種別依存のアセンブラで書かないといけない。スタックに関しては、Linux の場合、execve システムコールがスタックを準備するため、スタックは正しく準備された状態でエントリーポイントが呼び出される。

この標準Cライブラリ未使用の Hello worldGCC, Linux, x86-64 の組み合わせで動作する。gcc -nostdlib -fno-builtin -static -o nostdlib nostdlib.c でコンパイルする。

static void write(long fd, const void *buf, unsigned long count)
{
    __asm__ volatile (
        "movq %0, %%rax \n\t"
        "movq %1, %%rdi \n\t"
        "movq %2, %%rsi \n\t"
        "movq %3, %%rdx \n\t"
        "syscall        \n\t"
        :
        : "i" (1), "r" (fd), "r" (buf), "r" (count)
        : "%rax", "%rdi", "%rsi", "%rdx");
}

static void _exit(long status)
{
    __asm__ volatile (
        "movq %0, %%rax \n\t"
        "movq %1, %%rdi \n\t"
        "syscall        \n\t" 
        :
        : "i" (60), "r" (status)
        : "%rax", "%rdi");
}

void _start(void)
{
    write(1, "Hello, world!\n", 14);
    _exit(0);
}

テンプレート:Sister テンプレート:CProLang