关于链接/加载和模拟器的问题

时间:2010-07-12 19:44:03

标签: c++ assembly linker loader

我使用Verilator设计了一个MIPS I模拟器,它允许我将verilog代码包装到c ++中。我试图在我的处理器上运行一个c ++程序,但我遇到了一些问题。我的目标是:

  1. 用c ++编写测试程序
  2. 使用交叉编译器g ++(mips-linux)
  3. 编译该程序
  4. 使用生成的ELF文件并使用objdump
  5. 对其进行反汇编
  6. 将整个二进制对象转储存储在文本文件中
  7. 在我的模拟器中打开文本文件
  8. 运行一些文本操作函数来隔离objdump的HEX转储部分
  9. 将整个elf十六进制转储加载到我的处理器内存中(一个c ++内存映射,其中包含由ELF文件定义的内存中的地址键入的元素。)
  10. 通过设置程序计数器运行程序,直到退出程序的系统调用。
  11. 问题是第7步和第8步。我对ELF文件格式有一个非常基本的了解。据我所知(readelf可用于输出程序起始点)程序ounter应该最初设置在.text部分开头的地址。不幸的是,这样做不会导致在我的处理器上运行正确的程序。

    我已经通过编写汇编程序,将它们加载到MIPS汇编模拟器中,并通过指令验证寄存器文件和生成的寻址匹配来验证我的处理器的正确程序执行。我不明白为什么我不能通过用c ++编写,编译和加载到我的“内存”来运行“helloworld”程序?我在这个领域并不是特别懂。我真的可以用一些帮助搞清楚这一点。

    我的理解是.text和.data包含我的程序运行所需的一切。显然不是这种情况,因为当我遍历.text部分时,我的程序无法正确执行。在将ELF文件加载到内存之前,我还需要对ELF文件做些什么吗?

3 个答案:

答案 0 :(得分:1)

我已经编写了一个完整的MIPS I模拟器,可以加载ELF二进制文件。您可以获取源代码here,也许您会得到问题的答案。还包括一些演示程序。关键是让编译器生成一个不使用任何运行时库的独立可执行文件,甚至不是gcc的支持库。

答案 1 :(得分:0)

Here是我喜欢的精灵的解释,虽然你似乎了解精灵问题。他们还解释了g +​​+如何输出elf文件,因此它可以帮助你解析输出文件(part 1中的更多信息)。

希望其中一些信息有所帮助。

答案 2 :(得分:0)

zvrba可能已经击中头部,你不能/不应该在你的程序中调用像printf这样的C库函数。

编写一个简单的C程序,可以从:

开始
const unsigned char hello[]="helloworld";

void notmain ( void )
{
   unsigned int ra;

   for(ra=0;hello[ra];ra++)
   {
       PUT32(0x1234,hello[ra]);
   }
}

并且从您编写的汇编程序中调用notmain,并且它们一起工作并链接在一起。

PUT32只是将一些数据写入某个地址,我通常在汇编程序ymmv中实现它们。

选择除0x1234以外的其他地址,我的假设是在您的SIM环境中,您可以观看对地址位置的访问并观看字符。当您可以观察总线上的字节时,无需与uart交谈并且必须在模拟中解码串行。

Elf文件真的很容易解析,如果你已经编写了一个模拟器,那么读取一个elf文件并不是什么大问题。我不打扰图书馆他们只是让它变得更难。如果您选择使用结构,这是一些结构。如果您愿意,我可以为您提供可以帮助您入门的代码。另一种方法是使用gnu工具将elf转换为二进制文件(mips-whatever-objcopy file.elf -O binary file.bin)。如果您的.text和.data彼此不相近,则objcopy程序将生成一个带有零的大文件,以便在两个地址空间之间填充。对于嵌入式,你想要避免在你的.data部分中有任何东西,总是不提前初始化程序中的变量而只读表make const所以它们在.text而不是.data

这是一个有趣或工作或一般公众消费的项目吗?我可能有兴趣使用它有一天我喜欢verilator的概念,但它对于verilog标准来说有限或太严格,而且那里的verilog不会在没有工作的情况下运行,所以我没有真正玩它。 / p> 祝你好运。