ARM汇编[1] 打印格式化字符串(printf
文章目录
- 写在前面
- 关键知识
- 简单加减乘除
- 函数调用和循环
- 系统调用
- 栈的使用
- GDB调试
- 示例代码
写在前面
如果您对ARM汇编还一无所知的话请先参考ARM汇编hello world
本篇不会广泛详细的列举各种指令,仍然只讲解最关键的部分,然后使用他们来完成一个汇编程序
关键知识
简单加减乘除
加
add x0, x1, x2
x0 = x1 + x2
减
sub x0, x1, x2
x0 = x1 - x2
乘
mul x1, x1, x0
x1 = x1 × x0,保存结果的低64位
除
sdiv x0, x1, x2
x0 = x1 / x2,保存结果的商
msub x3, x0, x2, x1
x3=x1-(x0 × x2),计算上述除法指令的余数
函数调用和循环
以下面这段计算字符串长度的程序为例
.datastrr: .string "hello~"strlen:stp x29,x30,[sp, -16]!mov x10, 0 // use x10 as counterstrlen_loop: // compare if cur byte is \0ldrb w9, [x0, x10]cmp w9, 0beq strlen_lendadd x10, x10, 1b strlen_loop // enter next round loopstrlen_lend:mov x0, x10ldp x29,x30,[sp], 16ret _start:ldr x0, =strrbl strlen
(上述代码片段并不完整,仅做说明使用)
x29 帧指针寄存器
x30 下一条指令寄存器
sp 栈指针寄存器
执行前先将x29和x30寄存器保存在sp,sp+7 . sp+8,sp+15的地方,并将sp的值减去一些以用作栈空间保存临时变量
结束的时候再从栈中恢复
x30寄存器保存的是下一条指令的地址,在ret执行的时候要用到
如果只是普通的调用这一个函数那即使不保存也不会出问题,但是如果这个函数内又调用了其他函数,那么这个x30寄存器就会指向错误的地址导致永远陷在这个函数中。(bus error)
函数调用和循环实际上都是跳转类指令
上述代码片段使用了bl、b和beq指令
bl指令:跳转到指定的地址执行下一条指令,并将跳转前的下一条指令地址保存在x30寄存器中,在ret的时候恢复(ret伪指令实际上是bl x30)
b指令:和bl一样但不保存x30,也就是说如果用b指令调用函数那结束的时候跳不回来
beq指令:判断标志位进行跳转的b指令,beq是相等时跳转
子函数调用的时候要记得把x9、x10…这些通用寄存器压栈保存,调用完再恢复
系统调用
ARM汇编hello world
这里已经讲过,本篇不再赘述
栈的使用
暂时没时间写,,看下示例程序吧,都写了注释的,有空的话我补一下
GDB调试
GDB调试在汇编中是必不可少的,学习汇编语言3天比我用c语言写3个月代码出的段错误都多,,
c语言还可以靠printf定位,汇编又没有,,
参考AT&T汇编的GDB调试这一节,用GDB调试的操作都是一样的
示例代码
实现类似c语言中printf函数的功能
用4个子函数实现
strlen:计算字符串长度
numlen:计算数字长度
numtos:将8位长度以内的数字转成ASCII码的字符串格式
prints:实现了能在格式化字符串中拼接打印一个正数的功能
root@arco-arm:/home/arco/as/prints# cat prints.s
.datastrr: .string "ret=%d\n"
.text.global strlen.global numlen.global numtos.global prints.global _start// p1: source string
// ret: length of string
strlen:stp x29,x30,[sp, -16]!mov x10, 0 // use x10 as counterstrlen_loop: // compare if cur byte is \0ldrb w9, [x0, x10]cmp w9, 0beq strlen_lendadd x10, x10, 1b strlen_loop // enter next round loopstrlen_lend:mov x0, x10ldp x29,x30,[sp], 16ret// p1: source number
// p2: 10/16
// ret: length of number
numlen:stp x29,x30,[sp, -16]!mov x12, 0 // use x12 store lengthnumlen_loop:sdiv x9, x0, x1 // use x9 cache quotientmsub x10, x9, x1, x0 // (x10=x0-(x9*x1))use x10 cache remainderadd x11, x9, x10cmp x11, 0beq numlen_lendadd x12, x12, 1 // length+1mov x0, x9 // use quotient as new dividendb numlen_loop // enter next round loopnumlen_lend:mov x0, x12 // copy the value from x12 to x0 as resultldp x29,x30,[sp], 16ret// p1: source number
// p2: 10/16
// ret: string format number
numtos:stp x29,x30,[sp, -32]! // save stack pointerstr x0, [sp, 16] // save origin num in stackbl numlen // call numlenmov x11, x0 // use x11 store num lengthldr x0, [sp, 16] // restore origin num from stackmov x12, 0 // use x12 as counteradd x13, x11, 15 // use x13 cache stack position(sp+16~16+len)numtos_loop:sdiv x9, x0, x1 // (x9=x0/x1)use x9 cache quotientmsub x10, x9, x1, x0 // (x10=x0-(x9*x1))use x10 cache remainderadd x10, x10, 0x30 // add '0'// sp+ :// sp+17:2// sp+16:1strb w10, [sp, x13] // store 1 byte to stack sub x13, x13, 1 // next byte position(from stack high to low, num l2hadd x12, x12, 1 // counter++cmp x11, x12 // judge if calculate overmov x0, x9 // use quotient as dividendbeq numtos_lendb numtos_loopnumtos_lend:ldr x0, [sp, 16] // copy stack value to x0ldp x29,x30,[sp],32 // restore stackret// p1: format string
// p2: target number
prints:stp x29,x30,[sp,-64]!mov x9, 0 // use x9 as counterstr x0, [sp, 16] // save format string addrstr x1, [sp, 24] // save target numberprints_loop:ldr x0, [sp, 16] // restore format string addrldrb w10, [x0, x9] // read 1 bytecmp w10, 0 // judge if overbeq prints_lendcmp w10, 0x25 // judge if %beq prints_valueprints_value_over:// counter point to next char ldr x1, [sp, 16] // restore str addradd x1, x1, x9 // next char addr is origin+offsetmov x0, 1mov x2, 1mov x8, 64svc #0add x9, x9, 1b prints_loopprints_lend:ldp x29,x30,[sp], 64ret
prints_value:add x9, x9, 1 // counter+1, jump %ldrb w10, [x0, x9] // read the byte after %cmp x10, 0x64 // case %dbeq prints_decb prints_value_over // if no matches, jump back and print next char
prints_dec:str x9, [sp, 40] // save x9 (counterldr x0, [sp, 24] // restore target numbermov x1, 10bl numlenmov x2, x0str x2, [sp, 32] // save the length of target numberldr x0, [sp, 24]mov x1, 10bl numtosldr x9, [sp, 40] // restore x9str x0, [sp, 24] // store str format num in sp+24mov x0, 1 // stdoutmov x1, spadd x1, x1, 24 // the address of str format numldr x2, [sp, 32] // out lengthmov x8, 64svc #0add x9, x9, 1 // to next charb prints_value_over_start:ldr x0, =strrmov x1, 123bl prints# exitmov x8, #93// use return of numlen as returnsvc #0相关文章:
ARM汇编[1] 打印格式化字符串(printf
文章目录 写在前面关键知识简单加减乘除函数调用和循环系统调用栈的使用 GDB调试示例代码 写在前面 如果您对ARM汇编还一无所知的话请先参考ARM汇编hello world 本篇不会广泛详细的列举各种指令,仍然只讲解最关键的部分,然后使用他们来完成一个汇编程序…...
Java 集合、迭代器
Java 集合框架主要包括两种类型的容器,一种是集合(Collection),存储一个元素集合,另一种是图(Map),存储键/值对映射。Collection 接口又有 3 种子类型,List、Set 和 Queu…...
在 Docker 中启动 ROS2 里的 rivz2 和 rqt 出现错误的解决方法
1. 出现错误: 运行 ros2 run rivz2 rivz2 ,报错如下 : No protocol specified qt.qpa.xcb: could not connect to display :1 qt.qpa.plugin: Could not load the Qt platform plugin "xcb" in "" even though it was f…...
使用securecrt+xming通过x11访问ubuntu可视化程序
windows使用securecrtxming通过x11访问ubuntu可视化程序 windows机器IP:192.168.9.133 ubuntu-desktop20.04机器IP:192.168.9.190 windows下载xming并安装 按照图修改xming配置 开始->xming->Xlaunch 完成xming会在右下角后台运行 windows在…...
红队打靶练习:HEALTHCARE: 1
目录 信息收集 1、arp 2、nmap 3、nikto 4、whatweb 目录探测 1、gobuster 2、dirsearch WEB web信息收集 gobuster cms sqlmap 爆库 爆表 爆列 爆字段 FTP 提权 信息收集 本地提权 信息收集 1、arp ┌──(root㉿ru)-[~/kali] └─# arp-scan -l Inte…...
Java IO:概念和分类总结
前言 大家好,我是chowley,刚看完Java IO方面内容,特此总结一下。 Java IO Java IO(输入输出)是Java编程中用于处理输入和输出的API。它提供了一套丰富的类和方法,用于读取和写入数据到不同的设备、文件和…...
【Linux】基本命令(下)
目录 head指令 && tail指令 head指令 tail指令 find指令 grep指令 zip/unzip指令 tar指令 时间相关的指令 date显示 1.在显示方面,使用者可以设定欲显示的格式,格式设定为一个加号后接数个标记,其中常用的标记列表如下&…...
腾讯云游戏联机服务器配置价格表,4核16G/8核32G/4核32G/16核64G
2024年更新腾讯云游戏联机服务器配置价格表,可用于搭建幻兽帕鲁、雾锁王国等游戏服务器,游戏服务器配置可选4核16G12M、8核32G22M、4核32G10M、16核64G35M、4核16G14M等配置,可以选择轻量应用服务器和云服务器CVM内存型MA3或标准型SA2实例&am…...
面试经典150题——长度最小的子数组
"In the midst of winter, I found there was, within me, an invincible summer." - Albert Camus 1. 题目描述 2. 题目分析与解析 首先理解题意,题目要求我们找到一个长度最小的 连续子数组 满足他们的和大于target,需要返回的是子数组的…...
业务流程
一、需求分析和设计: 在项目启动阶段,需要与业务人员和产品经理充分沟通,了解业务需求,并根据需求进行系统设计和数据库设计。这一阶段的输出通常是需求文档、系统架构设计、数据库设计等。 1.需求文档 需求文档是一份非常重要…...
ChatGPT Plus如何升级?信用卡付款失败怎么办?如何使用信用卡升级 ChatGPT Plus?
ChatGPT Plus是OpenAI提供的一种高级服务,它相较于标准版本,提供了更快的响应速度、更强大的功能,并且用户可以优先体验到新推出的功能。 尽管许多用户愿意支付 20 美元的月费来订阅 GPT-4,但在实际支付过程中,特别是…...
Spring 如何配置 bean (XML 方式)
请直接看原文:Spring 如何配置 bean (XML 方式)_spring 在哪配置bean 文件-CSDN博客 -------------------------------------------------------------------------------------------------------------------------------- Java Bean 如何配置配置到 spring 容器中 基于 XM…...
揭秘外观模式:简化复杂系统的关键设计策略
前言 外观模式(Facade Pattern)是一种结构型设计模式,它隐藏了系统的复杂性,并向客户端提供了一个可以访问系统的接口。这种类型的设计模式向现有的系统添加一个接口,来隐藏系统的复杂性。这种模式涉及到一个单一的类…...
Nginx 命令(Ubuntu)
常用命令: 1.查看错误日志: sudo vim /var/log/nginx/error.log 2.重新加载 nignx sudo systemctl reload nginx 3.立即停止Nginx服务。如果Nginx正在运行,它将被终止 sudo systemctl stop nginx 4. 禁止Nginx服务在系统重启时自动启…...
从github上拉取项目到pycharm中
有两种方法,方法一较为简单,方法二用到了git bash,推荐方法一 目录 有两种方法,方法一较为简单,方法二用到了git bash,推荐方法一方法一:方法二: 方法一: 在github上复制…...
python从入门到精通(十八):python爬虫的练习案列集合
python爬虫的练习 1.爬取天气网的北京城市历史天气数据1.1 第一种使用面向对象OOP编写爬虫1.2 第二种使用面向过程函数编写爬虫 1.爬取天气网的北京城市历史天气数据 1.1 第一种使用面向对象OOP编写爬虫 import re import requests from bs4 import BeautifulSoup import xlw…...
2.12作业
第一题:段错误。 第二题:hello world 第三题:hello 第四题:world 第五题: a: int a; b: int*a; c: int a0;int *p&a;int **q&p; d: int a[10]; e: int *a[10]; …...
树莓派4B(Raspberry Pi 4B) 使用docker搭建单机版nacos
树莓派4B(Raspberry Pi 4B) 使用docker搭建单机版nacos ⚠️ 由于树莓派上的芯片是ARM架构,而官方推出的docker镜像不适用于ARM架构,所以想用树莓派搭建最新版的Nacos服务的小伙伴们可以忽略我这篇文章了。本文基于nacos 2.0.4&am…...
C++入门学习(二十七)跳转语句—continue语句
当在循环中遇到continue语句时,它会跳过当前迭代剩余的代码块,并立即开始下一次迭代。这意味着continue语句用于跳过循环中特定的执行步骤,而不是完全终止循环。 直接看一下下面的代码更清晰: 与上一节的break语句可以做一下对比…...
JPEG图像格式加速神经网络训练--使用DCT训练CNN
JPEG图像格式加速神经网络训练 JPEG图像格式加速神经网络训练工作原理DCT系数与JPEG直接利用DCT系数阶段 1: 数据准备步骤 1: 读取JPEG文件结构步骤 2: 提取量化表和Huffman表步骤 3: 解析图像数据步骤 4: 反量化步骤 5: 获取DCT系数 阶段 2: 输入处理预处理 1: 正规化…...
eNSP-Cloud(实现本地电脑与eNSP内设备之间通信)
说明: 想象一下,你正在用eNSP搭建一个虚拟的网络世界,里面有虚拟的路由器、交换机、电脑(PC)等等。这些设备都在你的电脑里面“运行”,它们之间可以互相通信,就像一个封闭的小王国。 但是&#…...
Unity3D中Gfx.WaitForPresent优化方案
前言 在Unity中,Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染(即CPU被阻塞),这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案: 对惹,这里有一个游戏开发交流小组&…...
FFmpeg 低延迟同屏方案
引言 在实时互动需求激增的当下,无论是在线教育中的师生同屏演示、远程办公的屏幕共享协作,还是游戏直播的画面实时传输,低延迟同屏已成为保障用户体验的核心指标。FFmpeg 作为一款功能强大的多媒体框架,凭借其灵活的编解码、数据…...
基于Flask实现的医疗保险欺诈识别监测模型
基于Flask实现的医疗保险欺诈识别监测模型 项目截图 项目简介 社会医疗保险是国家通过立法形式强制实施,由雇主和个人按一定比例缴纳保险费,建立社会医疗保险基金,支付雇员医疗费用的一种医疗保险制度, 它是促进社会文明和进步的…...
【算法训练营Day07】字符串part1
文章目录 反转字符串反转字符串II替换数字 反转字符串 题目链接:344. 反转字符串 双指针法,两个指针的元素直接调转即可 class Solution {public void reverseString(char[] s) {int head 0;int end s.length - 1;while(head < end) {char temp …...
Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...
工业自动化时代的精准装配革新:迁移科技3D视觉系统如何重塑机器人定位装配
AI3D视觉的工业赋能者 迁移科技成立于2017年,作为行业领先的3D工业相机及视觉系统供应商,累计完成数亿元融资。其核心技术覆盖硬件设计、算法优化及软件集成,通过稳定、易用、高回报的AI3D视觉系统,为汽车、新能源、金属制造等行…...
SpringCloudGateway 自定义局部过滤器
场景: 将所有请求转化为同一路径请求(方便穿网配置)在请求头内标识原来路径,然后在将请求分发给不同服务 AllToOneGatewayFilterFactory import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; impor…...
鸿蒙DevEco Studio HarmonyOS 5跑酷小游戏实现指南
1. 项目概述 本跑酷小游戏基于鸿蒙HarmonyOS 5开发,使用DevEco Studio作为开发工具,采用Java语言实现,包含角色控制、障碍物生成和分数计算系统。 2. 项目结构 /src/main/java/com/example/runner/├── MainAbilitySlice.java // 主界…...
Hive 存储格式深度解析:从 TextFile 到 ORC,如何选对数据存储方案?
在大数据处理领域,Hive 作为 Hadoop 生态中重要的数据仓库工具,其存储格式的选择直接影响数据存储成本、查询效率和计算资源消耗。面对 TextFile、SequenceFile、Parquet、RCFile、ORC 等多种存储格式,很多开发者常常陷入选择困境。本文将从底…...
