HTML5技术

如何实现在Windows上运行Linux程序,附示例代码 - q303248153(9)

字号+ 作者:H5之家 来源:H5之家 2017-05-16 14:00 我要评论( )

我们需要模拟的64位Linux程序,它传参使用了System V AMD64 ABI标准, 先把参数按RDI, RSI, RDX, RCX, R8, R9的顺序设置,如果有再多参数就放在栈中. 而64位的Windows传参使用了Microsoft x64 calling convention标

我们需要模拟的64位Linux程序,它传参使用了System V AMD64 ABI标准, 先把参数按RDI, RSI, RDX, RCX, R8, R9的顺序设置,如果有再多参数就放在栈中.
而64位的Windows传参使用了Microsoft x64 calling convention标准, 先把参数按RCX, RDX, R8, R9的顺序设置,如果有再多参数就放在栈中, 除此之外还需要预留一个32字节的影子空间.
如果我们需要让Linux程序调用Windows程序中的函数, 需要对参数的顺序进行转换, 这就是上面的汇编代码所做的事情.

转换前的栈结构如下

[原返回地址 8bytes] [第七个参数] [第八个参数] ...

转换后的栈结构如下

[返回地址 8bytes] [影子空间 32 bytes] [第五个参数] [第六个参数] [第七个参数] ...

因为需要支持不定个数的参数, 上面的代码用了一个thread local变量来保存原返回地址, 这样的处理会影响性能, 如果函数的参数个数已知可以换成更高效的转换代码.

在设置好动态链接的函数地址后, 我们完成了构想中的第4步, 接下来就可以运行主程序了

// 获取入口点 std::uint64_t entryPointAddress = *reinterpret_cast<const std::uint64_t*>(elfHeader.e_entry); void(*entryPointFunc)() = reinterpret_cast<void(*)()>(entryPointAddress); std::cout << "entry point: " << entryPointFunc << std::endl; std::cout << "====== finish loading elf ======" << std::endl; entryPointFunc();

入口点的地址在ELF头中可以获取到,这个地址就是_start函数的地址, 我们把它转换成一个void()类型的函数指针再执行即可,
至此示例程序完成了构想中的所有功能.

执行效果如下图

这份示例程序还有很多不足, 例如未支持32位Linux程序, 不支持加载其他Linux动态链接库(so), 不支持命令行参数等等.
而且这份示例程序和Bash On Windows的原理有所出入, 因为在用户层是无法模拟syscall.
我希望它可以让你对如何运行其他系统的可执行文件有一个初步的了解, 如果你希望更深入的了解如何模拟syscall, 可以查找rdmsr和wrmsr指令相关的资料.

最后附上我在编写这份示例程序中查阅的链接:

 

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

相关文章
  • 通用网页调用本地应用程序方案(windows平台) - 小龙女先生

    通用网页调用本地应用程序方案(windows平台) - 小龙女先生

    2017-05-16 13:00

  • H5到底如何做视频直播 - 郭东生blog

    H5到底如何做视频直播 - 郭东生blog

    2017-05-13 11:01

  • cordova 基本命令 以及如何添加,删除插件 - huangenai

    cordova 基本命令 以及如何添加,删除插件 - huangenai

    2017-05-13 09:00

  • 如何快速处理线上故障 - 倒骑的驴

    如何快速处理线上故障 - 倒骑的驴

    2017-05-02 12:01

网友点评
=