2

最近、これを 64 ビット コードで実行できることに気付きました。

  const size_t kLowStackSize = 1024UL * 1024UL * 4UL;
  void *low_stack = mmap(NULL, kLowStackSize, PROT_READ | PROT_WRITE,
      MAP_PRIVATE | MAP_ANONYMOUS | MAP_32BIT, -1, 0);
  struct __attribute__((packed, aligned(16))) {
    int32_t address;
    int16_t segment;
  } target = {(uint32_t) (uint64_t) code, 0x23};
  asm volatile(
      "mov %%rsp, %%r8\n"
      "mov %[stack], %%rsp\n"
      "push %%r8\n"
      "lcall *(%[target])\n"
      "pop %%rsp"
      :
      : [stack] "r" (low_stack + kLowStackSize), [target] "r" (&target)
      : "r8");

ここcodeで、アドレス空間の下位 4GiB の実行可能ページにある 32 ビット コードの一部を指し、Linux の x86 ヘッダーのセグメント セレクター0x23の値です。__USER32_CSジャンプ対象に属性が必要かどうかはわかりませんが、念のため追加しました。もちろん、far return を可能にするには、この呼び出しコード自体を仮想アドレス空間の下位 4 GiB のどこかに配置する必要があります。に入れるだけmainで十分であることがわかりました。

これはほとんど役に立たず (32 ビット ライブラリがロードされていない、呼び出し規約が異なるなど)、破損しやすい (の値は__USER32_CSLinux のユーザー空間向け API の一部ではない) ことを理解しています。

私の質問:呼び出しのターゲットが実際に 32 ビット モードで実行されていることを示す簡単な方法はありますか? この種の呼び出しの実用的な用途 (それを利用するライブラリの既存のソフトウェア、または少なくともそれほど非現実的ではない可能性) はありますか?

4

1 に答える 1