编辑: liubingb | 2018-10-23 |
而这一切 源于操作系统的开放性和硬件平台的不断发展, 尤其是存储器的发展, 使得我们在编写程序的时 候不必在意需要多大的存储空间了. 然而,嵌入式系统可就没那么幸运了.至今为止,在嵌入式系统里仍然没有一个能够像 Windows 这样应用如此广泛的操作系统,也没有可以不考虑存储空间的硬件平台.在数以亿计 的嵌入式设备使用者中,都还在用着一成不变的应用程序,单调同时也令人乏味.我们能不能也 像在 Windows 下面一样, 在嵌入式系统中可以安装应用程序呢?应该怎样克服嵌入式系统的限 制而实现这个功能呢? 有梦想才会不断的追求!我们知道,在Windows 中程序都是以文件的形式存储在文件系 统中的,然后通过操作系统控制这些程序的运行,我们可以说它的程序是 分散式 的.而在嵌入 式系统中通常是将程序烧录在一个 Flash 芯片中,文件系统在另一个 Flash 芯片中(也可以二 者在同一个芯片中),CPU 是直接从程序 Flash 芯片中读取指令执行的,没有经过文件系统, 我们可以叫这种程序是 一体式 的.Windows 的 分散式 程序体通过文件的形式存在,可以把 程序的不同部分分割成不同的文件, 当我们只需要更新一个模块内容的时候, 只更新这个文件就 可以了.熟悉它的朋友们可能已经知道了,这个文件就是在 Windows 操作系统中的 DLL 文件. 这样的方式可以很容易的实现程序分发, 这给了我们一个很好的启示: 嵌入式系统中也有文件系 统,把程序放在文件系统里不就可以了吗?真是个好主意! 在我们庆幸找到了好方法的时候,问题不偏不倚地出现了:系统如何运行文件系统中的程 序,文件中的程序又如何调用平台中的函数?要实现 分散式 的程序运行,这两个问题是必须要 解决的,而其中第二个问题就更为重要了.或许您现在还不是十分的明白这些问题的意义,不要 着急,这一章里我会逐一的向您讲解如何理解并解决这两个问题.当然,现在我们知道 BREW 已经在嵌入式系统中解决了这两个问题,从现在开始就让我们沿着开发者的足迹去追寻 BREW 的本质吧. 1.平台的作用 平台的作用 平台的作用 平台的作用 如果想要清楚的了解我们在嵌入式系统中所面临的问题,那么我们就首先需要了解 分散 式 系统的结构.一个 分散式 系统需要有三个部分组成:平台、软件开发工具包(SDK: Software Development Kit)和应用程序. 分散式 应用程序的运行需要平台的支持,就像 是DLL 文件只有在 Windows 操作系统平台下才有作用,而到了 Linux 平台则不起任何作用一 样;
应用程序则通过 SDK 进行开发,开发出的源程序经过编译之后可以运行在运行平台之上. 平台又分为开发平台和运行平台,开发平台是 SDK 运行的平台,用来开发可以在运行平台上运 行的应用程序, 对于一些系统还会提供模拟运行平台的模拟器, 以便于在没有显而易见的运行设 备的时候也可以看到开发的效果;
运行平台是应用程序运行的平台, 它提供应用程序运行的环境, 同时肩负着控制应用程序的作用. 开发平台和运行平台可以是同一个平台, 也可以两个不同的平 台,比如现在的 Winows 平台的应用就可以使用 VC 等工具开发基于 Windows 的应用程序, 而BREW SDK 则是运行在 Windows 环境下,但应用程序却在嵌入式系统中运行.它们之间的 关系如下图: 图1分散式系统结构图 从这个图中我们可以看出, SDK 需要使用运行平台的接口声明来开发应用程序, 运行平台 负责根据用户的输入启动应用程序, 而应用程序则通过运行平台的接口调用运行平台的函数库来 实现功能,我们的问题主要集中在应用程序和运行平台的互动关系上. 从前面的编译器基础一章中我们可以知道,在固定链接的模式下,各个函数的地址是固定 的,我们可以在同一个映像文件中调用任何函数.而存储在文件系统中的程序就不一样了,文件 系统中的程序没有固定的位置并且地址也不连续, 我们该怎样实现应用程序的启动呢?可选的方 案就是将应用程序复制到一个连续的内存块中去, 然后在内存中执行程序. 在这里需要特别的说 明一下,在PC 的Windows 操作系统中,Windows 将全部的程序载入内存中运行,并且其中 包含了复杂的内存管理功能,但是在嵌入式系统中通常程序是在 Flash 芯片中运行的,只有可 读写的数据是放在 RAM 中的, 具体的细节可以参考编译器基础一章. BREW 主要是应用程序在 嵌入式系统中的, 因此将程序复制到内存中执行是需要特殊处理的. 这个特殊的处理就是我们所 面临的第一个问题了――系统如何运行文件系统中的程序. 在我一开始理解 BREW 的时候,我曾经认为系统如何运行存在于文件系统中的程序是我 们所面临的主要问题,但当深入 BREW 内部的时候发现根本不是这么回事.现在我们可以假设 运行平台分配了一个足够大的内存, 这块内存地址是已知的, 可以想象的到我们可以从这个地址 开始执行程序.现在我们暂时忽略那些特殊的处理,文件系统中的这个程序现在正在运行,就像 在Flash 中的程序一样的在运行.从理论上来讲这个是行得通的,因此系统如何运行文件系统 中的程序的问题并不是我们所面临的难题.实际上 BREW 也是按照这个思路做的,只是实现时 还有细节的东西在,关于这些细节我们将在 Shell 内幕一章进行详细的介绍. 进一步的,假设现在程序运行到了需要调用平台函数的时候了,问题就来了,由于当前的 应用程序是开发者使用 SDK 开发的,就像平台不知道应用程序的地址一样,应用程序也不知道 平台的函数地址, 因此, 我们现在面临的问题是怎么能够知道应用程序中所调用的平台函数的地 址.SDK 可以提供运行平台中的每个函数的地址吗?可以提供,但是行不通.因为平台是会经 常升级的,导致每个函数的链接地址不固定,如果由 SDK 提供所有函数的地址带来的问题是, 只要运行平台一升级,那么 SDK 和应用程序都需要同时升级.如果这样的话我们的分散式程序 就不能实现 分散式 的升级了,这种程序的运行方式也就没有任何意义了.看来我们还要寻找更 为高级的方法, 这种方法要能够提供一种应用程序与运行平台之间无关的机制. 我们现在所需要 的这个 机制 就是第二个问题了――文件系统中的程序如何调用平台的函数. 从分散式系统结构图中我们可以看到, SDK 使用的是运行平台的接口声明, 应用程序调用 真正的运行平台接口. 或者换句话说开发过程中使用运行平台的接口声明, 而在运行时应用程序 使用真正的二进制接口,并且在二进制层面调用接口函数.那么,现在无论是 SDK 还是应用程 序都与接口相关, 那么, 可以想象的到的解决第二个问题的方式就是让接口和接口实现之间分离. 接口与实现间分离的方法就是 BREW 的核心,也是接下来我们主要阐述的议题. 2.软件分发和 软件分发和 软件分发和 软件分发和 C ........