做网站销售好累平台怎样推广
文章目录
- 写在前面
- 关键知识
- 简单加减乘除
- 函数调用和循环
- 系统调用
- 栈的使用
- 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