热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

轻松控制uClinux嵌入式开发过程一(图)

文章标题:轻松控制uClinux嵌入式开发过程一(图)。Linux是中国IT实验室的一个技术频道。包含桌面应用,Linux系统管理,内核研究,嵌入式系统和开源等一些基本分类

  uClinux是目前比较普及的嵌入式Linux版本之一,它的功能很多,并且随着低成本、可运行uClinux的32位CPU的激增,以及uClinux首次成为Linux 2.6内核的一部分,uClinux将更加流行(如图1)。下面讨论一下开发者使用uClinux时如何控制开发过程,以及将会遇到的与普通Linux的不同之处。
  

  
图1 uClinux运行在Palm上

  
  应用无内存管理
  
  uClinux与普通Linux系统的主要区别就是它没有内存管理。在普通Linux下,通过使用虚拟内存(VM)来实现内存管理。虚拟内存一般是通过内存管理单元(Memory Management Unit,简称MMU)来实现,而在uClinux的世界里,经常可以看到“NOMMU”这个词。
  
  在有虚拟内存的情况下,所有的进程都在相同的地址空间运行,由虚拟内存系统处理虚拟内存到物理内存的映射。因此,即使进程看到的虚拟内存是连续的,它所占的物理内存也可能是分散的,有的甚至被交换到了硬盘。因为物理内存能映射到进程地址空间的任何位置,所以这种环境下能够向正在运行的进程添加内存。
  
  在没有虚拟内存的情况下,每个进程必须被分配到固定的内存位置。由于一个进程的上、下(内存位置)都可能有别的进程在运行,所以它通常不能动态扩展内存。这就是说,在uClinux下运行的进程不能在运行过程中动态增加可用内存,这与传统Linux下的情况有所不同。
  
  对于uClinux开发者来说,分配内存是一个棘手的问题,并且由于没有任何形式的内存保护,任何应用程序或内核都可能破坏系统。更为糟糕的是,无意识的误操作不会引人注意,造成要跟踪随机的、进程间的破坏非常困难。但是这些缺陷对于uClinux来说几乎不算问题,这是因为使用uClinux的系统一般没有硬盘驱动器和足够的内存,完全没有必要做复杂的管理和交换。
  
  做足内存映射
  
  对于内核开发者,uClinux与普通Linux区别很小。惟一真正会遇到的问题是uClinux内核开发者不能利用MMU提供的分页支持,比如,依赖虚拟内存的tmpfs文件系统在uClinux下就不起作用。类似的,普通Linux下的标准可执行文件格式uClinux都不支持,因为它们都要利用虚拟内存的特性。uClinux需要一种新的格式——Flat,它是一种压缩的可执行文件格式,只保存可执行的代码和数据,以及将可执行程序装载到内存时所需要的重定位信息。
  
  理解uClinux内核中内存映射的实现方式也是很有必要的,因为有些方式在uClinux系统上行不通,理解内存映射的实现后可以避免使用这些方式。uClinux要求内存映射能够直接在文件系统中指到文件,从而保证它是顺序的和连续的,否则就必须事先为文件分配好内存,并把数据拷贝到分配给它的内存块上。
  
  因此,uClinux下有效内存映射的用法要素非常明确:首先,当前惟一能够保证文件连续存储的文件系统是ROM文件系统(Romfs),所以必须使用Romfs来避免传统内存分配;其次,只有只读的内存映射能够被共享,也就是说,为了避免传统内存分配,映射必须是只读的。由于这些原因,uClinux下的开发者不能利用“Copy-on-Write”特性。
  
  要将设备驱动程序移植到uClinux环境,需要做一些修改,这并不是因为内核上的区别,而是由于与硬件细节相关部分有所不同造成的。比如,普通Linux下,SMC网络驱动程序可以支持ISA SMC卡。该驱动程序是16位的,并且一般都分配到0x3ff以下的I/O地址空间。
  
  但是用来支持SMC卡的非ISA嵌入式版本,驱动程序要求运行在8位、16位或32位模式下都是可能的,并且在满32位的I/O地址中,中断号一般要高于ISA的最大值16。所以,与硬件细节相关的部分可能还是要做一些移植工作。
  
  恰当的内存分配
  
  uClinux除了提供跟普通Linux一样的内存分配器之外,还提供另一个可选的。普通Linux中缺省的内存分配器是使用“2的幂”的分配方法,这样可以快速找到符合要求的内存区域。不幸的是,在uClinux下这种方法可能会带来令人痛苦的结果。
  
  为了理解这一问题带来的结果,尤其是大的内存分配,我们举例说明。试想一个应用程序要求33KB的内存空间进行装载。如果使用“2的幂”的分配方法,就必须分配64KB(2的6次方)内存空间,多余的31KB内存空间不能被利用上。在uClinux中,这种浪费是不能接受的。为了解决这个问题,专门为uClinux内核设计了可选的内存分配器。不同的内核版本,这个可选的内存分配器不同,一般是page_alloc2和kmalloc2。
  
  page_alloc2能解决缺省的分配方法造成的浪费问题。虽然它也是使用“2的幂”的分配方法,但它是按页(每页4096字节,即4KB)分配的,分配的内存大小如果已经满足了要求,则只是将当前的一页分配出去,其它的就不再分配。在前面的例子中,如果使用这种方法,就只是分配36KB(≥33KB,且为整页)即可,这样就能节省28KB的空间。
  
  page_alloc2还采取了一些避免内存碎片的方法。它将所有的两页(8KB)或更少的内存需求从空闲内存开始部分向上分配,所有大的内存需求从剩余内存的末尾部分开始向下分配。这样防止了网络缓存等的临时分配,避免了内存碎片的出现。
  
  一旦开发者理解了内核内存分配的区别,应用程序中就会出现变化。
  
  1.没有动态栈的问题
  
  在使用虚拟内存的Linux上,当一个应用程序试图冲销栈顶单元时,会被标记异常,同时系统会映射新的内存到栈顶以便让栈增长。在uClinux下,由于必须在编译阶段给栈分配好内存,所以不会有这样的增长。当出现莫名其妙的崩溃或者新移植的应用程序出现怪异行为时,开发者首先应该考虑到的是给栈分配的内存大小问题。缺省情况下,uClinux为栈分配4KB的内存空间,开发者可以用下面提到的方法之一来增加栈的空间。
  
  ◆ 应用程序build之前
  
  应用程序build之前,可以在Makefile文件中增加以下两行代码:
  
  FLTFLAGS = -s
  export FLTFLAGS
  
  ◆ 应用程序build之后
  
  应用程序build之后,可以运行以下命令:
  
  flthdr -s executable
  
  其中,stacksize 就是为栈增加的内存空间。
  
  2.没有动态堆的问题
  
  堆是C语言中malloc及相关函数分配内存的区域。在有虚拟内存的Linux上,应用程序可能通过动态堆在运行过程中改变进程的大小。这个功能是通过在底层使用sbrk()和brk()系统调用来实现的。sbrk()是在进程的末尾增加内存空间,所以调用sbrk()能够使应用程序获得额外的内存。
  
  brk()可以把任意位置设置为进程空间的末尾,因此,可以通过调用brk()减少或增加内存空间的占用。由于uClinux不能实现brk()和sbrk(),它采用了一个全局的内存池,就是内核的空闲内存池。使用全局内存池的方法有一些优点。
推荐阅读
  • CMake跨平台开发实践
    本文介绍如何使用CMake支持不同平台的代码编译。通过一个简单的示例,我们将展示如何编写CMakeLists.txt以适应Linux和Windows平台,并实现跨平台的函数调用。 ... [详细]
  • 本文将深入探讨PHP编程语言的基本概念,并解释PHP概念股的含义。通过详细解析,帮助读者理解PHP在Web开发和股票市场中的重要性。 ... [详细]
  • PyCharm下载与安装指南
    本文详细介绍如何从官方渠道下载并安装PyCharm集成开发环境(IDE),涵盖Windows、macOS和Linux系统,同时提供详细的安装步骤及配置建议。 ... [详细]
  • 本文详细介绍了C语言中链表的两种动态创建方法——头插法和尾插法,包括具体的实现代码和运行示例。通过这些内容,读者可以更好地理解和掌握链表的基本操作。 ... [详细]
  • 本文深入探讨了 Python 中的循环结构(包括 for 循环和 while 循环)、函数定义与调用,以及面向对象编程的基础概念。通过详细解释和代码示例,帮助读者更好地理解和应用这些核心编程元素。 ... [详细]
  • 装饰器是一种用于在不修改原函数代码的情况下,动态地添加功能的工具。它允许你在函数执行前后插入额外的逻辑,从而增强或改变函数的行为。 ... [详细]
  • 本文详细探讨了C语言中指针的概念,特别是指针在变量和数组中的应用。通过实例讲解,帮助读者更好地掌握指针的使用方法。 ... [详细]
  • 本文介绍了几种不同的编程方法来计算从1到n的自然数之和,包括循环、递归、面向对象以及模板元编程等技术。每种方法都有其特点和适用场景。 ... [详细]
  • Python入门:第一天准备与安装
    本文详细介绍了Python编程语言的基础知识和安装步骤,帮助初学者快速上手。涵盖Python的特点、应用场景以及Windows环境下Python和PyCharm的安装方法。 ... [详细]
  • 本文探讨了高质量C/C++编程的最佳实践,并详细分析了常见的内存错误及其解决方案。通过深入理解内存管理和故障排除技巧,开发者可以编写更健壮的程序。 ... [详细]
  • 在Java中,this是一个引用当前对象的关键字。如何通过this获取并显示其所指向的对象的属性和方法?本文详细解释了this的用法及其背后的原理。 ... [详细]
  • 本文详细介绍了C语言中的指针,包括其基本概念、应用场景以及使用时的优缺点。同时,通过实例解析了指针在内存管理、数组操作、函数调用等方面的具体应用,并探讨了指针的安全性问题。 ... [详细]
  • C语言标准及其GCC编译器版本
    编程语言的发展离不开持续的维护和更新。本文将探讨C语言的标准演变以及GCC编译器如何支持这些标准,确保其与时俱进,满足现代开发需求。 ... [详细]
  • 解析SQL查询结果的排序问题及其解决方案
    本文探讨了为什么某些SQL查询返回的数据集未能按预期顺序排列,并提供了详细的解决方案,帮助开发者理解并解决这一常见问题。 ... [详细]
  • C语言基础入门:7个经典小程序助你快速掌握编程技巧
    本文精选了7个经典的C语言小程序,旨在帮助初学者快速掌握编程基础。通过这些程序的实践,你将更深入地理解C语言的核心概念和语法结构。 ... [详细]
author-avatar
郭爷们1986_488
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有