【问题标题】:How are addresses resolved by a compiler in a medium memory model?编译器如何在中等内存模型中解析地址?
【发布时间】:2014-09-04 21:49:18
【问题描述】:

我是中小型内存型号 CPU 编程的新手。我正在使用一个嵌入式处理器,它在地址 0x00000 到 0x3FFFF 中包含 256KB 的闪存代码空间,在地址 0xF0000 到 0xFFFFF 中包含 20KB 的 RAM。有编译器选项可以在小型、中型或大型内存模型之间进行选择。我选择了中等。我的问题是,编译器如何区分代码/闪存地址和 RAM 地址?

例如,我在 RAM 地址 10 有一个 1 字节变量,我在实际地址 10 有一个 const 变量。我做了类似的事情:

value = *((unsigned char *)10);

编译器将如何在实际地址 10 或(虚拟?)地址 10 之间进行选择。我想如果我想在实际地址 10 处指定值,我会使用:

value = *((const unsigned char *)10);

?

另外,您能否解释一下我认为与答案相关的以下代码:

uint32_t var32;     // 32 bit unsigned integer.
unsigned char *ptr; // 2 byte pointer.

ptr = (unsigned char *)5;
var32 = (uint32_t)ptr;
printf("%lu", var32)

代码打印 983045(0xf0005 十六进制)。看起来不太现实,一个16位的变量怎么能返回一个大于16位可以存储的值呢?

【问题讨论】:

  • 首先,细节可能是特定于平台的(我不知道“中等内存模型”可能是什么)。但听起来闪存和 RAM 都映射到同一个地址空间; 10 属于您所说的闪存映射到的范围,因此它从闪存读取。
  • 次要:应使用printf("%" PRIu32, var32)printf("%lu", (unsigned long) var32)
  • 我的编译器不支持 PRIu32。事实上,它甚至不包括 uint32_t 的 ,我只是为了清楚起见而举了一个例子。实际类型是无符号长整数,在我的编译器上是一个 32 位变量。
  • 中内存模型意味着 2 字节指针用于 RAM/变量和 4 字节指针用于代码。
  • 你能澄清一下你的意思是x86 medium memory model还是别的什么?

标签: c compiler-construction embedded memory-address memory-model


【解决方案1】:

阅读编译器的文档以了解每种内存模型的详细信息。

它可能有各种类型的指针,例如char near * 为 2 字节,char far * 为 4 字节。或者(或同样),它可能包含更改您必须手动调用的代码页的说明。

16 位变量如何返回大于 16 位可以存储的值?

不能。您的代码将指针转换为 32 位 int。 , 和 0xF0005 可以适应 32 位 int。根据您的描述,我猜char * 仅指向数据区域,您将使用不同类型的指针指向代码区域。

【讨论】:

    【解决方案2】:

    我试图评论马特的回答,但我的评论太长了,我认为这可能是一个答案,所以这是我的评论:

    我认为这是一个答案,不过我真的在寻找更多细节。我已经阅读了手册,但没有太多关于该主题的信息。没错,编译器具有可用于手动指定地址(类型?)的近/远关键字。我猜 C 编译器知道变量是近指针还是远指针,如果它是近指针,它会生成将 2 字节近指针映射到实际地址的指令;这些生成的映射指令对 C 程序员来说是不透明的。那将是我唯一的猜测。这就是为什么指针返回的值大于其 16 位值的原因;编译器在将值存储到 var32 之前将地址映射到绝对地址。这是可能的,因为 1) RAM 地址从 0xF0000 开始并以 0xFFFFF 结束,因此您始终可以通过将地址与 0xF0000 或地址来将近地址映射到其绝对地址,并且 2) 代码之间没有重叠(远) 指针和近指针或与 0xF0000 相匹配。谁能确认一下?

    【讨论】:

      【解决方案3】:

      我的第一件事是阅读文档,但正如我所见,它已经完成了。

      所以我的假设是,您必须以某种方式在一个大型现有代码库上工作,该代码库是在不太知名的架构上使用不太广泛支持的编译器开发的。

      在这种情况下(在我尝试获取正确文档的所有尝试都失败之后),我会为测试程序生成汇编程序输出,并对其进行分析。我前一阵子这样做了,所以它不是凭空而来的(它是在 MDS-70 上运行的 8051 PL/M 编译器,它由 80 年代后期基于 DOS 的模拟器模拟,DOS 由 DOSBox 模拟- 是的,对于我们需要维护的庞大代码库,我们无法绕过这个混乱)。

      因此,请构建简单的程序,这些程序将使用一些指针执行某些操作,编译那些没有优化到程序集的程序(或请求程序集转储,无论编译器可以为您做什么),并理解输出。尝试涵盖您在编译器中知道的所有指针类型和内存模型。它将阐明正在发生的事情,希望现有的文档在您以这种方式了解它们的差距后也会有所帮助。最后,不要停留在对当前问题的理解上,尝试记录正确的差距,这样以后你就不需要重做实验来找出你曾经几乎完成的事情。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-08-29
        • 2014-05-24
        • 2018-04-01
        • 2012-08-06
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多