【问题标题】:Basic question regarding ROM based executable关于基于 ROM 的可执行文件的基本问题
【发布时间】:2011-03-11 23:19:25
【问题描述】:

我对存储在 ROM 中的可执行文件有基本的疑问。

据我所知,带有文本和 RO 属性的可执行文件存储在 ROM 中。问题是ROM是只读存储器,如果出现代码需要写入内存的情况怎么办?

我无法在这里举出任何例子来引用(可能我对这种情况一无所知,或者我错过了基本的东西;)但是关于这个主题的任何启示都可以极大地帮助我理解! :)

最后一次 - 1、有没有这样的情况? 2. 在这种情况下,将代码从 ROM 复制到 RAM 是答案吗?

用一些例子回答会有很大帮助..

非常感谢!

/MS

【问题讨论】:

  • 你说的是自修改代码?
  • 其实我的问题好像是这样!但我真正的疑问是ROM中的内容是什么?当我们刷新二进制文件时,只有 .text 区域(代码)而不是数据(RW)?在那种情况下,我们将什么闪存到 ROM 中?加载程序是否负责将 .text/code 映射到 ROM 并将任何 RW 数据映射到 RAM?最好的问候..

标签: operating-system cpu computer-architecture embedded


【解决方案1】:

通常只有程序代码、常量和初始化数据存储在 ROM 中。 RAM 中的一个单独的内存区域用于堆栈、堆等。

【讨论】:

  • 嗨 Paul,我知道我们将堆栈、堆、数据、RW 部分配置到合适的 RAM 位置,但我怀疑如果代码部分(即在 ROM 中)需要写入内存怎么办? (它恰好在 ROM 本身中!)链接器是否生成具有读/写属性的代码段,最后它驻留在 RAM 中?但是我们所做的只是将可执行文件闪存到 ROM 中,那么这种到 RAM 的传输是如何发生的呢?那么为什么我们需要RAM,“代码从ROM复制到RAM然后执行”? (它可以直接从 ROM 对吗?感谢您的回答.. :) 最好的问候..
  • 在大多数操作系统中,代码段都是只读的,即使它们驻留在 RAM 中。这使得程序更健壮,安全问题更少。因此,您的代码在 ROM 中这一事实确实没有什么区别——您通常不需要写入该段。如果您需要使用自修改代码或其他类似的黑客,那么您必须在 RAM 中执行此操作,然后可能将页面标记为可执行(取决于操作系统)。
【解决方案2】:

由于硬件限制,只读内存是只读的。该程序可能位于EEPROM、防止写入的闪存、CD-ROM 或任何硬件物理上不允许写入的地方。如果软件写入 ROM,硬件无法更改存储的数据,所以什么也不会发生。

所以如果ROM 中的软件程序想要写入内存,它会写入RAM。这是唯一的选择。如果一个程序从 ROM 运行并想要change itself,它不能,因为它不能写入 ROM。但是是的,程序可以从 RAM 中运行。

事实上,除了最小的嵌入式系统之外,从 ROM 运行是很少见的。操作系统在运行之前将可执行代码从 ROM 复制到 RAM。有时code is compressed在ROM中,运行前必须解压到RAM中。如果 RAM 已满,操作系统将使用paging 对其进行管理。从 ROM 运行如此罕见的原因是因为 ROM 比 RAM 慢,而且有时代码需要在运行前由 loader 更改。

请注意,如果您的代码会自行修改,那么您确实必须了解您的系统。许多系统使用data-execution prevention (DEP)。可执行代码进入 RAM 的读取+执行区域。数据进入读+写区域。所以在这些系统上,代码永远不会在 RAM 中改变自己。

【讨论】:

  • 嗯.. 所以使用 ROM 只是因为它可以在电源开/关之间保存代码。除此之外,我们花了两次(一次用于 ROM 和一次用于 RAM)。我想知道是否只有RAM可以在两次启动之间保持不变,那么我们可以完全消除ROM吗? NOR flash & XIP (eXecute In Place) 可能就是它。我将查看 wiki 了解更多信息。谢谢详细解答! :)
  • @MS:当前系统运行良好的原因是可执行代码与数据相比非常小。您确实花费了两次,但可以通过库共享代码。即使是复杂的程序也往往比高分辨率 jpeg 图像小。但可以肯定的是,快速、廉价的持久 RAM 将是一项不错的技术。速度在通用 PC 中很重要,这就是为什么经常有多层缓存方案的原因:硬盘缓存到闪存缓存到 RAM 缓存到处理器 L1 和 L2。在为特定用途量身定制的系统中,从闪存执行可能已经足够快了。
  • 感谢个人!我现在想知道当我们刷新可执行文件时会进入 ROM 的内容是什么?当读/写发生时,它需要的数据会发生什么?如果只有我们正在闪存到 ROM 中的可执行文件(代码),那么在执行期间如何为 ROM 中的代码和 RAM 中的数据设置内存映射?
【解决方案3】:

您想要在运行时修改代码部分的正当理由很少。编译器本身不会生成需要它的代码。

您的链接器可以选择生成 MAP 文件。这将告诉您 所有 内存对象的位置。

链接器根据链接器脚本选择定位位置(您可以根据需要对其进行自定义以组织内存)。通常在基于 FLASH 的微控制器上,代码和常量数据将被放置在 ROM 中。非零初始化静态数据的初始化数据也放置在 ROM 中,在调用 main() 之前将其复制到 RAM。零初始化静态数据在 main() 之前简单地清零。

可以安排链接器定位 ROM 中的部分或全部代码,并让运行时启动代码以与非零静态数据相同的方式将其复制到 RAM,但代码必须要么是可重定位的,要么首先位于 RAM 中,你通常不能仅仅将打算从 ROM 运行的代码复制到 RAM 并期望它运行,因为它可能有绝对地址引用(除非你的目标有一个 MMU 和可以重新映射地址空间)。在微控制器上的 RAM 中定位通常是为了提高执行速度,因为当使用高时钟速度时,RAM 通常比 FLASH 快,产生更少或零等待状态。当代码在运行时从文件系统加载而不是存储在 ROM 中时,也可以使用它。即使加载到 RAM 中,如果处理器有 MMU,RAM 部分中的代码部分也可能会被标记为只读。

【讨论】:

  • 谢谢!我现在能够把它们放在一起。 :)
【解决方案4】:

哈佛架构微控制器

许多小型微控制器(Microchip PIC、Atmel AVR、Intel 8051、Cypress PSoC 等)都具有哈佛架构。 它们只能执行程序存储器(闪存或 ROM)中的代码。 可以将任何字节从程序存储器复制到 RAM。 然而,(2) 将可执行指令从 ROM 复制到 RAM 并不是解决办法——对于这些小型微控制器,程序计数器总是指向程序存储器中的某个地址。无法在 RAM 中执行代码。

数据从 ROM 复制到 RAM 是很常见的。 首次上电时,典型的固件应用程序会将所有 RAM 清零,然后在 main() 启动之前将非常量全局变量和静态变量的初始值从 ROM 复制到 RAM 中。 每当应用程序需要将一个固定字符串从串行端口推出时,它就会从 ROM 中读取该字符串。

对于这些微控制器的早期版本,连接到微控制器的外部“设备编程器”是更改程序的唯一方法。 在正常操作中,该设备远不及“设备编程器”。 如果微控制器上运行的软件需要写入程序存储器 ROM——对不起,太糟糕了—— 这是不可能的。 许多嵌入式系统都有代码可以写入的非易失性 EEPROM——但这仅用于存储数据值。微控制器只能执行程序 ROM 中的代码,不能执行 EEPROM 或 RAM。 人们用这些微控制器做了很多好事,包括 BASIC 解释器和字节码 Forth 解释器。 所以显然 (1) 代码永远不需要写入程序内存。

使用最近的一些“自编程”微控制器(来自 Atmel、Microchip、Cypress 等), 芯片上有特殊的硬件,允许在微控制器上运行的软件擦除和重新编程其自己的程序存储器闪存的块。 一些应用程序使用这种“自编程”功能来读取和写入数据到“额外”闪存块 - 从未执行过的数据,因此它不算作自修改代码 - 但这并没有做任何事情您无法使用更大的 EEPROM。 到目前为止,我只见过两种运行在哈佛架构微控制器上的软件,它们将新的可执行软件写入自己的程序 Flash:引导加载程序和 Forth 编译器。

当 Arduino 引导加载程序(引导加载程序)运行并检测到新的应用程序固件映像可用时,它会下载新的应用程序固件(到 RAM),并将其写入闪存。 下次打开系统时,它现在正在运行闪亮的新版本 16.98 应用程序固件,而不是笨重的旧版本 16.97 应用程序固件。 (当然,包含引导加载程序本身的闪存块保持不变)。 如果没有写入程序内存的“自编程”功能,这将是不可能的。

一些 Forth 实现在小型微控制器上运行,编译新的可执行代码并使用“自编程”功能将其存储在程序 Flash 中——这个过程有点类似于 JVM 的“即时”编译。 (所有其他语言似乎都需要一个太大而复杂的编译器,无法在小型微控制器上运行,因此编辑-编译-下载-运行周期需要更多的挂钟时间)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-10-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多