ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

RK3506 裸机开发(三):编译、下载、反汇编验证与 U-Boot 命令行实战

RK3506 裸机开发(三):编译、下载、反汇编验证与 U-Boot 命令行实战 上一篇把led_thumb.s写完了这一篇把它真正跑起来。为了避免来回切窗口建议开两个终端终端在哪干什么终端 A本机 Ubuntu编译、生成mw命令、反汇编验货终端 B串口连 RK3506抢 U-Boot、粘贴mw、go执行、看现象所有命令都在本机 Ubuntu 22.04 RK3506 板子上实测通过。说明本文统一写完整命令arm-none-eabi-*。如果你想用变量先在终端 A 里执行CROSSarm-none-eabi-再把arm-none-eabi-gcc换成${CROSS}gcc。一、终端 A编译与生成mw命令终端 A 从头到尾不需要碰串口只负责把.s变成 U-Boot 能吃的mw.txt/batches.txt。1.1 进目录、编译、链接、抽取bashcd ~/linux/1_leds # 1. 汇编.s - .o arm-none-eabi-gcc -mcpucortex-a7 -mthumb -c led_thumb.s -o led_thumb.o # 2. 链接.o - .elf arm-none-eabi-ld -Ttext0x01000000 led_thumb.o -o led_thumb.elf # 3. 抽取.elf - .bin arm-none-eabi-objcopy -O binary led_thumb.elf led_thumb.bin # 4. 量大小 stat -c%s led_thumb.bin本机实测textled_thumb.o 784 B led_thumb.elf 66520 B led_thumb.bin 76 B ← 最终上板的就是这 76 字节1.2 生成 19 条mwbashcd ~/linux/1_leds python3 - EOF LOAD 0x01000000 d open(led_thumb.bin, rb).read() with open(mw.txt, w) as f: for i in range(0, len(d), 4): f.write(mw 0x%08x 0x%08x\n % (LOAD i, int.from_bytes(d[i:i4], little))) print(bytes%d words%d % (len(d), len(d) // 4)) EOF # bytes76 words19检查最后一行必须是0xff940000bashwc -l mw.txt tail -1 mw.txt # 19 mw.txt # mw 0x01000048 0xff9400001.3 生成“分批 回读”版本为什么要分批本板串口是1500000 baud一次性粘贴太长可能丢字符U-Boot 的CONFIG_SYS_CBSIZE1024单行过长会被截断。bashcd ~/linux/1_leds python3 - EOF cmds [l.strip() for l in open(mw.txt) if l.strip()] out [] for i in range(0, len(cmds), 6): grp cmds[i:i6] addr grp[0].split()[1] out.append(; .join(grp) ; md %s %d % (addr, len(grp))) open(batches.txt, w).write(\n.join(out) \n) for l in out: print(l) EOF本机实测输出4 行终端 B 直接粘贴这 4 行textmw 0x01000000 0x480fb5f0; mw 0x01000004 0x3140f44f; mw 0x01000008 0x480e6001; mw 0x0100000c 0x7180f04f; mw 0x01000010 0x480d6001; mw 0x01000014 0x2101f04f; md 0x01000000 6 mw 0x01000018 0xf04f60c1; mw 0x0100001c 0x60412101; mw 0x01000020 0x2101f04f; mw 0x01000024 0xf04f6041; mw 0x01000028 0x3a015200; mw 0x0100002c 0xf04fd1fd; md 0x01000018 6 mw 0x01000030 0x60417180; mw 0x01000034 0x5280f04f; mw 0x01000038 0xd1fd3a01; mw 0x0100003c 0x0000e7f0; mw 0x01000040 0xff950830; mw 0x01000044 0xff9b0800; md 0x01000030 6 mw 0x01000048 0xff940000; md 0x01000048 11.4 反汇编验货可选但强烈建议basharm-none-eabi-objdump -d -M force-thumb led_thumb.elf | head -20只要能看到mov.w、b.n、push、ldr这些 Thumb-2 特征就没问题。bash# 指令集自检 arm-none-eabi-objdump -d -M force-thumb led_thumb.elf \ | grep -qE mov\.w|b\.n|ldr\.w|push \ echo [OK] Thumb-2 || echo [!!] 不是 Thumb # 入口地址末位必须是 1 arm-none-eabi-readelf -h led_thumb.elf | grep -i entry # Entry point address: 0x1000001到这一步终端 A 的活干完了batches.txt已经在~/linux/1_leds里等着往终端 B 粘贴。1.5 用 Makefile 一键打包推荐因为很方便1.5.1 为什么值得写这份 Makefile前面 1.1~1.4 一共敲了 4 组命令textgcc -mcpucortex-a7 -mthumb -c led_thumb.s -o led_thumb.o ld -Ttext0x01000000 led_thumb.o -o led_thumb.elf objcopy -O binary led_thumb.elf led_thumb.bin python3 生成 mw.txt / batches.txt问题不在于命令长而在于每次手敲都容易漏一条。最典型的是漏-mthumb漏了它gcc 按 ARM 指令集汇编得到的 .bin 是 ARM 版104 字节左右U-Boot 的go一样会跳过去板子不报错只是跑飞undefined instruction。这种静默失败最浪费时间。Makefile 的作用就是把这一串命令固定下来想漏也漏不掉同时利用 make 的增量编译——源码没改就一句make什么都不做。1.5.2 Makefile 三条最核心的概念第一条一个规则的结构makefile目标: 依赖 TAB命令读作要得到目标需要依赖只要依赖比目标新就跑下面的命令重新生成它。第二条命令前必须是 TAB不能是空格用空格会报missing separator而且报错信息不会告诉你应该用 TAB新手很容易卡在这儿。第三条#注释要单独占一行写变量赋值时尤其要注意。GNU Make不会去掉行内注释前的空格那些空格会变成变量值的一部分makefileCROSS ? arm-none-eabi- # 工具链前缀这样写$(CROSS)就变成arm-none-eabi- 末尾三个空格拼起来是arm-none-eabi- gcc直接command not found。所以本项目的 Makefile 里所有注释都单独占一行。顺便记三个自动变量写通用规则时用得到变量含义$目标名冒号左边那个$第一个依赖$^所有依赖1.5.3 这份 Makefile 提供了哪些目标放在~/linux/1_leds/Makefile里只服务led_thumb.s一份源码。对外只暴露这几个动作命令干什么产物make默认目标汇编 → 链接 → 抽取led_thumb.binmake dump反汇编 指令集自检led_thumb.dismake bytes以十六进制查看 bin打到屏幕make mw生成 U-Boot 的mw命令mw.txtmake clean删除所有生成物——make help打印帮助——几条使用要点make会自动量大小跑完直接打印led_thumb.bin的字节数省掉一条stat。make dump自带 Thumb-2 自检会调readelf看.ARM.attributes里有没有Tag_THUMB_ISA_use: Thumb-2有就打印✓ Thumb-2。这一步比肉眼看反汇编更可靠。make mw不需要外部脚本早先版本调gen_mw.py脚本丢了就报No such file or directory。现在把 19 行mw.l的生成逻辑内联进 Makefile只依赖python3不再有额外文件。工具链前缀可覆盖CROSS用?定义默认arm-none-eabi-。要临时换一套工具链直接make CROSSarm-linux-gnueabihf-即可不用改文件。链接脚本可替换如果以后不用-Ttext而用自定义.ldsmake LDSCRIPTxxx.lds就行其余规则不动。clean不删源码只清.o / .elf / .bin / .map / .dis / mw.txtled_thumb.s一个字节都不会动。1.5.4 实际怎么用从零到拿到mw.txt三条命令bashcd ~/linux/1_leds make # 编译led_thumb.s - led_thumb.bin make dump # 验货反汇编 Thumb-2 自检 make mw # 生成mw.txt19 条 mw.l跑完make mwmw.txt已经在目录里了bashwc -l mw.txt tail -1 mw.txt # 19 mw.txt # mw 0x01000048 0xff940000最后一次核对末行地址必须是0x01000048值必须是0xff940000。这两项对了说明 76 字节一字不差。改源码之后重跑一遍上面三条即可——make 会自己判断哪些步骤需要重做不用手动clean。1.5.5 和终端 B 的衔接mw.txt直接生成后接下来在终端 Bpicocom 里的 U-Boot有两种贴法直接贴mw.txt每行一条mw19 行贴 19 次分批贴推荐本板串口 1500000 baud一次性粘贴太长可能丢字符U-Boot 的CONFIG_SYS_CBSIZE1024单行过长也会被截断。所以把mw.txt按 6 条一组切成分批文件每批后面跟一条md回读。分批文件的生成可以放在 Makefile 之外一行python3脚本也可以直接手工切——只要保证每行以; md 地址 个数结尾方便粘贴后立刻核对。到这一步终端 A 的活干完了led_thumb.bin和mw.txt都在~/linux/1_leds里等着往终端 B 粘贴。二、终端 B串口、抢 U-Boot、写内存、执行终端 B 只干三件事抢到 U-Boot、把batches.txt贴进去、go。2.1 打开串口先确认设备bashls /dev/ttyACM* /dev/ttyUSB* 2/dev/null # 本机实测/dev/ttyACM0CH343 是 CDC-ACM所以是ttyACM*CH340/CP2102 通常是ttyUSB*。bashsudo picocom -b 1500000 /dev/ttyACM0退出 picocom 是CtrlA然后CtrlX。2.2 抢 U-Boot 命令行关键这块板子的 U-Boot 默认textbootdelay0启动日志长这样textHit key to stop autoboot(CTRLC): 0 ## Booting FIT Image at 0x1d51f1c0 with size 0x004d8c00打印完0就立刻往下走复位后猛敲回车是抢不到的。正确做法在 picocom 里先按住CtrlC不放另一只手按板子上的RESET键等串口出现提示符再松开CtrlC。如果一次没抢到重复上面三步。核心是上电瞬间串口线上必须已经在连续发0x03。抢到之后你会看到text2.3 粘贴batches.txt的 4 行在终端 A 里bashcat ~/linux/1_leds/batches.txt把输出的 4 行依次粘贴到终端 B 的 U-Boot 里。每贴一行U-Boot 会自动执行mw并跟一条md回读。贴完第一行应该看到类似text mw 0x01000000 0x480fb5f0; ... ; md 0x01000000 6 01000000: 480fb5f0 3140f44f 480e6001 7180f04f ...H.O.1..H.O 01000010: 480d6001 2101f04f ..H.O..!逐行核对md打出来的 32 位字必须和你mw写进去的值一一对应。只要有一个不对别往下走重新贴这一行。4 行贴完内存里就是完整的 76 字节。2.4 再整体回读一次保险起见在 U-Boot 里手动再读一遍全段textmd 0x01000000 1919 个字对应 76 字节。对照终端 A 的mw.txt看一遍。2.5go执行textgo 0x01000000U-Boot 会把地址强制| 1变成0x01000001Thumb 入口打印## Starting application at 0x01000000 ...跳过去CPU 交给你的程序。正常现象板上 LED 开始闪烁亮:灭 ≈ 2:1因为0x20000000 : 0x10000000。go之后 U-Boot 命令行不会回来这是正常的——程序最后是b blink死循环。想回 U-Boot 或 Linux按RESET键。2.6 怎么恢复程序只存在于 DDR 里掉电即失情况怎么恢复程序死循环按 RESET或断电重上电程序跑飞 / data abort同上复位后板子正常启动 Linuxflash 里的东西一个字节都没变。实测复位后textLinux ATK-DLRK3506 6.1.118 armv7l boot_mode normal LED trigger [heartbeat]LED 由内核 heartbeat 驱动接管板子回到出厂状态。三、两个终端的配合流程一张图text终端 AUbuntu 终端 Bpicocom / RK3506 ───────────────────────── ───────────────────────── gcc -c led_thumb.s - .o ld -Ttext0x01000000 - .elf objcopy -O binary - .bin (76 B) python3 生成 mw.txt python3 生成 batches.txt picocom -b 1500000 /dev/ttyACM0 按住 CtrlC按 RESET 抢到 cat batches.txt ──── 复制 mw.txt的内容 ────► 逐行粘贴看 md 回读 md 0x01000000 19 整体核对 go 0x01000000 LED 闪烁 ✅四、常见坑速查现象原因处理go后 undefined instruction编译时漏了-mthumb重新编译确认反汇编是 Thumb-2go后跑飞 / data abortmw粘贴丢字符内存值错重新贴batches.txt先md核对md看着对go异常cache 一致性换 U-Boot 版本时可能遇到优先怀疑 cache不是指令集复位后猛敲回车进不去 U-Bootbootdelay0按住CtrlC再按 RESETgo后命令行不回来程序是死循环正常按 RESET链接地址 / 装载地址 /go地址不一致跳转和 PC 相对取数会错三者必须完全相同makefile等代码详见https://github.com/joyful-jogo/rk3506-baremetal/tree/main/1_leds
返回列表