assembly 编译器是否可以在没有系统调用或库调用的情况下生成独立于平台的二进制文件?

voj3qocg  于 2023-04-30  发布在  其他
关注(0)|答案(1)|浏览(68)

这个问题是来自超级用户的migrated,因为它可以在Stack Overflow上回答。19小时前
我不太懂低级的东西。但是,据我所知,编译器生成的二进制文件中包含系统和库调用。
如果你不做任何系统调用,也不调用任何库,那么二进制文件是否只是原始的汇编,如果你在同一台机器上,但在另一个操作系统上,可以不做任何更改地执行?还有什么能把二进制文件和它们的操作系统联系起来?有没有可能在没有任何系统调用的情况下编写跨平台的Hello world asm程序?它是否需要访问内核空间,因此它是不可能的?

kyxcudwk

kyxcudwk1#

不知道
可执行文件有元数据,而不仅仅是原始机器码,不同的操作系统使用不同的格式。(除非你有DOS .com可执行文件;该格式没有元数据,并且只是以相对于OS选择的任何段的固定偏移量加载到存储器中。)这让您在x86-64 OpenBSD或Linux上运行x86 -64 FreeBSD可执行文件时,即使它们都使用相同的格式(ELF),也可以获得有用的错误消息(而不是运行它并获得segfault)。
或者让操作系统透明地在其上调用模拟器,例如AArch 64硬件上的macOS如何通过Rosetta运行x86-64二进制文件,或者Linux如何通过binfmt-misc调用QEMU,而不是为错误的架构加载机器代码,并使CPU错误与非法指令或页面错误或其他东西很快。
Hello World需要进行write系统调用或MessageBoxA等效的WinAPI调用或类似的操作。系统调用ABI是特定于操作系统的。
例如,在x86-64 Linux上,mov eax, 1/syscallwrite系统调用。在x86-64 MacOS上,mov eax, 0x2000004/syscall。这两个都是类Unix操作系统;其他像Windows甚至没有一个稳定的系统-调用ABI;要在自己的进程之外执行任何操作,唯一可移植(跨Windows版本)的方法是调用DLL函数,这取决于可执行文件中特定于Windows的元数据。
假设您有一种可移植的方法来获得运行正确伊萨的机器代码块,您可以在无限循环中进行一些数字运算或其他操作,但在进程外部传达结果需要系统调用。(假设一个现代主流操作系统名副其实,i。也就是说,它做内存保护和多任务处理,所以不像MS-DOS,它不允许用户空间进程直接访问任何硬件。)
即使是可移植地退出也是一个问题;通常这是通过退出系统调用完成的,因此是特定于操作系统的。但是如果你的程序出错了(e。例如,非法指令,访问错误地址,或试图运行特权指令),操作系统将杀死您的进程。因为您之前没有进行系统调用来设置处理程序之类的东西。
不,不是Hello World。没有系统调用你所能做的就是修改你自己的内存;主流的操作系统不会用任何特殊的内存区域来启动进程,这些内存区域Map到从它们外部可见的任何东西。
你可以通过一个侧通道(side-channel)进行通信(泄露数据),比如CPU温度,或者性能计数器,或者对其他进程的性能影响(例如:例如,内存带宽或从共享L3缓存中驱逐数据的速度,无论是否在大量堆栈空间上循环)。不同的指令混合会使CPU发热,而less;您不能选择让进程休眠(这需要系统调用),但运行x86 pause指令的循环将比vmulpd ymm0, ymm1, ymm2指令块使用更少的功率。(256位浮点乘法,或FMA可能更耗电。)
这当然不能使“Hello World”出现在控制台中,除非您正在运行另一个进程,该进程经常检查CPU温度并一次收集几位输出。这个程序当然必须进行系统调用。
但是如果你不关心“Hello World”在控制台中结束,而只是想将数据传递给其他一些也不进行任何系统调用的进程,它可能会运行定时测试,使用x86 rdtsc或其他东西进行定时,也许是依赖于L3缓存命中的微基准测试,数据生产者可以运行一个循环,写入一大块堆栈空间,或者不触及内存。也许每个输出位花费10亿个TSC tick,以便给予读者有时间看到它发送的内容。(您可以为您实际想要发送的任何数据制定协议。这个想法将适用于任何共享L3缓存的CPU核心对,因此大多数台式机/笔记本电脑CPU,除了一些具有多个“核心集群”(CCX)的Ryzens)

相关问题