编译器能否在没有系统调用或库调用的情况下生成平台无关的二进制文件?

问题描述 投票:0回答:1

我对底层的东西了解不多。但是,据我所知,编译器生成的二进制文件中包含系统和库调用。

如果您既不进行任何系统调用也不调用任何库,那么二进制文件是否只是原始程序集,如果您在同一台机器上但在另一个操作系统上,则无需任何更改即可执行?还有什么可以将二进制文件链接到他们的操作系统?是否可以在没有任何系统调用的情况下编写跨平台的 Hello world asm 程序?是否需要访问内核空间因此不可能?

compilation cross-platform assembly
1个回答
0
投票

可执行文件有元数据,而不仅仅是原始机器代码,不同的操作系统使用不同的格式。 (除非您有 DOS .com

 可执行文件;该格式没有元数据,只是以相对于操作系统选择的任何段的固定偏移量加载到内存中。)这使您可以获得有用的错误消息(而不是运行它并获得段错误)尝试在 x86-64 OpenBSD 或 Linux 上运行 x86-64 FreeBSD 可执行文件时,即使它们都使用相同的格式(ELF)。

或者让操作系统透明地调用模拟器,例如 AArch64 硬件上的 macOS 如何通过 Rosetta 运行 x86-64 二进制文件,或者 Linux 通过

binfmt-misc

 调用 QEMU,而不是为错误的架构加载机器代码并拥有 CPU很快就会出现非法指令或页面错误或其他问题的故障。


Hello World 需要进行

write

 系统调用或 MessageBoxA 等效的 WinAPI 调用,或类似的东西。系统调用 ABI 是特定于操作系统的。

例如在 x86-64 Linux 上,

mov eax, 1

 / 
syscall
 是一个 
write
 系统调用。在 x86-64 MacOS 上,
mov eax, 0x2000004
 / 
syscall
。这些都是类 Unix 操作系统; Windows 等其他系统甚至没有稳定的系统调用 ABI;在您自己的进程之外执行任何操作的唯一可移植(跨 Windows 版本)方法是调用 DLL 函数,这取决于可执行文件中特定于 Windows 的元数据。


假设您有一种可移植的方法来为正确的 ISA 运行获取机器代码块,您可以在无限循环或其他内容中可移植地进行一些数字运算,但是在您的进程之外传递结果需要系统调用。 (假设现代主流操作系统名副其实,即进行内存保护和多任务处理,因此与 MS-DOS 不同,不允许用户空间进程直接访问任何硬件。)

连便携退出都是问题;通常这是通过退出系统调用完成的,因此是特定于操作系统的。但是,如果您的进程出现故障(例如,非法指令、访问错误地址或尝试运行特权指令),操作系统将终止您的进程。因为您不会进行较早的系统调用来设置处理程序或其他东西。

所以不,不是 Hello World;没有系统调用,你所能做的就是修改你自己的记忆;主流操作系统不会启动具有任何特殊内存区域的进程,内存映射到从外部可见的任何内容。

您可以通过诸如 CPU 温度、性能计数器或对其他进程的性能影响(例如内存带宽或您从共享 L3 缓存中驱逐数据的速度,或者在大量堆栈上循环)等边通道进行通信(泄露数据)空间与否)。不同的指令组合会使 CPU 升温更多或更少;您没有让进程休眠的选项(这需要系统调用),但是运行 x86

pause

 指令的循环将使用比 
vmulpd ymm0, ymm1, ymm2
 指令块少得多的功率。 (256 位浮点乘法,或 FMA 可能更耗电。)

这当然不能使“Hello World”出现在控制台中,除非您正在运行另一个经常检查 CPU 温度并一次收集几位输出的进程。该程序当然必须进行系统调用。

但是,如果您不关心最终出现在控制台中的“Hello World”,并且只想将数据传递给其他一些也不进行任何系统调用的进程,它也许可以运行定时测试,使用 x86 定时

rdtsc

 之类的,也许是一个依赖于 L3 缓存命中的微基准测试,数据生产者可以运行一个循环来写入大量堆栈空间或者不接触内存。可能每比特输出花费 10 亿个 TSC 滴答,让读者有时间看看它发送了什么。 (你可以为你实际想要发送的任何数据想出协议。这个想法适用于共享 L3 缓存的任何一对 CPU 内核,因此大多数台式机/笔记本电脑 CPU 除了一些具有多个“核心集群”的 Ryzens (CCX))

© www.soinside.com 2019 - 2024. All rights reserved.