这个问题是来自超级用户的migrated,因为它可以在Stack Overflow上回答。19小时前我不太懂低级的东西。但是,据我所知,编译器生成的二进制文件中包含系统和库调用。如果你不做任何系统调用,也不调用任何库,那么二进制文件是否只是原始的汇编,如果你在同一台机器上,但在另一个操作系统上,可以不做任何更改地执行?还有什么能把二进制文件和它们的操作系统联系起来?有没有可能在没有任何系统调用的情况下编写跨平台的Hello world asm程序?它是否需要访问内核空间,因此它是不可能的?
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/syscall是write系统调用。在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)
.com
binfmt-misc
write
mov eax, 1
syscall
mov eax, 0x2000004
pause
vmulpd ymm0, ymm1, ymm2
rdtsc
1条答案
按热度按时间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
/syscall
是write
系统调用。在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)