【问题标题】:Same binary code on Windows and Linux (x86)Windows 和 Linux (x86) 上的相同二进制代码
【发布时间】:2010-11-18 16:10:55
【问题描述】:

我想将一堆 C++ 文件编译成原始机器代码,并使用用 C 编写的依赖于平台的启动器运行它。类似于

fread(buffer, 1, len, file);
a=((\*int(\*)(int))buffer)(b);

如何让 g++ 输出原始代码?

函数调用会起作用吗?我怎样才能让它发挥作用?

我认为 Linux 和 Windows 的调用约定不同。这是一个问题吗?我该如何解决?

编辑:我知道 PE 和 ELF 会阻止可执行文件的直接启动。但这就是我的首发。

【问题讨论】:

  • 不会发生 - 两种完全不同的目标文件格式
  • 虽然我没有资格回答,但似乎这样的事情应该是可能的。如果我可以编写不依赖于任何标准库的代码,就像嵌入式系统一样,那么它应该可以在任何 x86 芯片上运行,不是吗?
  • 看到这个问题superuser.com/questions/209703/… -- 简答 ELF (linux) vs. PE (windows)
  • 一个包含可执行代码的文件不仅仅是机器级指令。数据段等,因此该文件必须与您的平台兼容,这意味着它需要是 ELF 或 PE。换句话说,您可以保存带有机器指令的二进制 blob 文件并运行它,即使您有一个依赖于平台的启动器。

标签: c++ assembly x86 linker g++


【解决方案1】:

有一种(相对)简单的方法可以实现其中的一些,这就是所谓的“位置无关代码”。请参阅您的编译器文档。

这意味着您可以将一些源代码编译成二进制文件,无论您将其放在地址空间中的哪个位置,它都会执行。如果你在一个文件中有这样一段 x86 二进制代码并且 mmap() 它(或 windows 等效),则可以从 Linux 和 Windows 调用它。

已经提到的限制当然仍然存在 - 即,二进制代码必须限制自己使用在两个平台上相同的调用约定/可以在两个平台上表示(对于 32 位 x86,这将在EAX 中的堆栈和返回值),当然代码必须是完全自包含的 - 没有 DLL 函数调用,因为解决这些问题取决于系统,也没有系统调用。

即:

  1. 您需要与位置无关的代码
  2. 您必须创建没有任何外部依赖项的自包含代码
  3. 您必须从目标文件中提取机器代码。

然后 mmap() 那个文件,初始化一个函数指针,(*myblob)(someArgs) 就可以了。

如果您使用 gcc,“-ffreestanding -nostdinc -fPIC”选项应该可以为您提供关于前两个的大部分内容,然后使用 objdump 从 ELF 目标文件中提取二进制 blob。

【讨论】:

    【解决方案2】:

    理论上,其中一些是可以实现的。然而,一路走来有太多的陷阱,以至于它并不是任何事情的实际解决方案。

    • 系统调用格式完全不兼容
    • DEP 将阻止数据作为代码执行
    • 内存布局不同
    • 您需要先有效地动态“重新链接”代码,然后才能运行它。
    • ..等等...

    【讨论】:

    • 你有链接吗?我想我可以将一个函数指针传递给包含的代码,该代码指向一个执行平台相关操作的函数。就像系统调用一样。
    【解决方案3】:

    同一可执行文件不能同时在 Windows 和 Linux 上运行。

    您独立编写代码平台(STL、Boost 和 Qt 可以提供帮助),然后在 Linux 上用 G++ 编译以输出 linux 二进制文件,类似地在 Windows 平台上的编译器上。

    编辑:另外,也许这两个帖子可以帮助你:

    One

    Two

    【讨论】:

    • 是什么让这两个平台不兼容?两者都使用 x86。
    • x86 是一系列指令集架构,与可执行文件和操作系统的结构无关。我已经用我发布的有关跨平台编程的其他一些答案更新了我的帖子。
    【解决方案4】:

    你为什么不看看酒?它用于在 Linux 上使用 Windows 可执行文件。另一种解决方案是使用 Java 或 .NET 字节码。

    您可以在 Linux 上运行 .NET 可执行文件(需要单运行时)

    还可以查看 Agner 的 objconv(反汇编、将 PE 可执行文件转换为 ELF 等) http://www.agner.org/optimize/#objconv

    【讨论】:

      【解决方案5】:

      做这样的事情会相当复杂。这不仅仅是发出 cpu 命令的问题,编译器还依赖于许多将链接到代码中的库。这些库必须在运行时匹配,否则将无法工作。

      例如,STL 库是一系列模板和库函数。编译器将内联一些构造并为其他构造调用库。它必须是完全相同的库才能工作。

      现在,理论上您可以避免使用任何库而只编写基础知识,但即便如此,编译器也可能会对它们的工作方式、涉及的数据对齐类型、调用约定等做出假设。

      不要误会我的意思,它可以工作。查看在 Linux 上使用的 Windows 中的 WINE 项目和其他本机驱动程序。我只是说这不是您可以快速轻松地做到的事情。

      最好在每个平台上重新编译。

      【讨论】:

        【解决方案6】:

        只有在您的 Linux 系统上有 WINE 可用时,才能实现这一点。否则,可执行文件格式的差异将阻止您在 Linux 上运行 Windows 代码。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-09-16
          • 1970-01-01
          • 2021-07-27
          • 2014-09-28
          • 2012-03-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多