简短回答
阅读更长的回答。
简短回答
如果你打算提供一个自定义的 libc,使用你的仿真器的某些特性来让主机操作系统执行你的系统调用,那么你必须实现所有这些系统调用。
更长回答
先停一下,看看在一个真实(非模拟)系统中通常是如何分层的:
你试图实现的工作发生在第 3 层和第 2 层之间,即 libc 或用户代码中的函数执行任何 OS 定义为触发系统调用的操作。这会引起许多问题:
操作系统定义触发系统调用的方式因操作系统而异,甚至同一操作系统的不同版本也有所不同(但很少)。在“真实”的系统上,提供一个动态链接的libc可以处理这些细节。除此之外,如果您想要运行一个MIPS32二进制文件,它是否使用了您的模拟器支持的系统调用约定?
您需要提供一个自定义的libc,使其执行特定的系统调用并让您的模拟器识别。您希望运行的任何程序都必须交叉编译为MIPS32,并与之静态链接,就像程序需要的任何其他库一样(例如libm)。或者,您的模拟器软件包将需要提供模拟动态链接器以及所有所需库的动态链接副本,因为在主机上打开这些库是行不通的。如果您有足够的源代码来从头重新编译该程序,则移植可能比模拟更好。
任何假设路径到特定系统上的文件或其他假设关于它们在某些设备(它们本身就是文件)中找到什么的代码都无法正确运行。
如果您提供第二层,那么您就要签署提供整个操作系统某个特定版本行为的完整、正确模拟。一些调用,如read()
和write()
,很容易处理;而其他调用,如fork()
、uselib()
和ioctl()
则要困难得多。此外,您的程序使用的调用和行为与主机操作系统提供的调用之间并不一定有一对一的映射关系。所有这些都假设目标程序是Unix,并且主机也是Unix。如果目标编译为其他环境,则情况就未知了。
大多数ISO标准C库都可以用纯C编写。只有少部分需要访问较低级别的操作系统功能。
至少,您需要在块或字符级别模拟基本的I/O,以便使用fopen
、fread
和fwrite
。您可以采用Unix方法,在较低级别的open
、read
和write
调用之上实现这些函数。
您还需要管理malloc
和free
的动态内存分配。
以及需要访问执行堆栈的setjmp
和longjmp
。
还有time
和signal.h
函数。
我不确定MIPS是如何工作的,但在Win32上,操作系统调用必须通过DLL/EXE导入表明确地导入到进程中。MIPS系统使用的可执行文件格式可能存在类似的情况。
大多数调用无法使用通用存根/代理工作,而需要特定的解决方案。
祝你好运!