web-dev-qa-db-ja.com

Linuxの32ビットプログラムで64ビットtime_tを取得する方法はありますか?

Windowsでは、次のように呼び出すことができます。

_time32(__time32_t); // to get 32-bit time_t
_time64(__time64_t); // to get 64-bit time_t

(32ビットプログラムと64ビットプログラムの両方)

Linux(GCCでコンパイル)でこれを行う方法はありますか?

16
chiyer

どうやら、それは不可能です。手始めに、Linuxにはtime()関数が1つだけあり、time32()またはtime64()はありません。

しばらく検索したところ、libcのせいではないことがわかりましたが、原因は実際にはカーネルです。

Libcが現在の時刻をフェッチするには、次のシステムコールを実行する必要があります。 ソース

_time_t time (t) time_t *t;
{
    // ...
    INTERNAL_SYSCALL_DECL (err);
    time_t res = INTERNAL_SYSCALL (time, err, 1, NULL);
    // ...
    return res;
}
_

システムコールは次のように定義されます。 ソース

_SYSCALL_DEFINE1(time, time_t __user *, tloc)
{
    time_t i = get_seconds();
    // ...
    return i;
}
_

関数get_seconds()は、次のように_unsigned long_を返します。 ソース

_unsigned long get_seconds(void)
{
    struct timekeeper *tk = &timekeeper;

    return tk->xtime_sec;
}
_

そして、_timekeeper.xtime_sec_は実際には64ビットです: ソース

_struct timekeeper {
    // ...
    /* Current CLOCK_REALTIME time in seconds */
    u64                     xtime_sec;
    // ...
}
_

さて、あなたがあなたのCを知っているなら、あなたは_unsigned long_のサイズが実際には実装に依存していることを知っています。ここにある私の64ビットマシンでは、64ビットです。しかし、ここの私の32ビットマシンでは、32ビットです。 おそらく一部の32ビット実装では64ビットである可能性がありますが、保証はありません。

一方、_u64_は常に64ビットであるため、カーネルは基本的に64ビット型で時間を追跡します。その後、64ビット長が保証されていない_unsigned long_としてこれを返す理由は私にはわかりません。

結局、libcが_time_t_に64ビット値を保持するように強制したとしても、それは何も変更しません。

アプリケーションをカーネルに深く結び付けることもできますが、それだけの価値はないと思います。

13
netcoder

time64()/time32()関数は標準ライブラリに含まれていません。

標準ヘッダーでは、time32_t/time64_t定義は考慮されていません。

time_ttime.htypedef __time_t time_tとして定義されています。

再定義の長いチェーンに続いて、__time_tが32ビットマシンでは32ビット、64ビットマシンでは64ビットとして定義されていることがわかります。

7
Davide Berra

上記の多くの回答は、これは不可能であると述べていますが、それは完全に間違っています。当時は不可能でしたが、人々は何年もの間 それを修正することについて話していました でした。最後に、32ビットプラットフォームでの64ビット時間のサポートは Linux 5.1カーネルに導入されました 新しい _*time64_ syscalls が追加されました。 この表 を見てください。これらのシステムコールは64ビットプラットフォームでは使用できないことがわかります。 32ビットシステムのコードを記述している場合は、_clock_gettime64_を直接(インラインアセンブリまたはCから syscall() を使用して)呼び出して、現在の時刻を取得できます。

しかしその後、あなたは完全にあなた自身になります。完全なuserspaceサポートが必要な場合は、Linux5.6以降とmusl1.2 +またはglibc2.32 +を使用している必要があります。コードを再構築するだけで、_time_t_は64ビット長になります

  • すべてのユーザースペースは、64ビットの_time_t_でコンパイルする必要があります。これは、今後のmusl-1.2およびglibc-2.32リリースでサポートされ、linux-5.6以降のカーネルヘッダーがインストールされます。

  • システムコールインターフェイスを直接使用するアプリケーションは、既存のシステムコールの代わりにlinux-5.1で追加されたtime64syscallを使用するように移植する必要があります。これは、futex()seccomp()のほとんどのユーザー、およびlibcに基づかない独自のランタイム環境を持つプログラミング言語に影響を与えます。

https://lkml.org/lkml/2020/1/29/355?anz=web

詳細については

1
phuclv

あなたが本当にこれを必要とするならば、なぜあなた自身を転がしてみませんか?

_typedef int32_t my_time32;
typedef int64_t my_time64;


my_time32 get_mytime32() {
    if (sizeof(time_t) == sizeof(my_time32))
        return time(NULL);
    else {
        /* Check for overflow etc. here... */
        return (my_time32)(time(NULL));
    }
}
_

同様にget_mytime64()についても同様です。

オーバーフローを気にしない場合は、Cの暗黙的な数値変換のおかげで、単純なreturn time(NULL);が両方の関数で機能します。

0
Nemo

このライブラリを使用してください: https://github.com/evalEmpire/y2038

このプロジェクトの目標は、POSIX time.hのドロップイン置換を提供することです。これは、32ビットのtime_tを持ちながら、2038バグの影響を受けていないマシンで動作します。これにより、Cプログラマーは、ソフトウェアを新しいインターフェイスに書き直すことなく、2038年に安全になります。これは、システムタイムゾーンデータベースを使用しながら行います。

0
amadvance