当前位置: 首页 > article >正文

macOS 下的 ARM 裸机嵌入式开发入门- 第二部分:实现第一个裸机应用并且调试

在这里插入图片描述

1、准备二进制运行程序镜像

利用 QEMU 仿真一个完整的系统,并创建最简单的“Hello world!”示例。

QEMU 模拟器支持 VersatilePB 平台,该平台包含一个 ARM926EJ-S 核心,以及其他外设,四个 UART 串行端口;特别是第一个串行端口(UART0)在使用 -nographic 或 “-serial stdio” qemu 选项时充当终端。UART0 被映射的地址:0x101f1000

为了实现简单的“Hello world!”打印,编写test.c 文件如下:

volatile unsigned int * const UART0DR = (unsigned int *)0x101f1000;

void print_uart0(const char *s) {
    while(*s != '\0') { /* 循环直到字符串结束 */
        *UART0DR = (unsigned int)(*s); /* 传输字符 */
        s++; /* 下一个字符 */
    }
}

void c_entry() {
    print_uart0("Hello world!\n");
}

代码非常简单;一些细节:

  • volatile 关键字是必要的,以指示编译器 UART0DR 指向的内存可以独立于程序改变或产生影响。 unsigned int类型强制执行 32 位读写访问。

  • QEMU 模型的 PL011 串行端口忽略了传输 FIFO 功能;在实际的系统芯片中,必须在
    UARTFR 寄存器中检查“传输 FIFO 满”标志,然后才在 UARTDR 寄存器上写入。

  • -kernel 选项将二进制文件(通常是 Linux 内核)加载到系统内存中,从地址0x00010000 开始。模拟器从地址 0x00000000 开始执行,其中一些指令(已经就位)用于跳转到内核映像的开头。ARM核心的中断表通常位于地址 0x00000000。

startup.s 汇编器文件内容如下:

.global _Reset
_Reset:
    LDR sp, =stack_top
    BL c_entry
    B .

链接器脚本 test.ld:

ENTRY(_Reset)
SECTIONS
{
    . = 0x10000;
    .startup . : { startup.o(.text) }
    .text : { *(.text) }
    .data : { *(.data) }
    .bss : { *(.bss COMMON) }
    . = ALIGN(8);
    . = . + 0x1000; /* 4kB 的堆栈内存 */
    stack_top = .;
}

运行的命令,生成相应的elf和bin文件:

$ arm-none-eabi-as -mcpu=arm926ej-s -g startup.s -o startup.o
$ arm-none-eabi-gcc -c -mcpu=arm926ej-s -g test.c -o test.o
$ arm-none-eabi-ld -T test.ld test.o startup.o -o test.elf
$ arm-none-eabi-objcopy -O binary test.elf test.bin

2、执行和调试二进制文件

在模拟器中运行程序,命令是:

$ qemu-system-arm -M versatilepb -m 128M -nographic -kernel test.bin

-M 选项指定了被模拟的系统。程序在终端打印 “Hello world!” 并无限期运行;要退出 QEMU,请按 “Ctrl + a” 然后按 “x”。

QEMU 实现了一个使用 TCP 连接的 gdb 连接器。按照以下方式运行模拟器:

$ qemu-system-arm -M versatilepb -m 128M -nographic -s -S -kernel test.bin

此命令在执行任何客户代码之前冻结系统,并在 TCP 端口 1234 上等待连接。从另一个终端,我运行 arm-none-eabi-gdb 并输入命令:

target remote localhost:1234
file test.elf

这连接到 QEMU 系统并加载测试程序的调试符号,其二进制图像已经加载在系统内存中。从那里,可以使用 continue 命令运行程序,单步执行程序并进行一般调试。gdb 中的 exit 命令关闭了调试器和模拟器。
编译和运行命令的参考结果见下图,左边是编译和执行的情况,右边是用arm-none-eabi-gdb工具调试的情况:
在这里插入图片描述


http://www.kler.cn/a/389723.html

相关文章:

  • spring中r类是什么
  • 给查询业务添加redis缓存和缓存更新策略
  • uniapp打包华为,提示请提供64位版本软件包后再提交审核
  • 扫雷游戏代码分享(c基础)
  • Qwen2 系列大型语言模型
  • 【循环神经网络】
  • 深入提升Python编程能力的全方位指南
  • mac 安装指定的node和npm版本
  • 中间件安全
  • 大数据新视界 -- 大数据大厂之 Impala 性能优化:数据加载策略如何决定分析速度(上)(15/30)
  • 机器学习(基础1)
  • 基于springboot+小程序的鲜花管理系统(鲜花1)
  • 小马识途营销顾问谈百科词条建立的注意事项
  • 网络安全:构建坚固的数字堡垒
  • 【C++ 算法进阶】算法提升十三
  • HCIP小型园区网拓扑实验
  • Java基础Day-Seventeen
  • 【算法一周目】双指针(1)
  • Android Auto 不再用于旧手机
  • HTML5:网页开发的新纪元
  • 埃隆·马斯克的 AI 初创公司 xAI 推出了 API
  • 链式结构二叉树
  • css 实现展开合并按钮
  • 【JavaScript】JavaScript开篇基础(5)
  • 每日一题|3258. 统计满足 K 约束的子字符串数量 I|滑动窗口
  • 手写JDK动态代理实现AOP