手把手教你嵌入式linux根文件系统原理和制作方法

一起学嵌入式 2024-06-29 08:13

扫描关注一起学嵌入式,一起学习,一起成长

今天分享一下关于Linux根文件系统的内容:

  1、根文件系统原理   

1.1 为什么需要根文件系统

  • init进程的应用程序在根文件系统上
  • 根文件系统提供了根目录 /
  • 内核启动后的应用层配置( etc 目录)在根文件系统上。几乎可以认为:发行版=内核+rootfs
  • shell命令程序在根文件系统上,比如 ls、cd 等命令

一套linux体系,只有内核本身是不能工作的,必须要 rootfs 上的 etc 目录下的配置文件、/bin /sbin 等目录下的 shell 命令,还有 /lib 目录下的库文件等···)相配合才能工作 。

1.2 根文件系统的实质

  • 根文件系统是特殊用途的文件系统。
  • 根文件系统也必须属于某种文件系统格式。rootfstype=

存储设备(块设备,像硬盘、flash等)是分块(扇区)的,物理上底层去访问存储设备时是按照块号(扇区号)来访问的。

文件系统是一些代码,是一套软件,这套软件的功能就是对存储设备的扇区进行管理,将这些扇区的访问变成了对目录和文件名的访问。

我们在上层按照特定的目录和文件名去访问一个文件时,文件系统会将这个目录+文件名转换成对扇区号的访问。不同的文件系统的差异就在于对这些扇区的管理策略和方法不同,譬如坏块管理、碎片管理。

1.3 根文件系统的形式

  • 使用专用工具软件制作的可供烧录的镜像文件
  • 镜像中包含了根文件系统中的所有文件
  • 烧录此镜像类似于对相应分区格式化。
  • 镜像文件系统具有一定的格式,格式是内化的,跟文件名后缀是无关的。

以文件夹形式构成的文件系统:

  • 根文件系统其实就是一个包含特定内容的文件夹
  • 根文件系统可由任何一个空文件夹添加必要文件构成而成
  • 根文件系统的雏形就是在开发主机中构造的文件夹形式的

镜像文件形式的根文件系统主要目的是用来烧录到块设备上,设备上的内核启动后去挂载它。镜像文件形式的根文件系统是由文件夹形式的根文件系统使用专用的镜像制作工具制作而成的。

最初在开发主机中随便 mkdir 创建了一个空文件夹,然后向其中添加一些必要的文件(包括etc目录下的运行时配置文件、/bin 等目录下的可执行程序、/lib目录下的库文件等···)后就形成了一个文件夹形式的 rootfs。

然后这个文件夹形式的 rootfs 可以被 kernel 通过 nfs 方式来远程挂载使用,但是不能用来烧录块设备。我们为了将这个 rootfs 烧录到块设备中于是用一些专用的软件工具将其制作成可供烧录的一定格式的根文件系统镜像。

文件夹形式的 rootfs 是没有格式的,制作成镜像后就有了一定的 rootfs 格式了,格式是由我们的镜像制作过程和制作工具来决定的。每一种格式的镜像制作工具的用法都不同。

1.4 自己制作简单的根文件系统

1.4.1 动手制作ext3格式的根文件系统

  • mke2fs介绍

mke2fs 是一个应用程序,在 ubuntu 中默认是安装了的。这个应用程序就是用来制作 ext2、ext3、ext4 等格式的根文件系统的。

一般用来制作各种不同格式的 rootfs 的应用程序的名字都很相似,类似于 mkfs.xxx(譬如用来制作 ext2 格式的 rootfs 的工具叫 mkfs.ext2、用来制作 jffs2 格式的 rootfs 的工具就叫 mkfs.jffs2)。ubuntu14.04中的 mkfs.ext2 等都是 mke2fs 的符号链接而已。

  1. 创建rootfs.ext2文件并且将之挂载到一个目录下方便访问它 《参考资料:http://blog.csdn.net/zhengmeifu/article/details/24174513》
dd if=/dev/zero of=rootfs.ext2 bs=1024 count=2048
losetup  /dev/loop1 rootfs.ext2
mke2fs -m 0 /dev/loop1 2048
mount -t ext2 /dev/loop1 ./rootfs/
  1. 我们向镜像中写入一个普通文件linuxrc。这个文件就会成为我们制作的镜像中的/linuxrc。内核挂载了这个镜像后就会尝试去执行/linuxrc。然后执行时必然会失败。我们将来实验看到的现象就应该是:挂载成功,执行/linuxrc失败。

  2. 将来真正去做有用的rootfs时,就要在这一步添加真正可以执行的 linuxrc 程序,然后还要添加别的 /lib 目录下的库文件,/etc目录下的配置文件等。

  3. 卸载掉,然后镜像就做好了。

umount /dev/loop1
losetup -d /dev/loop1

1.4.2 nfs 方式启动 rootfs

  • 什么是 nfs?

nfs 是一种网络通讯协议,由服务器和客户端构成。利用 nfs 协议可以做出很多直接性应用,我们这里使用 nfs 主要是做 rootfs 挂载。

开发板中运行 kernel 做 nfs 客户端,主机 ubuntu 中搭建 nfs 服务器。在主机 ubuntu 的 nfs 服务器中导出我们制作的文件夹形式的 rootfs 目录,则在客户端中就可以去挂载这个文件夹形式的 rootfs 进而去启动系统。

  • 搭建nfs服务器

配置内核以支持 nfs 作为 rootfs,设置 nfs 启动方式的 bootargs,在 menuconfig 中配置支持 nfs 启动方式。

  • 总结

nfs 方式启动相当于开发板上的内核远程挂载到主机上的 rootfs,nfs 方式启动不用制作 rootfs 镜像。nfs 方式不适合真正的产品,一般作为产品开发阶段调试使用。

  • uboot 中的启动参数设置
setenv bootargs root=/dev/nfs nfsroot=192.168.1.104:/home/SummerGift/work/samsung_kernel/rootfs/rootfs ip=192.168.1.88:192.168.1.104:192.168.1.1:255.255.255.0::eth0:off  init=/linuxrc console=ttySAC2,115200 
  • 测试 nfs 挂载
mount -t nfs -o nolock 192.168.1.104:/home/SummerGift/work/samsung_kernel/rootfs/rootfs  /opt

1.4.3 关于 linuxrc

  • /linuxrc 是一个可执行的应用程序 /linuxrc 是应用层的,和内核源码一点关系都没有,/linuxrc 在开发板当前内核系统下是可执行的。

    因此在 ARM SoC 的 linux 系统下,这个应用程序就是用 arm-linux-gcc 编译链接的;如果是在 PC 机 linux 系统下,那么这个程序就是用 gcc 编译连接的。

/linuxrc如果是静态编译连接的那么直接可以运行;如果是动态编译连接的那么我们还必须给他提供必要的库文件才能运行。

但是因为我们 /linuxrc 这个程序是由内核直接调用执行的,因此用户没有机会去导出库文件的路径,因此实际上这个 /linuxrc 没法动态连接,一般都是静态连接的。

  • /linuxrc执行时引出用户界面 操作系统启动后在一系列的自己运行配置之后,最终会给用户一个操作界面(也许是 cmdline,也许是 GUI),这个用户操作界面就是由 /linuxrc 带出来的。

用户界面等很多事并不是在 /linuxrc 程序中负责的,用户界面有自己专门的应用程序,但是用户界面的应用程序是直接或者间接的被 /linuxrc 调用执行的。

用户界面程序和其他的应用程序就是进程2、3、4·····,这就是我们说的进程1(init进程,也就是 /linuxrc)是其他所有应用程序进程的祖宗进程。

  • /linuxrc 负责系统启动后的配置 就好像一个房子建好之后不能直接住,还要装修一样;操作系统启动起来后也不能直接用,要配置下。操作系统启动后的应用层的配置(一般叫运行时配置,英文简写 etc)是为了让我们的操作系统用起来更方便,更适合我个人的爱好或者实用性。

  • /linuxrc在嵌入式linux中一般就是busybox busybox 是一个 C 语言写出来的项目,里面包含了很多 .c 文件和 .h 文件。

  • 这个项目可以被配置编译成各个平台下面可以运行的应用程序。我们如果用 arm-linux-gcc 来编译busybox就会得到一个可以在我们开发板 linux 内核上运行的应用程序。

busybox 这个程序开发出来就是为了在嵌入式环境下构建 rootfs 使用的,也就是说他就是专门开发的 init 进程应用程序。

busybox 为当前系统提供了一整套的 shell 命令程序集。譬如 vi、cd、mkdir、ls 等。在桌面版的linux 发行版(譬如ubuntu、redhat、centOS等)中 vi、cd、ls 等都是一个一个的单独的应用程序。

但是在嵌入式 linux 中,为了省事我们把 vi、cd 等所有常用的 shell 命令集合到一起构成了一个shell 命令包,起名叫 busybox。

1.4.4 rootfs 中的其他目录

  • /linuxrc

  • dev目录下的设备文件


在linux中一切皆是文件,因此一个硬件设备也被虚拟化成一个设备文件来访问,在linux系统中/dev/xxx就表示一个硬件设备,我们要操作这个硬件时就是open打开这个设备文件,然后read/write/ioctl操作这个设备,最后close关闭这个设备。在最小 rootfs 中 /dev 目录也是不可少的,这里面有一两个设备文件是 rootfs 必须的。

  • sys和proc目录

在最小 rootfs 中也是不可省略的,但是这两个只要创建了空文件夹即可,里面是没东西的,也不用有东西。这两个目录也是和驱动有关的。属于linux中的虚拟文件系统。

  • usr是系统的用户所有的一些文件的存放地,这个东西将来 busybox 安装时会自动生成。

    etc 目录中的所有文件全部都是运行时配置文件。/etc 目录下的所有配置文件会直接或者间接的被 /linuxrc 所调用执行,完成操作系统的运行时配置。etc 目录是制作 rootfs 的关键,所以后面下一个课程专门讲这个 etc 目录。

    lib 目录也是 rootfs 中很关键的一个,不能省略的一个。lib目录下放的是当前操作系统中的动态和静态链接库文件。我们主要是为了其中的动态链接库。


   2、用busybox制作一个简单的rootfs 

2.1 移植 busybox 到开发板

  • busybox源码下载

busybox 是一个开源项目,所以源代码可以直接从网上下载。版本差异不大,版本新旧无所谓。下载busybox可以去 linuxidc 等镜像网站,也可以去 www.busybox.net官方网站下载。

  • 修改Makefile
ARCH = arm
CROSS_COMPILE = /usr/local/arm/arm-2009q3/bin//arm-none-linux-gnueabi-
  • make menuconfig 进行配置
Busybox Settings--->
 Build Options--->
  [*]Build BusyBox as a static binary(no shared libs)

Busybox Library Tuning--->
 [*]vi-style line editing commands
 [*]Fancy shell prompts

Linux Module Utilities--->
 [ ]Simplified modutils
 [*]insmod
 [*]rmmod
 [*]lsmod
 [*]modprobe
 [*]depmod

Linux System Utilities--->[*]mdev
 [*]Support /etc/mdev.conf
 [*]Support subdirs/symlinks
 [*]Support regular expressions substitutions when renaming dev
 [*]Support command execution at device addition/removal
 [*]Support loading of firmwares
  • make 然后 make install

make 编译,如果有错误解决之,make install 执行的时候其实是在执行 busybox 顶层目录下的一个目标 install。

make install 在所有的 linux 下的软件中作用都是安装软件。在传统的 linux 系统中安装软件时都是选择源代码方式安装的。

我们下载要安装的软件源代码,然后配置、编译、安装。make install的目的就是将编译生成的可执行程序及其依赖的库文件、配置文件、头文件安装到当前系统中指定(一般都可以自己指定安装到哪个目录下,如果不指定一般都有个默认目录)的目录下。

  • 设置 bootargs 挂载添加了busybox移植的rootfs

之前建立了一个空的文件夹然后自己 touch linuxrc 随便创建了一个不能用的 /linuxrc 然后去 nfs 挂载 rootfs,实验结果是:挂载成功,执行 /linuxrc 失败。

现在我们移植了 busybox 后 /linuxrc 就可以用了,然后再次去 nfs 挂载这个 rootfs。预计看到的效果是:挂载成功,执行/linuxrc也能成功。

uboot 的 bootargs 设置成:

setenv bootargs root=/dev/nfs nfsroot=192.168.1.141:/root/porting_x210/rootfs ip=192.168.1.10:192.168.1.141:192.168.1.1:255.255.255.0::eth0:off  init=/linuxrc console=ttySAC2,115200 

挂载成功,执行 /linuxrc(也就是busybox)成功,但是因为找不到 /etc/init.d/rcS 和 /dev/tty2 等文件所以一直在打印错误提示信息,但是其实有进入命令行。

2.2 inittab 详解

  • 添加一个典型的inittab

将一个典型的 inittab 文件复制到我们制作的 rootfs 的根目录下的 /etc/ 目录下,再次启动内核挂载这个 rootfs 看效果,实验现象是成功启动并且挂载 rootfs 进入了控制台命令行。当前制作的最小rootfs 成功了。

  • inittab格式解析

inittab 的工作原理就是被 /linuxrc(也就是busybox)执行时所调用起作用。

inittab 在 /etc 目录下,所以属于一个运行时配置文件,是文本格式的(内容是由一系列的遵照一个格式组织的字符组成的),实际工作的时候 busybox 会(按照一定的格式)解析这个 inittab 文本文件,然后根据解析的内容来决定要怎么工作。

busybox 究竟如何完成解析并且解析结果如何去工作(busybox 中实现 /etc/inittab 的原理)并不是我们的目标,我们的重点是 inittab 的格式究竟怎样的?我们看到一个 inittab 后怎么去分析这个inittab 对启动的影响。inittab 的格式在 busybox 中定义的。

  • 常见的配置项
第一个:#开始的行是注释 
第二个:冒号在里面是分隔符,分隔开各个部分。
第三个:inittab内容是以行为单位的,行与行之间没有关联,每行都是一个独立的配置项,每一个配置项表示一个具体的含义。
第四个:每一行的配置项都是由3个冒号分隔开的4个配置值共同确定的。这四个配置值就是id:runlevels:action:process。值得注意是有些配置值可以空缺,空缺后冒号不能空缺,所以有时候会看到连续2个冒号。
第五个:每一行的配置项中4个配置值中最重要的是 action 和 process,action 是一个条件/状态,process 是一个可被执行的程序的 pathname。

合起来的意思就是:当满足 action 的条件时就会执行process 这个程序。

理解 inittab 的关键就是明白“当满足 action 的条件时就会执行 process 这个程序。” 分析 busybox的源代码就会发现,busybox 最终会进入一个死循环,在这个死循环中去反复检查是否满足各个action 的条件,如果某个 action 的条件满足就会去执行对应的 process。

   3、busybox源码分析   

3.1 分析 busybox 启动状况

分析一个程序,不管多庞大还是小,最好的路线都是按照程序运行时的逻辑顺序来。所以找到一个程序的入口至关重要。主函数main函数就是整个程序的入口,这种情况适应于操作系统下工作的应用程序的情况。

在 uboot 和 linux kernel 这两个大的 C 语言的项目中,main函数都没有,都不是入口。在我们这种裸机程序中入口不是 main 函数,而是由连接脚本来指定的。

busybox 是 linux 启动起来后工作的一个应用程序,因此其中必然有 main 函数,而且 main 就是入口。

3.2 busybox 中 main 函数全解析

busybox 入口就是 main 函数,其中有很多个 main 但是只有一个起作用了,其他的是没起作用的。真正的busybox工作时的入口是 libbb/appletlib.c 中的 main 函数。

busybox中有很多 xxx_main 函数,这些 main 函数每一个都是 busybox 支持的一个命令的真正入口。例如 ls_main 函数就是 busybox 当作 ls 函数使用时的入口程序。ls 或者 cd 等命令其实都是 busybox 一个程序,但是实际执行时的效果却是各自的效果。

busybox 每次执行时都是先执行其 main,在 main 函数中识别(靠 main 函数的传参 argv[0] 来识别)我们真正要执行的函数(譬如ls)然后去调用相应的xxx_main(譬如ls_main)来具体实现这个命令。

3.3 inittab 解析与执行

inittab 的解析是在 busybox/init/init.c/init_main 函数中。执行逻辑是:先通过 parse_inittab 函数解析 /etc/inittab(解析的重点是将 inittab 中的各个 action 和 process 解析出来),然后后面先直接执行 sysinit 和 wait 和 once(注意这里只执行一遍),然后在 while(1) 死循环中去执行 respwan 和 askfirst。

3.4 busybox 的体积优势原理

busybox 实际上就是把 ls、cd、mkdir 等很多个 linux 中常用的 shell 命令集成在一起了。集成在一起后有一个体积优势:就是 busybox 程序的大小比 busybox 中实现的那些命令的大小加起来要小很多。

busybox 体积变小的原因主要有2个:

  • 第一个是 busybox 本身提供的 shell 命令是阉割版的(busybox 中的命令支持的参数选项比发行版中要少,譬如ls在发行版中可以有几十个 -x,但是在 busybox 中只保留了几个常用的选项,不常用的都删除掉了)

  • 第二个是 busybox 中因为所有的命令的实现代码都在一个程序中实现,而各个命令中有很多代码函数都是通用的(譬如 ls 和 cd、mkdir 等命令都会需要去操作目录,因此在 busybox 中实现目录操作的函数就可以被这些命令共用),共用会降低重复代码出现的次数,从而减少总的代码量和体积。

busybox 的体积优势是嵌入式系统本身的要求和特点造成的。


   4、rsS文件实战  

4.1 rcS 文件介绍

/etc/init.d/rcS 文件是linux的运行时配置文件中最重要的一个,其他的一些配置都是由这个文件引出来的。这个文件可以很复杂也可以很简单,里面可以有很多的配置项。

  • PATH=xxx

首先从shell脚本的语法角度分析,这一行定义了一个变量PATH,值等于后面的字符串,后面用export导出了这个PATH,那么PATH就变成了一个环境变量。

PATH 这个环境变量是 linux 系统内部定义的一个环境变量,含义是操作系统去执行程序时会默认到PATH 指定的各个目录下去寻找。如果找不到就认定这个程序不存在,如果找到了就去执行它。将一个可执行程序的目录导出到 PATH,可以让我们不带路径来执行这个程序。

  • rcS 中为什么要先导出 PATH?

因为我们希望一旦进入命令行下时,PATH 环境变量中就有默认的 /bin /sbin /usr/bin /usr/sbin 这几个常见的可执行程序的路径,这样我们进入命令行后就可以 ls、cd 等直接使用了。

为什么rcS 文件还没添加,系统启动就有了 PATH 中的值?原因在于 busybox 自己用代码硬编码为我们导出了一些环境变量,其中就有 PATH。

  • runlevel=

runlevel也是一个shell变量,并且被导出为环境变量,runlevel=S表示将系统设置为单用户模式。

  • umask=

umask 是 linux 的一个命令,作用是设置 linux 系统的 umask 值。umask值决定当前用户在创建文件时的默认权限。

  • mount -a

mount -a 是挂载所有的应该被挂载的文件系统,在 busybox中 mount -a 时 busybox 会去查找一个文件 /etc/fstab 文件,这个文件按照一定的格式列出来所有应该被挂载的文件系统(包括了虚拟文件系统)

  • mdev

mdev 是 udev 的嵌入式简化版本,udev/mdev 是用来配合 linux 驱动工作的一个应用层的软件,udev/mdev 的工作就是配合 linux 驱动生成相应的 /dev 目录下的设备文件。

在 rcS 文件中没有启动 mdev 的时候,/dev 目录下启动后是空的。在 rcS 文件中添加上 mdev 有关的 2 行配置项后,再次启动系统后发现 /dev 目录下生成了很多的设备驱动文件。(4)/dev目录下的设备驱动文件就是mdev生成的,这就是mdev的效果和意义。

  • hostname

hostname 是 linux 中的一个 shell 命令。命令(hostname xxx)执行后可以用来设置当前系统的主机名为 xxx,直接 hostname 不加参数可以显示当前系统的主机名。

/bin/hostname -F /etc/sysconfig/HOSTNAME -F 来指定了一个主机名配置文件(这个文件一般文件名叫 hostname 或者 HOSTNAME)

  • ifconfig

有时候我们希望开机后进入命令行时ip地址就是一个指定的 ip 地址(譬如192.168.1.30),这时候就可以在 rcS 文件中 ifconfig eth0 192.168.1.88

4.2 rcS 文件测试问题记录

  • PATH & runlevel

发现 rcS 文件明明存在但是却提示不存在,问题原因就是 rcS 文件在 windows 下创建的,行尾换行符为 '\r\n',多了点东西。

但是因为 ubuntu 中的 vi 对行尾做了优化,所以在 ubuntu 中是看不出来多了东西的。但是在 securecrt 下一看就发现每一行末尾多出来了一个 ^M。

这个情况表明:shell 脚本文件如果格式不对,运行时可能会被提示文件不存在。有时候一个应用程序执行时也会提示文件不存在,问题可能是这个程序所调用的一个动态链接库找不到。

测试结果:PATH 本来在 busybox 中就已经用代码导出过了,所以 rcS 中再次导出没有任何明显的现象,因此看不出什么差别。runlevel 实际执行结果一直是 unknown,问题在于 busybox 并不支持 runlevel 这个特性。

  • umask测试

umask是 022 的时候,默认touch创建一个文件的权限是 644 umask是 044 的时候,默认touch创建一个文件的权限是 622 umask是 444 的时候,默认touch创建一个文件的权限是 222

总结:umask 的规律就是:umask 值和默认创建文件的权限值加起来是 666。

  • mount 测试

挂载时全部出错:

mount: mounting proc on /proc failed: No such file or directory
mount: mounting sysfs on /sys failed: No such file or directory
mount: mounting tmpfs on /var failed: No such file or directory
mount: mounting tmpfs on /tmp failed: No such file or directory
mount: mounting tmpfs on /dev failed: No such file or directory

原因是因为根文件系统中找不到挂载点。所谓挂载点就是我们要将目标文件系统(当然这里都是虚拟文件系统)挂载到当前文件系统中的某一个目录中,这个目录就是挂载点。

解决方案就是自己在制作的 rootfs 根目录下创建这些挂载点目录即可。验证是否挂载成功,可以看挂载时输出信息;还可以启动后去看 proc 和 sys 文件夹,如果有文件出现则证明挂载成功了,如果没东西就证明失败了。

4.3 开机自启动与主流 rcS 格式介绍

  • 修改rcS实现开机自启动

机自启动指的是让一些应用程序能够开机后自动执行,开机自启动的实现原理就是在开机会自动执行的脚本 rcS 中添加上执行某个程序的语句代码即可。

  • 前台运行与后台运行

程序运行时占用了当前的控制台,因此这个程序不结束我们都无法使用控制台,这就叫前台运行。默认执行程序就是前台运行的。

后台运行就是让这个程序运行,并且同时让出控制台。这时候运行的程序还能照常运行而且还能够不影响当前控制台的使用。让一个程序后台运行的方法就是 ./xxx &。开机装载驱动等其他开机自动执行

  • 实际开发中 rootfs 的 rcS 是怎样的

分析 inittab 发现:sysinit 执行 rcS,shutdown 时执行 rcK。

分析 /etc/init.d/rcS 和 rcK 文件发现,rcS 和 rcK 都是去遍历执行 /etc/init.d/ 目录下的S开头的脚本文件,区别是 rcS 传参是 start,rcK 传参是 stop。

由此可以分析出来,正式产品中的 rcS 和 rcK 都是一个引入,而不是真正干活的。真正干活的配置脚本是 /etc/init.d/S??*

这些文件中肯定有一个判断参数是 start 还是 stop,然后 start 时去做一些初始化,stop 时做一些清理工作。

  5、添加动态链接库     

  • 静态编译链接 helloworld 程序并执行

自己写一个 helloworld 程序,然后交叉编译连接,然后丢到开发板根文件系统中,开机后去运行。

C 程序如果使用 gcc 来编译则可以在主机 ubuntu 中运行,但是不能在开发板运行。要在开发板运行需要用 arm-linux-gcc 来交叉编译,但是这时候就不能在主机 ubuntu 中运行了。

可以用 file xx 命令来查看一个 elf 可执行程序是哪个架构的。

静态链接:arm-linux-gcc hello.c -o hello_satic -static

静态编译连接后生成的 hello_satic 可以直接在开发板上运行。

  • 动态编译连接 helloworld 程序并执行

动态链接:arm-linux-gcc hello.c -o hello_dynamic

实验结果:-sh: ./hello_dynamic: not found 运行时提示找不到程序。

原因是动态连接的 hello 程序中调用到了 printf 函数,而 printf 函数在动态连接时要在运行时环境(开发板的rootfs)中去寻找对应的库文件(开发板 rootfs 中部署的动态链接库中包含了 printf 函数的那个库文件)。如果找到了则 printf 函数就会被成功解析,然后 hello_dynamic 程序就会被执行;如果找不到则程序就不能被执行,命令行会提示错误信息

-sh: ./hello_dynamic: not found

解决方案:将 arm-linux-gcc 的动态链接库文件复制到开发板 rootfs 的 /lib 目录下即可解决。

  • 找到并复制动态链接库文件到 rootfs 中

现在使用的 arm-2009q3 这个交叉编译工具链的动态链接库在 /usr/local/arm/arm-2009q3/arm-none-linux-gnueabi/libc/lib 目录下。其他的一些交叉编译工具链中动态链接库的目录不一定在这里,要去找一下。找的方法就是 find 命令,find -name *libm.so*

复制动态链接库到 roots/lib 目录下。复制时要注意参数用 -rdf,主要目的就是符号链接复制过来还是符号链接。

复制命令:

cp lib/ /home/SummerGift/work/samsung_kernel/rootfs/rootfs -r

拷贝动态链接库到根文件系统之后,再去测试 ./hello_dynamic 就可以直接运行了。

  • 使用 strip 工具去掉库中符号信息

动态链接库 so 文件中包含了调试符号信息,这些符号信息在运行时是没用的(调试时用的),这些符号会占用一定空间。

在传统的嵌入式系统中flash空间是有限的,为了节省空间常常把这些符号信息去掉。这样节省空间并且不影响运行。

去掉符号命令:arm-none-linux-gnueabi-strip *so*

使用该命令后发现库文件由3.8M变成了3.0M,节省了0.8M的空间。

   6、制作ext2格式镜像并烧录启动  

  • 确定文件夹格式的 rootfs 可用

设置 bootargs 为 nfs 启动方式,然后从主机 ubuntu 中做好的文件夹格式的 rootfs 去启动,然后看启动效果,作为将来的参照物。

  • 制作 ext2 格式的镜像
dd if=/dev/zero of=rootfs.ext2 bs=1024 count=10240
losetup  /dev/loop1 rootfs.ext2
mke2fs -m 0 /dev/loop1 10240
mount -t ext2 /dev/loop1 ./ext2_rootfs/

向 ./rootfs 中复制内容,用cp ../rootfs/* ./ -rf

umount /dev/loop1

losetup -d /dev/loop1

完成后得到的rootfs.ext2就是我们做好的rootfs镜像。拿去烧录即可。

  • 烧录镜像并设置合适的 bootargs

使用 fastboot 烧录制作好的 rootfs.ext2 到开发板 inand 中

fastboot flash system rootfs.ext2

烧录完成后重启系统,设置 bootargs 为:

set bootargs console=ttySAC2,115200 root=/dev/mmcblk0p2 rw init=/linuxrc rootfstype=ext2

启动后发现现象和之前 nfs 方式启动挂载 rootfs 后一样的,至此 rootfs 制作实验圆满完成。

   7、常见的linux产品的bsp介绍   

7.1 嵌入式 linux 产品的 bsp 介绍

大部分的 ARM 架构的 linux 平台的 bsp 的内容和结构都是相似的,bsp 一般是芯片厂家/板卡厂家提供的。

  • X210的 linux+QT bsp 整体介绍 tslib_x210_qtopia.tgz 是用来支持QT的触摸屏操作的应用层库。

xboot 和 uboot 是 X210 支持的2个 bootloader 源代码。kernel 文件夹中是内核源代码,buildroot 文件夹是用来构建根文件系统的文件夹。tools 里是一些有用工具。

7.2 mk 脚本

mk 脚本是用来管理和编译整个 bsp 的。

  • mk 的帮助信息 linux下的惯例就是,执行程序时加 -h 或者 --help 就可以看到这个程序执行的帮助信息。

mk 脚本的主要作用是编译 bsp 中的所有的源代码(包括bootloader、kernel、rootfs等),但是我们可以完整编译也可以部分编译,我们通过执行 mk 后面加不同的参数来指定 mk 脚本去编译相应的部分。

mk -a 即可编译所有的bsp源代码
mk -x 即可只编译xboot
mk -ui 即可只编译uboot针对inand版本开发板的源代码
mk -r   即可只编译buildroot,-r只是得到了文件夹形式的rootfs,并没有将其制作成镜像文件。
mk -re 即可编译buildroot并且制作得到ext3格式的rootfs镜像
mk -rj 即可编译buildroot并且制作得到jffs2格式的rootfs镜像

注:./mk和 mk 都是执行 mk 这个脚本文件,区别在于 ./mk 是带路径的,mk 是不带路径的。还有 source mk,这个和前两个的区别是 source 执行时不需要 mk 文件具有可执行权限,而前面两种要求 mk 必须在当前用户下具有可执行权限。

7.3 mk 文件分析

  • shell程序结构

shell 脚本程序分为:变量定义、函数、代码。shell脚本程序的结构非常类似于C语言程序。

shell 程序和 C 语言程序很大的一个差别就是 shell 没有 main 函数,shell 脚本执行时也是先执行主函数的,不过主函数没有放在一个类似于 main 这样的函数中,而是直接放在全局下的一些代码。

shell 程序执行时首先执行变量定义,然后执行主函数,其他函数在主函数代码中被调用执行。

  • 主函数 mk 可以编译整个bsp的源代码,也可以只编译其中一部分。实现原理就是:用一个函数来完成编译一个(譬如编译内核用build_kernel函数,编译 inand 的 uboot 用build_bootloader_uboot_inand),然后用相应的一些变量来控制这个函数要不要被编译(譬如uboot_inand 变量=yes就表示要编译inand版本的uboot,=no 就表示不要编译),我们编译时通过-xxxxx来传参时,这些传参会影响这些变量的值=yes或者=no。

如果直接./mk并不传参,则$1为空,这时候按照一套默认的配置来编译。

   8、buidroot介绍  

8.1 buildroot 介绍

之前自己从零开始构建根文件系统,一路下来事情还挺多,步骤比较麻烦。

交叉编译工具链 arm-linux-gcc,我们目前都是从 soc 官方直接拿来使用的,官方的工具链从何而来?实际上交叉编译工具链都是由gcc配置编译生成的,这个配置编译过程比较复杂,一般人自己去配置编译得到自己的交叉编译工具链是比较麻烦的,所以经常都是用别人最好的。

buildroot 就是一个集成包,这个包里集成了交叉编译工具链的制作,以及整个 rootfs 的配置编译过程。也就是说,使用 buildroot 可以很简便的得到一个做好的文件夹形式的根文件系统。

buildroot 将很多东西集成进来后,移植了 linux kernel 的 make xxx_defconfig+make menuconfig的 2 步配置法,我们可以在 buildroot 的配置界面下完成集成在里边的所有东西的配置,然后直接 make 就可以最终得到文件夹形式的 rootfs。

8.2 使用 buildroot 构建根文件系统

编译 buildroot 的错误解决方案(环境为ubuntu14.04)

  • make x210ii_defconfig
make xxx_defconfig
make menuconfig
make
  • make及其错误解决 直接 make 会遇到很多错误,这些错误原因都是因为ubuntu中缺乏一些必要软件包造成的。解决方案是先安装这些必要的软件包。编译过程会需要从网上下载一些软件包,因此整个编译过程需要在联网状态下进行。

  • 安装需要的软件包

sudo apt-get install g++ bison flex texinfo git hgsubversion whois
  • 编译后结果查看与分析

编译后生成的文件夹格式的 rootfs 在 buildroot/output/images/rootfs.tar。我们将其复制到了根目录下的 release 目录下去,这个文件就是一个完整的可以工作的文件夹形式的 rootfs。

文章来源于网络,版权归原作者所有,如有侵权,请联系删除。



关注【一起学嵌入式】,回复加群进技术交流群。



觉得文章不错,点击“分享”、“”、“在看” 呗!

一起学嵌入式 公众号【一起学嵌入式】,RTOS、Linux编程、C/C++,以及经验分享、行业资讯、物联网等技术知
评论
  • 日前,商务部等部门办公厅印发《手机、平板、智能手表(手环)购新补贴实施方案》明确,个人消费者购买手机、平板、智能手表(手环)3类数码产品(单件销售价格不超过6000元),可享受购新补贴。每人每类可补贴1件,每件补贴比例为减去生产、流通环节及移动运营商所有优惠后最终销售价格的15%,每件最高不超过500元。目前,京东已经做好了承接手机、平板等数码产品国补优惠的落地准备工作,未来随着各省市关于手机、平板等品类的国补开启,京东将第一时间率先上线,满足消费者的换新升级需求。为保障国补的真实有效发放,基于
    华尔街科技眼 2025-01-17 10:44 206浏览
  •  光伏及击穿,都可视之为 复合的逆过程,但是,复合、光伏与击穿,不单是进程的方向相反,偏置状态也不一样,复合的工况,是正偏,光伏是零偏,击穿与漂移则是反偏,光伏的能源是外来的,而击穿消耗的是结区自身和电源的能量,漂移的载流子是 客席载流子,须借外延层才能引入,客席载流子 不受反偏PN结的空乏区阻碍,能漂不能漂,只取决于反偏PN结是否处于外延层的「射程」范围,而穿通的成因,则是因耗尽层的过度扩张,致使跟 端子、外延层或其他空乏区 碰触,当耗尽层融通,耐压 (反向阻断能力) 即告彻底丧失,
    MrCU204 2025-01-17 11:30 156浏览
  • 高速先生成员--黄刚这不马上就要过年了嘛,高速先生就不打算给大家上难度了,整一篇简单但很实用的文章给大伙瞧瞧好了。相信这个标题一出来,尤其对于PCB设计工程师来说,心就立马凉了半截。他们辛辛苦苦进行PCB的过孔设计,高速先生居然说设计多大的过孔他们不关心!另外估计这时候就跳出很多“挑刺”的粉丝了哈,因为翻看很多以往的文章,高速先生都表达了过孔孔径对高速性能的影响是很大的哦!咋滴,今天居然说孔径不关心了?别,别急哈,听高速先生在这篇文章中娓娓道来。首先还是要对各位设计工程师的设计表示肯定,毕竟像我
    一博科技 2025-01-21 16:17 41浏览
  • 本文介绍瑞芯微开发板/主板Android配置APK默认开启性能模式方法,开启性能模式后,APK的CPU使用优先级会有所提高。触觉智能RK3562开发板演示,搭载4核A53处理器,主频高达2.0GHz;内置独立1Tops算力NPU,可应用于物联网网关、平板电脑、智能家居、教育电子、工业显示与控制等行业。源码修改修改源码根目录下文件device/rockchip/rk3562/package_performance.xml并添加以下内容,注意"+"号为添加内容,"com.tencent.mm"为AP
    Industio_触觉智能 2025-01-17 14:09 124浏览
  •  万万没想到!科幻电影中的人形机器人,正在一步步走进我们人类的日常生活中来了。1月17日,乐聚将第100台全尺寸人形机器人交付北汽越野车,再次吹响了人形机器人疯狂进厂打工的号角。无独有尔,银河通用机器人作为一家成立不到两年时间的创业公司,在短短一年多时间内推出革命性的第一代产品Galbot G1,这是一款轮式、双臂、身体可折叠的人形机器人,得到了美团战投、经纬创投、IDG资本等众多投资方的认可。作为一家成立仅仅只有两年多时间的企业,智元机器人也把机器人从梦想带进了现实。2024年8月1
    刘旷 2025-01-21 11:15 34浏览
  • 现在为止,我们已经完成了Purple Pi OH主板的串口调试和部分配件的连接,接下来,让我们趁热打铁,完成剩余配件的连接!注:配件连接前请断开主板所有供电,避免敏感电路损坏!1.1 耳机接口主板有一路OTMP 标准四节耳机座J6,具备进行音频输出及录音功能,接入耳机后声音将优先从耳机输出,如下图所示:1.21.2 相机接口MIPI CSI 接口如上图所示,支持OV5648 和OV8858 摄像头模组。接入摄像头模组后,使用系统相机软件打开相机拍照和录像,如下图所示:1.3 以太网接口主板有一路
    Industio_触觉智能 2025-01-20 11:04 119浏览
  • 电竞鼠标应用环境与客户需求电竞行业近年来发展迅速,「鼠标延迟」已成为决定游戏体验与比赛结果的关键因素。从技术角度来看,传统鼠标的延迟大约为20毫秒,入门级电竞鼠标通常为5毫秒,而高阶电竞鼠标的延迟可降低至仅2毫秒。这些差异看似微小,但在竞技激烈的游戏中,尤其在对反应和速度要求极高的场景中,每一毫秒的优化都可能带来致胜的优势。电竞比赛的普及促使玩家更加渴望降低鼠标延迟以提升竞技表现。他们希望通过精确的测试,了解不同操作系统与设定对延迟的具体影响,并寻求最佳配置方案来获得竞技优势。这样的需求推动市场
    百佳泰测试实验室 2025-01-16 15:45 324浏览
  • 80,000人到访的国际大展上,艾迈斯欧司朗有哪些亮点?感未来,光无限。近日,在慕尼黑electronica 2024现场,ams OSRAM通过多款创新DEMO展示,以及数场前瞻洞察分享,全面展示自身融合传感器、发射器及集成电路技术,精准捕捉并呈现环境信息的卓越能力。同时,ams OSRAM通过展会期间与客户、用户等行业人士,以及媒体朋友的深度交流,向业界传达其以光电技术为笔、以创新为墨,书写智能未来的深度思考。electronica 2024electronica 2024构建了一个高度国际
    艾迈斯欧司朗 2025-01-16 20:45 191浏览
  • 2024年是很平淡的一年,能保住饭碗就是万幸了,公司业绩不好,跳槽又不敢跳,还有一个原因就是老板对我们这些员工还是很好的,碍于人情也不能在公司困难时去雪上加霜。在工作其间遇到的大问题没有,小问题还是有不少,这里就举一两个来说一下。第一个就是,先看下下面的这个封装,你能猜出它的引脚间距是多少吗?这种排线座比较常规的是0.6mm间距(即排线是0.3mm间距)的,而这个规格也是我们用得最多的,所以我们按惯性思维来看的话,就会认为这个座子就是0.6mm间距的,这样往往就不会去细看规格书了,所以这次的运气
    wuliangu 2025-01-21 00:15 75浏览
  • 嘿,咱来聊聊RISC-V MCU技术哈。 这RISC-V MCU技术呢,简单来说就是基于一个叫RISC-V的指令集架构做出的微控制器技术。RISC-V这个啊,2010年的时候,是加州大学伯克利分校的研究团队弄出来的,目的就是想搞个新的、开放的指令集架构,能跟上现代计算的需要。到了2015年,专门成立了个RISC-V基金会,让这个架构更标准,也更好地推广开了。这几年啊,这个RISC-V的生态系统发展得可快了,好多公司和机构都加入了RISC-V International,还推出了不少RISC-V
    丙丁先生 2025-01-21 12:10 42浏览
  • Ubuntu20.04默认情况下为root账号自动登录,本文介绍如何取消root账号自动登录,改为通过输入账号密码登录,使用触觉智能EVB3568鸿蒙开发板演示,搭载瑞芯微RK3568,四核A55处理器,主频2.0Ghz,1T算力NPU;支持OpenHarmony5.0及Linux、Android等操作系统,接口丰富,开发评估快人一步!添加新账号1、使用adduser命令来添加新用户,用户名以industio为例,系统会提示设置密码以及其他信息,您可以根据需要填写或跳过,命令如下:root@id
    Industio_触觉智能 2025-01-17 14:14 89浏览
  • 在物联网(IoT)短距无线通信生态系统中,低功耗蓝牙(BLE)数据透传是一种无需任何网络或基础设施即可完成双向通信的技术。其主要通过简单操作串口的方式进行无线数据传输,最高能满足2Mbps的数据传输速率,可轻松实现设备之间的快速数据同步和实时交互,例如传输传感器数据、低采样率音频/图像与控制指令等。低功耗蓝牙(BLE)数据透传解决方案组网图具体而言,BLE透传技术是一种采用蓝牙通信协议在设备之间实现数据透明传输的技术,设备在通信时会互相验证身份和安全密钥,具有较高的安全性。在不对MCU传输数据进
    华普微HOPERF 2025-01-21 14:20 33浏览
  • 随着消费者对汽车驾乘体验的要求不断攀升,汽车照明系统作为确保道路安全、提升驾驶体验以及实现车辆与环境交互的重要组成,日益受到业界的高度重视。近日,2024 DVN(上海)国际汽车照明研讨会圆满落幕。作为照明与传感创新的全球领导者,艾迈斯欧司朗受邀参与主题演讲,并现场展示了其多项前沿技术。本届研讨会汇聚来自全球各地400余名汽车、照明、光源及Tier 2供应商的专业人士及专家共聚一堂。在研讨会第一环节中,艾迈斯欧司朗系统解决方案工程副总裁 Joachim Reill以深厚的专业素养,主持该环节多位
    艾迈斯欧司朗 2025-01-16 20:51 152浏览
  • 数字隔离芯片是一种实现电气隔离功能的集成电路,在工业自动化、汽车电子、光伏储能与电力通信等领域的电气系统中发挥着至关重要的作用。其不仅可令高、低压系统之间相互独立,提高低压系统的抗干扰能力,同时还可确保高、低压系统之间的安全交互,使系统稳定工作,并避免操作者遭受来自高压系统的电击伤害。典型数字隔离芯片的简化原理图值得一提的是,数字隔离芯片历经多年发展,其应用范围已十分广泛,凡涉及到在高、低压系统之间进行信号传输的场景中基本都需要应用到此种芯片。那么,电气工程师在进行电路设计时到底该如何评估选择一
    华普微HOPERF 2025-01-20 16:50 25浏览
我要评论
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦