exeGCC for SOLID s002 (ARM) ライブラリ仕様

本文章は s007 のリリース時に、遡ってアップデートされました。後から判明した機能制限(未実装)など、s002 リリース当時のドキュメントには記載されていない情報も含まれています。

ライブラリの共通設定

全てのライブラリは以下の設定でビルドされています。

  • char 型は signed。(-fsigned-char

  • 列挙型は 4 または 8 バイト。(-fno-short-enums

  • aligned data access。(-mno-unaligned-access

C11/C++14 標準関数サポート

  • libc と libm は NetBSD-7.0 ベース

    注釈

    非標準の関数や BSD 独自の関数は、過去の exeGCC との互換性やライブラリ内部で使用している等の理由により存在していますが、サポート範囲外となります。もし必要な場合は自己責任で使用してください。ヘッダには存在しますが、実体が存在しない関数も多数あります。

    • KMC による標準関数の実装

      abort(), exit(), perror(), setjmp(), longjmp(), strerror(), strerror_r(), signal(), raise()

      time.h

      clock(), difftime(), mktime(), time(), asctime(), ctime(), ctime_r(), gmtime(), localtime(), localtime_r(), strftime()

      • time_t は 64 bit です。

      • clock() はダミー実装です。初回の呼び出しは必ず 0 になり、2 回目以降は 10msec 精度カウンタの前回呼び出し時との差分を返します。

      • time_t はうるう秒未考慮です。

      • タイムゾーン未考慮(UTC のみ、常に GMT=UTC)なため、デバッグ時のみご利用ください。

    • malloc, free, realloc, calloc は dlmalloc 2.8.6 を使用しています。

  • VFP/FPU が有効なターゲットは RunFast モードで浮動小数点数演算を行います。

    注釈

    これはライブラリのビルド設定ではなく、exeGCC 付属のスタートアップルーチンの設定です。SOLID は自前のスタートアップルーチンを使用するため無関係となります。

    • 付属のスタートアップルーチンでは RunFast モードを選択しています。これによりパフォーマンスが向上します。

    • RunFast モードは以下のような設定となります。

      • flush-to-zero モード(FTZ)

        非正規数やアンダーフローを 0 に丸めます。NEON 命令は常にこの FTZ モードです。

      • デフォルト NaN モード(DN)

        IEEE754 仕様では指数部が全て 1 で仮数部が 0 以外の任意のビットパターン(値)を NaN として扱います。そして NaN が入力された場合、その値を結果にそのまま伝搬します。一方 DN モードでは NaN が入力されたり演算結果が NaN になった場合、デフォルトの NaN 値を返します。デフォルト NaN のビットパターンはハードウェアの実装依存となります。NEON 命令は常にこの DN モードです。

      • 浮動小数点数例外は発生しません。

        数学関数のエラーは errno で判定します。

  • ロケールは "C" のみサポート

    • *_l (locale) 関数は、対応する _l の無い関数と同じ挙動となります。

  • OS の機能を使用するような関数は、VLINK 有効時のみサポート

    • signal.h はダミー関数です。

      signal(), raise()

    • __SOFTFP__fenv.h feraiseexcept() は例外を発生させません。

    • stdio.hprintf() やファイル関係の関数、tmpnam() など。

    • stdlib.hgetenv(), setenv() など。

      system() は未サポート。

    • time.hclock(), time(), utime()

    • 以下の非標準関数(KMC による実装)

      rename(), getcwd(), getwd(), open(), creat(), close(), lseek(), read(), write(), unlink(), tell(), dup(), dup2(), access(), chdir(), rmdir(), findfirst(), findnext(), stat(), fstat(), lstat(), mkdir(), chmod(), mktemp(), sleep(), usleep()

      • stat(), fstat(), lstat(), utime() の制限

        MS-DOS Data and Time (FILETIME) を使用しているので、保証されるのは 1980/1/1-2107/12/31 の範囲です。

      • usleep() の制限

        millisecond 精度です。

未サポートの機能

  • GCC の float.h の制限で FLT_ROUNDS は常に 1 (nearest) となります。fenv.hfegetround() で現行の丸めモードを取得してください。

  • long double

    math.h, complex.h ヘッダの *l 関数など。

    例: long double sinl(long double x)

    nexttoward(), nexttowardf(), nexttowardl()

  • C99

    • math.h

      fma(), fmaf()

      FP_FAST_FMA, FP_FAST_FMAF, math_errhandling, MATH_ERRNO, MATH_ERREXCEPT

  • C11

    • uchar.h

    • time.h

      struct timespec, timespec_get()

    • stdio.h

      fopen() mode "x"

      Remove gets()

      Annex F/G/K/L [Optional]

    • stdlib.h

      aligned_alloc (s002 readme 未記載。)

    • C++11

      random ヘッダ

      random_device

    • マルチスレッド

      • C11

        stdatomic.h, thread.h ヘッダ [Optional]

      • C++

        auto_ptr は C++11 以降非推奨のため未サポート扱い

      • C++11

        atomic, thread, mutex, future, condition_variable ヘッダ

        shared_ptr はスレッドアンセーフ

      • C++14

        shared_mutex ヘッダ

        weak_ptr の lock() はスレッドアンセーフ

      • TLS (Thread Local Storage)

        GCC 拡張の __thread, C11 の _Thread_local, C++11 の thread_local キーワード

    • PCH (PreCompiled Header)

    • LTO (Link Time Optimization)

ワイド文字(列)の扱いについて

ワイド文字型 wchar_t は 4 バイト(UTF-32 LE)です。(GCC/Clang の仕様)

C11 の uchar.h は未サポートです。

ワイド文字列リテラル L"..." と C11 の U"..." は同じ意味となり、-fexec-charset オプションによる文字集合指定とは無関係に、必ず UCS4 (Unicode) コードポイントの配列になります。

注釈

つまり、仮に -fexec-charset=cp932 を指定したとしても、JIS X 0208 のコードポイント配列にはならないため、ワイド文字列リテラルをソースコード中に直接記述することはできません。これは GCC の仕様です。Clang はそもそも -finput-charset/-fexec-charset オプション未サポートなので、常に UCS4 文字集合を UTF-8/32 エンコーディングで扱う仕様となります。

ライブラリがサポートするロケールは "C" のみですが、マルチバイト文字列(mbs)とワイド文字列(wcs)を変換する際に必要となる、LC_CTYPE のみ、"C", "utf-8", "cp932" が指定可能です。デフォルトの LC_CTYPE"C" となります。UTF-8(ASCII の範囲外の文字)を使用する場合は setlocale(LC_CTYPE, "utf-8") 呼び出しが mbs/wcs 系関数を呼び出す前に必要です。

ワイド文字列からマルチバイト文字列への変換サンプル:

#include <locale.h> /* setlocale */
#include <stdlib.h> /* wcstombs */

/* ... */

wchar_t wcstr[] = L"この文字列は UCS4 文字集合を UTF-32 LE エンコーディングしたものとなります。";
int result;
char utf8buf[256];

/* 確認のため SOLID OS の syslog を使用します。 */
syslog_msk_log(LOG_UPTO(LOG_INFO), LOG_UPTO(LOG_INFO));

result = wcstombs(utf8buf, wcstr, 256);

/* デフォルトの "C" = ASCII 範囲外の文字を含むため失敗します。*/
if (result < 0) {
    syslog(LOG_INFO, "XFAIL: please setlocale()");
}

/* utf-8 に設定します。*/
syslog(LOG_INFO, "setlocale:%s", setlocale(LC_CTYPE, "utf-8"));

/* UTF-32 LE -> UTF-8 */
result = wcstombs(utf8buf, wcstr, 256);

if (result < 0) {
    syslog(LOG_INFO, "FAIL");
} else {
    syslog(LOG_INFO, "SUCC: %s", utf8buf);
}

TeraTerm (UTF-8) での出力例:

XFAIL: please setlocale()
setlocale:UTF8
SUCC: この文字列は UCS4 文字集合を UTF-32 LE エンコーディングしたものとなります 。