QEMU用户模式测试AARCH64程序

2024-09-07 18:44

本文主要是介绍QEMU用户模式测试AARCH64程序,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

QEMU的两种模式

QEMU(快速模拟器)是一个开源的机器模拟器和虚拟化器,它能够模拟多种处理器架构,并且可以在不同平台上运行。QEMU 支持两种模式:用户模式和系统模式。

  • 用户模式(User Mode):
    • 用户模式下的 QEMU 仅模拟用户空间的二进制执行环境,不模拟底层硬件。
    • 这种模式下,QEMU 可以运行不同架构编译的二进制程序,而不需要这些程序与宿主机的架构相匹配。
    • 用户模式通常用于测试和运行不同架构的应用程序,或者在不支持特定硬件架构的系统上运行程序。
    • 用户模式不需要硬件虚拟化支持,因为它不模拟硬件。
  • 系统模式(System Mode):
    • 系统模式下的 QEMU 模拟整个计算机系统,包括 CPU、内存、硬盘、网络接口等硬件设备。
    • 这种模式下,QEMU 可以运行完整的操作系统镜像,允许用户安装和运行完整的操作系统。
    • 系统模式需要更多的资源,并且可能需要硬件虚拟化支持,以提高性能和安全性。
    • 系统模式允许用户进行更全面的测试,包括操作系统级别的测试和硬件兼容性测试。
    • 在系统模式下,QEMU 还可以使用不同的后端来提高性能,例如使用 KVM(Kernel-based Virtual Machine)在 Linux 系统上进行硬件辅助虚拟化。KVM 可以将 QEMU 转换为一个全功能的虚拟机监控器,提供接近原生硬件的性能。

要启动 QEMU 并使用用户模式或系统模式,你需要使用不同的命令行参数。例如:

用户模式:qemu-<arch> -cpu <cpu-type> -L <path-to-libraries> <program-to-run>
系统模式:qemu-system-<arch> -m <memory-size> -hda <disk-image>
其中 <arch> 是你想要模拟的架构,比如aarch64,<cpu-type> 是特定的 CPU 类型,<path-to-libraries> 是库文件的路径,<program-to-run> 是你想要运行的程序,<memory-size> 是分配给虚拟机的内存大小,<disk-image> 是虚拟硬盘镜像的路径。

QEMU 是一个非常灵活的工具,可以根据需要进行配置和扩展,以满足不同的模拟和虚拟化需求。

用户模式的安装

简单的执行如下命令就可以安装用户模式:

sudo apt-get update
sudo apt-get install qemu-user qemu-user-static gdb-multiarch build-essential  gcc-aarch64-linux-gnu

用户模式C程序的测试

编写一个简单的C程序:

#include <stdio.h>int main(void) { return printf("Hello AARCH64!\n"); 
}

使用aarch64的编译器进行静态的交叉编译:

aarch64-linux-gnu-gcc -static -o hello64 hello.c

编译后使用file命令确认一下编译产生的事aarch64架构文件。 

developer@ecs-cloud-host-ubuntu-img-make:~$ file hello64 
hello64: ELF 64-bit LSB executable, ARM aarch64, version 1 (GNU/Linux), statically linked, BuildID[sha1]=c6209c6d4f0f2ec56fc1e9fe2443c34009ad60d5, for GNU/Linux 3.7.0, not stripped

如果没有安装QEMU用户模式程序,直接运行该程序会报告错误:

bash: ./hello64: cannot execute binary file: Exec format error

 安装了QEMU用户模式之后,直接运行程序就可以得到正确的输出了。这是因为系统内有qemu-user-static,它支持了其他架构程序的直接运行。

developer@ecs-cloud-host-ubuntu-img-make:~$ ./hello64 
Hello AARCH64!

也可以不使用static编译,比如:

aarch64-linux-gnu-gcc -o hello64dyn hello.c

不过不能直接运行hello64dyn这个程序,会报告错误:

developer@ecs-cloud-host-ubuntu-img-make:~$ ./hello64dyn 
aarch64-binfmt-P: Could not open '/lib/ld-linux-aarch64.so.1': No such file or directory

这是需要使用qemu-user了:

developer@ecs-cloud-host-ubuntu-img-make:~$ qemu-aarch64 -L /usr/aarch64-linux-gnu ./hello64dyn 
Hello AARCH64!

用户模式汇编程序的测试(调用C库)

准备一个简单的汇编程序hello.S

.section .text.global mainmain:
// Call puts and return stp fp, lr, [sp, #0x10]!mov fp, spadr x0, msgbl putsmov w0, wzrldp fp, lr, [sp], #0x10retmsg:.asciz "Hello Again!".align 2

 这个程序里面调用了C语言的puts函数。

前两条指令是所谓的序言,SP 寄存器被调整,以便在可能的中断情况下保存数据,以便使用 puts 函数。

adr 指令将 x0 设置为字符串所在位置的内存地址。

'bl puts' 调用 puts 函数。它是一个 C 库函数,它将文本输出到控制台/终端。或者,可以使用 printf 代替。之所以使用 puts,是因为它对 CPU 来说更快,因为它不能接受所谓的字符串中的格式描述符。此外,puts 函数在控制台上自动加入换行。注意我们没有在 Hello Again 字符串中包含 "\n"。

'mov w0, wzr' 指令是给 CPU 一个零值,它将在退出程序时使用。稍后,CPU 将调用 C/C++ 退出函数来退出程序。每当你编写任何 .S(main:)类型的源文件时,最终的 ret 指令将使 CPU 结束程序并调用 C/C++ 退出函数。在 ret 指令之前,w0 应该总是设置为 0。

最后两条指令是所谓的尾声。基本上是序言的相反。

直接使用下面的语句去编译,C语言的编译器会自动处理汇编代码并进行库链接。

aarch64-linux-gnu-gcc  -o hello hello.S

运行程序的方法和前面类似:

developer@ecs-cloud-host-ubuntu-img-make:~$ qemu-aarch64 -L /usr/aarch64-linux-gnu ./hello
Hello Again!

用户模式汇编程序的测试(调用系统调用)

我们也可以不使用C语言函数,直接使用QEMU模拟的系统调用。这和系统模式所模拟的裸机编程有所不同,系统模式是不提供任何系统调用的,你必须自己写串口输出代码或者使用编译好的BIOS文件。

下面是汇编代码:

.section .text.global _start_start:
// syscall write(int fd, const void *buf, size_t count)mov x0, #1    adr x1, msgmov x2, lenmov w8, #64 /*Syscall number for write for ARM64*/svc #0// syscall exit(int status)mov x0, #0mov w8, #93 /*Syscall number for exit for ARM64*/svc #0msg:.asciz "Hello World!\n"len = . - msg

QEMU 模拟所谓的系统调用。这些系统调用旨在模拟具有内置基本任务功能的计算机 BIOS。可以在程序中使用 svc 指令调用。在真正的硬件中,svc 指令将进入一个异常处理程序。在这个程序中,有代码(已经由程序早期编写)来处理 svc 的使用。

在 QEMU 中,这是完全不同的。你的程序在异常处理程序中写了什么并不重要。QEMU 将执行 svc 来模拟一个已经编写了某些指令的计算机 BIOS。简而言之,那里的例程在计算机 BIOS 中是通用的。因此,该例程接受某些参数以产生结果。你可以看出这是情况,因为在上述文件中,我们没有编写任何指令到任何异常处理程序。模拟系统调用的不好之处在于我们不能实际看到和调试 svc 异常。好的是,我们可以使用这些模拟器系统调用来执行基本任务。比如打印文本到控制台(终端),修改文件等。

系统调用 Write 会在控制台(终端)上打印消息。系统调用 Exit 退出程序。

有许多系统调用,每个系统调用都需要参数。在系统调用被“调用”(通过 svc 指令)之前,必须将正确的值放在正确的寄存器中。这种将正确的参数放在正确的寄存器中的概念被称为 ARM64 的调用约定。

代码中一些变量的解释:

  • adr 设置 msg 标签所在位置的内存地址。
  • msg: 是源文件中 Hello World 字符串所在的标签。字符串中的 "\n" 部分是你在控制台/终端输入新行时需要输入的。
  • len = . - msg 这是用于计算字符串大小的汇编器指令。点(.)在这里代表这里。所以 '这里' 减去 msg 将设置字符串的字节量。

要运行程序,需要将其汇编成一个目标文件。然后使用链接器制作一个可执行文件。这可以通过以下两个终端命令完成..

aarch64-linux-gnu-as  hello_world.s -o hello_world.o 
aarch64-linux-gnu-ld hello_world.o -o hello_world

所以我们现在有一个可执行文件。我们可以用 QEMU 启动它:

qemu-aarch64 ./hello_world

得到如下输出:

developer@ecs-cloud-host-ubuntu-img-make:~$ qemu-aarch64 ./hello_world
Hello World!

因为安装了qemu-user-static,直接运行程序也是可以的。 

参考文献

  • Assembler, QEMU, GDB
  • Running Arm Binaries on x86 with QEMU-User | Azeria Labs

这篇关于QEMU用户模式测试AARCH64程序的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1145849

相关文章

性能测试介绍

性能测试是一种测试方法,旨在评估系统、应用程序或组件在现实场景中的性能表现和可靠性。它通常用于衡量系统在不同负载条件下的响应时间、吞吐量、资源利用率、稳定性和可扩展性等关键指标。 为什么要进行性能测试 通过性能测试,可以确定系统是否能够满足预期的性能要求,找出性能瓶颈和潜在的问题,并进行优化和调整。 发现性能瓶颈:性能测试可以帮助发现系统的性能瓶颈,即系统在高负载或高并发情况下可能出现的问题

字节面试 | 如何测试RocketMQ、RocketMQ?

字节面试:RocketMQ是怎么测试的呢? 答: 首先保证消息的消费正确、设计逆向用例,在验证消息内容为空等情况时的消费正确性; 推送大批量MQ,通过Admin控制台查看MQ消费的情况,是否出现消费假死、TPS是否正常等等问题。(上述都是临场发挥,但是RocketMQ真正的测试点,还真的需要探讨) 01 先了解RocketMQ 作为测试也是要简单了解RocketMQ。简单来说,就是一个分

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听

在JS中的设计模式的单例模式、策略模式、代理模式、原型模式浅讲

1. 单例模式(Singleton Pattern) 确保一个类只有一个实例,并提供一个全局访问点。 示例代码: class Singleton {constructor() {if (Singleton.instance) {return Singleton.instance;}Singleton.instance = this;this.data = [];}addData(value)

【测试】输入正确用户名和密码,点击登录没有响应的可能性原因

目录 一、前端问题 1. 界面交互问题 2. 输入数据校验问题 二、网络问题 1. 网络连接中断 2. 代理设置问题 三、后端问题 1. 服务器故障 2. 数据库问题 3. 权限问题: 四、其他问题 1. 缓存问题 2. 第三方服务问题 3. 配置问题 一、前端问题 1. 界面交互问题 登录按钮的点击事件未正确绑定,导致点击后无法触发登录操作。 页面可能存在

业务中14个需要进行A/B测试的时刻[信息图]

在本指南中,我们将全面了解有关 A/B测试 的所有内容。 我们将介绍不同类型的A/B测试,如何有效地规划和启动测试,如何评估测试是否成功,您应该关注哪些指标,多年来我们发现的常见错误等等。 什么是A/B测试? A/B测试(有时称为“分割测试”)是一种实验类型,其中您创建两种或多种内容变体——如登录页面、电子邮件或广告——并将它们显示给不同的受众群体,以查看哪一种效果最好。 本质上,A/B测

EMLOG程序单页友链和标签增加美化

单页友联效果图: 标签页面效果图: 源码介绍 EMLOG单页友情链接和TAG标签,友链单页文件代码main{width: 58%;是设置宽度 自己把设置成与您的网站宽度一样,如果自适应就填写100%,TAG文件不用修改 安装方法:把Links.php和tag.php上传到网站根目录即可,访问 域名/Links.php、域名/tag.php 所有模板适用,代码就不粘贴出来,已经打

跨系统环境下LabVIEW程序稳定运行

在LabVIEW开发中,不同电脑的配置和操作系统(如Win11与Win7)可能对程序的稳定运行产生影响。为了确保程序在不同平台上都能正常且稳定运行,需要从兼容性、驱动、以及性能优化等多个方面入手。本文将详细介绍如何在不同系统环境下,使LabVIEW开发的程序保持稳定运行的有效策略。 LabVIEW版本兼容性 LabVIEW各版本对不同操作系统的支持存在差异。因此,在开发程序时,尽量使用

CSP 2023 提高级第一轮 CSP-S 2023初试题 完善程序第二题解析 未完

一、题目阅读 (最大值之和)给定整数序列 a0,⋯,an−1,求该序列所有非空连续子序列的最大值之和。上述参数满足 1≤n≤105 和 1≤ai≤108。 一个序列的非空连续子序列可以用两个下标 ll 和 rr(其中0≤l≤r<n0≤l≤r<n)表示,对应的序列为 al,al+1,⋯,ar​。两个非空连续子序列不同,当且仅当下标不同。 例如,当原序列为 [1,2,1,2] 时,要计算子序列 [

模版方法模式template method

学习笔记,原文链接 https://refactoringguru.cn/design-patterns/template-method 超类中定义了一个算法的框架, 允许子类在不修改结构的情况下重写算法的特定步骤。 上层接口有默认实现的方法和子类需要自己实现的方法