百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程网 > 正文

在Ubuntu X86_64中构建arm ubuntu rootfs和调试arm应用

yuyutoo 2024-10-11 21:43 8 浏览 0 评论

我们常用的是使用buildroot、busybox、yocto进行构建arm嵌入式根文件系统,这种方式大家接触得应该都比较多了,构建也是比较简单,唯一得缺点是源得速度太慢了,有时候需要一天才能编译出来一个文件系统。

1. 下载ubuntu base包

我今天讲得是一个更简单得方法,从ubuntu-base进行构建,以ubuntu20.04为例,下载arm架构的ubuntu-base压缩包https://cdimage.ubuntu.com/ubuntu-base/releases/,可以看到有几类以后缀-armXX.tar.gz结尾的,它们的含义如下:

  • ubuntu-base-20.04.3-base–arm64.tar.gz 适用于64位arm架构,几乎所有ARMv8-A都是64位处理器,例如ARM Cortex-A53、 ARM Cortex-A57、ARM Cortex-A72、ARM Cortex-A73、RM_Cortex-A76等。
  • ubuntu-base-20.04.3-base-armhf.tar.gz 适用于32位带硬浮点arm处理器,hf(hard float),即带有浮点单元 (FPU),主要用于ARMv7-A,例如[ARM Cortex-A5、ARM Cortex-A7、ARM Cortex-A8、ARM Cortex-A9、ARM Cortex-A12、ARM Cortex-A15、ARM Cortex-A17。

压缩包25M左右,解压出来大概50多M,还是比较精简的,如果这个大小不能接受,就只能自己使用buildroot构建,经常用它来构建一个ramdisk. QSPIFlash就完全可以装下一个文件系统。

使用ubuntu-base的好处是,可以直接使用apt来安装你所需要的软件包,不需要一个一个的编译各种依赖环境。我们下载后解压可以看到,很多命令是没有的,基本的ifconfigvim,file等命令都没有,当然实际运行环境是不需要这些软件包的。

如果你的嵌入式环境中没有网络,则我们可以直接在PC的Ubuntu中将需要的包通过apt安装好,再打包烧写到arm中。

下面讲一下具体方法:

2. 将ubuntu-base解压

将ubuntu-base包解压到准备的rootfs文件夹,这里为/mnt/ubuntu,下面命令根据实际情况更换

$sudo tar -xpvf ubuntu-base-20.04.3-base-armhf.tar.gz -C /mnt/ubuntu

3. 安装qemu arm模拟器环境,可以直接在x86_64中运行和调试应用

通过apt安装qemu

sudo apt-get install multistrap qemu qemu-user-static binfmt-support dpkg-cross

查看qemu版本

qemu-arm-static --version
qemu-arm version 2.11.1(Debian 1:2.11+dfsg-1ubuntu7.37)

Ubuntu自带的 QEMU 版本有点老(我的18.04 LTS 附带的 QEMU 2.11),如果需要新版本则需要自己编译安装,当前最新版本是QEMU 6.1.0

wget https://download.qemu.org/qemu-6.1.0.tar.xz
tar xvJf qemu-6.1.0.tar.xz
mkdir build
cd build
../qemu-6.1.0/configure --static --prefix="$PWD/user_static" --target-list=arm-softmmu --disable-system

--disable-system不编译qemu-system-xx相关的程序,这里暂时不需要.

其中--target-list后面可以接不同的架构的qemu,比如arm-softmmu是针对arm平台的。aarch64-softmmu是针对arm64平台,也就是aarch64.

4. 安装binfmt

binfmt(Binary Format)是一个内核模块,它的用处如它的名字,通过二进制文件头来识别它的格式,从而指定用哪个解释器去启动——可以理解为二进制文件的hashbang(用处类似于在Python文件的第一行写上“#!/usr/bin/env python”)。有了它我们就可以像启动原生ELF一样启动一个ARM或其他任何QEMU支持的程序了。

sudo apt install qemu-user-binfmt
update-binfmts --display

安装这个包会依赖安装系统软件源中的qemu-user。我们用不到它,但装这个包的意义在于它包含了几个自动向内核注册QEMU binfmt的脚本,这样我们就不需要再手动指定我们的ARM可执行文件需要哪个路径下的QEMU来执行,非常方便。安装成功后在命令行中执行“update-binfmts –display”。

我们此时可以测试一下,临时将环境变量QEMU_LD_PREFIX设置为我们要chroot进去的根目录,然后运行ARM设备中提取出的ELF可执行文件,如果不报错就可以了。如下a.out是我编译的arm的hello world,这个程序可在我的测试设备上正常运行。

5. 如何在x86_64中调试arm程序?不用在开发板中调试

编辑hello.c测试程序

#include <stdio.h>
int main()
{
    printf("hello world!\r\n");
    return 0;
}

交叉编译arm程序

$ arm-linux-gnueabihf-gcc hello.c -o a.out
$ file a.out             
a.out: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-armhf.so.3, for GNU/Linux 3.2.0, BuildID[sha1]=222b024ba166e297b1ceb1dc97a906259712bb60, with debug_info, not stripped

使用qemu在x86下运行arm程序

$ export QEMU_LD_PREFIX=/mnt/ubuntu
$ ./a.out

hello world!

不加QEMU_LD_PREFIX环境变量,则会出现找不到库的错误提示/lib/ld-linux-armhf.so.3: No such file or directory.

/mnt/ubuntu是ubuntu base包的解压路径,也就是arm rootfs的根目录.

在这里每次都需要设置QEMU_LD_PREFIX环境变量.我们是否可以模拟arm的文件系统环境?直接运行程序呢? 答案是肯定的.这也是我们在x86环境中构建根文件系统的原因.

复制QEMU程序

拷贝qemu-arm-static或者我们自己编译的最新版本到刚刚解压出来的目录/mnt/ubuntu/usr/bin/

$sudo cp /usr/bin/qemu-arm-static /mnt/ubuntu/usr/bin

若是arm64则拷贝qemu-aarch64-static

$sudo cp /usr/bin/qemu-aarch64-static /mnt/ubuntu/usr/bin

当我们启动为ARM或其他架构编译的应用程序时,系统会调用binfmts识别它的类型并调用之前注册的interpreter(如/usr/bin/qemu-aarch64)来“翻译”启动。在chroot下,依然会从这个路径中寻找。因此如果使用chroot 后[6 小点讲解],这个路径下找不到QEMU,启动任何程序都会报错No such file or directory。这个报错会有很多歧义,因此一定要自己确认一下QEMU确实在rootfs的“/usr/bin”目录中。

以后拿到一个新的固件包,只需要解压到一个文件夹里,把对应架构的qemu拷贝进去,直接运行命令chroot即可。遇到需要调试的程序,我们通过运行qemu-arm -g 2331 /path/to/binary指定-g参数开启调试选项,也可以声明一个环境变量QEMU_GDB=2331,带上这个环境变量所启动的程序,都会自动开启GDB端口并等待调试器attach,调试起来是不是很方便呢?

6. chroot操作

方法1:使用原始的方法,来进入chroot环境

挂载和激活 /dev:通常激活 /dev 目录下设备的方式是在 /dev 目录挂载一个虚拟文件系统(比如 tmpfs),然后允许在检测 到设备或打开设备时在这个虚拟文件系统里动态创建设备节点。这个通常是在启动过程中由 udev 完成。由于我们的ubuntu-base新系统还没有 udev,也没有被引导,有必要手动挂载和激活 /dev 这可以通过绑定挂载宿主机系统的/dev 目录来实现。绑定挂载是一种特殊的挂载模式,它允许在另外的位置创建某个目录或挂载点的镜像。运行下面的命令来实现:

sudo mount -v --bind /dev /mnt/ubuntu/dev

挂载虚拟文件系统:

sudo mount -vt devpts devpts /mnt/ubuntu/dev/pts -o gid=5,mode=620
sudo mount -vt proc proc /mnt/ubuntu/proc
sudo mount -vt sysfs sysfs /mnt/ubuntu/sys
sudo mount -vt tmpfs tmpfs /mnt/ubuntu/run
sudo cp /etc/resolve.conf /mnt/ubuntu/etc/

进入chroot环境:

chroot /mnt/ubuntu

我们可以编写一个bash脚本ch-mount.sh来完成挂载和后面的卸载操作

sudo bash ch-mount.sh -m ubuntu-rootfs/

ch-mount.sh的内容

#!/bin/bash
function mnt() {
    echo "MOUNTING"
    sudo mount -t proc /proc ${2}proc
    sudo mount -t sysfs /sys ${2}sys
    sudo mount -o bind /dev ${2}dev
    sudo mount -o bind /dev/pts ${2}dev/pts        
    sudo chroot ${2}
}
function umnt(){
    echo "UNMOUNTING"
    sudo umount ${2}proc
    sudo umount ${2}sys
    sudo umount ${2}dev/pts
    sudo umount ${2}dev
}
if ["$1" == "-m" ] && [ -n "$2" ] ;
then
    mnt $1 $2
elif ["$1" == "-u" ] && [ -n "$2" ];
then
    umnt $1 $2
else
    echo ""
    echo "Either 1'st, 2'nd or bothparameters were missing"
    echo ""
    echo "1'st parameter can be one ofthese: -m(mount) OR -u(umount)"
    echo "2'nd parameter is the full pathof rootfs directory(with trailing '/')"
    echo ""
    echo "For example: ch-mount -m/media/sdcard/"
    echo ""
    echo 1st parameter : ${1}
    echo 2nd parameter : ${2}
fi

卸载使用sudo bash ch-mount.sh -u ubuntu-rootfs/

方法2:使用arch-chroot

linux发行版archlinux提供了一个自动化chroot的脚本arch-chroot,包含自动配置DNS文件、自动挂载虚拟文件系统等操作,用来维护linux系统非常方便,chroot时无需挂载等操作直接执行:

sudo arch-chroot /mnt/ubuntu

arch-chroot是方法1的封装,除此之外有会对目标系统进行检测并预先配置.

经过上述步骤我们就进入chroot环境了.

更新源并安装需要的软件

修改/mnt/ubuntu/etc/apt/sources.list,修改之前做一个备份.

这里推荐使用中科大的源http://mirrors.ustc.edu.cn/ubuntu-ports/

# 默认注释了源码镜像以提高 apt update 速度,如有需要可自行取消注释
deb https://mirrors.ustc.edu.cn/ubuntu-ports/ focal main restricted universe multiverse
# deb-src https://mirrors.ustc.edu.cn/ubuntu-ports/ focal main restricted universe multiverse
deb https://mirrors.ustc.edu.cn/ubuntu-ports/ focal-updates main restricted universe multiverse
# deb-src https://mirrors.ustc.edu.cn/ubuntu-ports/ focal-updates main restricted universe multiverse
deb https://mirrors.ustc.edu.cn/ubuntu-ports/ focal-backports main restricted universe multiverse
# deb-src https://mirrors.ustc.edu.cn/ubuntu-ports/ focal-backports main restricted universe multiverse
deb https://mirrors.ustc.edu.cn/ubuntu-ports/ focal-security main restricted universe multiverse
# deb-src https://mirrors.ustc.edu.cn/ubuntu-ports/ focal-security main restricted universe multiverse

首先更新资源列表,然后安装必备的软件包,根据自己的需求:

# sudo sudo命令 # ssh ssh的client和server # vim vim编辑器 # net-tools ifconfig,netstat,route,arp等 # ethtool ethtool命令,显示、修改以太网设置 # wireless-tools iwconfig等,显示、修改无线设置 # ifupdown ifup,ifdown等工具 # network-manager Network Manager服务和框架,高级网络管理 # iputils-ping ping和ping6 # rsyslog 系统log服务 # bash-completion bash命令行补全 # htop htop工具,交互式进程查看器

apt-get install\
  sudo \
  ssh \
  vim \
  net-tools \
  ethtool \
  wireless-tools \
  ifupdown \
  network-manager \
  iputils-ping \
  rsyslog \
  bash-completion \
  htop \
  --no-install-recommends

也可通过chroot直接执行某个命令,例如修改root密码,其中/mnt/ubuntu是我们的rootfs目录:

sudo chroot  /mnt/ubuntu  passwd

配置串口调试服务

制作的rootfs里,可能是不包含有串口登陆tty的,需要添加一个/etc/init/ttyPS0.conf文件才能从串口登陆。否则你会在串口看见KERNL的输出信息,但就是等不到登陆提示。

ttyPS0.conf,修改其内容如下:

echo "start on stopped rc or RUNLEVEL=[12345]" > /etc/init/ttyPS0.conf
echo "stop on runlevel [!12345]" >> /etc/init/ttyPS0.conf
echo "respawn" >> /etc/init/ttyPS0.conf
echo "exec /sbin/getty -L 115200 ttyPS0 vt102" >> /etc/init/ttyPS0.conf

准备打包前,清除文件系统中的一些缓存数据

sudo apt-get clean
sudo rm -rf var/cache/*
sudo rm -rf var/lib/apt/lists/*

7. 退出构建Core根文件系统

设置好Core根文件系统后,用exit命令退出chroot。

8. 打包做好的Core根文件系统

sudo tar –czvf ../ubuntu.tar.gz .

在根文件系统上一目录生成ubuntu.tar.gz的文档.

相关推荐

VBA中利用Instr函数(vba int函数)

【分享成果,随喜正能量】每一个在你的生命里出现的人,都有原因,喜欢你的人给了你温暖和勇气,你喜欢的人让你学会了爱和自持,你不喜欢的人教会你宽容与尊重,不喜欢你的人让你自省与成长。。...

Insta360 Link体验:支持4K画质,一款使用场景丰富的AI云台摄像头

记者|王公逸伴随直播、线上会议需求的兴起,网络直播的需求愈发增大,8月2日,影石Insta360正式推出全新产品:Insta360Link,这是一款AI智能云台摄像头。从产品形态来说,Insta3...

VBA技术资料MF299:利用Instr进行文本查找

我给VBA的定义:VBA是个人小型自动化处理的有效工具。利用好了,可以大大提高自己的工作效率,而且可以提高数据的准确度。“VBA语言専攻”提供的教程一共九套,分为初级、中级、高级三大部分,教程是对VB...

Fabric.js 拖放元素进画布 - 掘金

本文简介点赞+关注+收藏=学会了学习Fabric.js,我的建议是看文档不如看demo。本文实现的功能:将元素拖进到画布中并生成对应的图形或图片。效果如下图所示:...

Vue3为什么推荐使用ref而不是reactive

为什么推荐使用ref而不是reactivereactive本身具有很大局限性导致使用过程需要额外注意,如果忽视这些问题将对开发造成不小的麻烦;ref更像是vue2时代optionapi的data的替...

Fabric.js 样式不更新怎么办?(js更改样式)

本文简介带尬猴,我嗨德育处主任不知道你有没有遇到过在使用Fabric.js时无意中一些骚操作修改了元素的样式,但刷新画布却没更新元素样式?如果你也遇到同样的问题的话,可以尝试使用本文的方法。...

Fabric.js 修改画布交互方式到底有什么用?

本文简介点赞+关注+收藏=学会了fabric.js为我们提供了很多厉害的方法。今天要搞明白的一个东西是canvas.interactive。官方文档对canvas.interact...

Rust Web编程:第五章 在浏览器上显示内容

我们现在正处于可以构建一个Web应用程序的阶段,该应用程序可以使用不同的方法和数据管理一系列HTTP请求。这很有用,特别是当我们为微服务构建服务器时。然而,我们也希望非程序员能够与我们的应...

Fabric.js 自由绘制椭圆 - 掘金(canvas画椭圆)

本文简介点赞+关注+收藏=学会了本文讲解在Fabric.js中如何自由绘制椭圆形,如果你还不了解Fabric.js,可以查阅《Fabric.js从入门到精通》。效果如下图所示...

手把手教你实现JS手搓&quot;防抖&quot;优化代码——专业的事用专业的方法!

前言在我们前端编程中,假如我们要给后端发送请求,万一手抖多点了几次,多发送了几遍怎么办?解决方案:防抖!这种事就要交给我们专业的“防抖”先生来处理!今天,我们就来教大家手搓“防抖”...

详解虚拟DOM与Diff算法(虚拟dom一定比实际dom快吗)

vue的虚拟DOM,Diff算法,其中一些关键的地方从别处搬运了一些图进行说明(感谢制图的大佬),也包含比较详细的源码解读。...

走进 React Fiber 的世界(我走进你的世界手势舞视频)

文/阿里淘系F(x)Team-冷卉Fiber设计思想Fiber是对React核心算法的重构,facebook团队使用两年多的时间去重构React的核心算法,在React16以上...

前端新一代框架 Svelte 火了!十个场景带你简单认识它!

近几年听到的主流框架都是Vue、React、Angular,但其实有一个框架在国外非常火,用起来也是很方便,那就是...

借助DeepSeek实现了一个PDF阅读器

1、简介使用pdf.js库加载和显示PDF文件。实现了翻页、缩放功能。提供了基本的错误处理。功能特点:支持选择本地PDF文件。可以逐页查看PDF内容。支持放大缩小功能。界面简洁,易于使...

DeepSeek代码之旅1:卫星地图标记方法之——html语言的实现

最近遇到一个任务,具体功能如下:1、调用高德地图API,图层为卫星图层,根据需要标记兴趣点;2、标记完成后可以保存兴趣点,便于下次加载历史兴趣点。...

取消回复欢迎 发表评论: