目錄
經典例子:求階乘
一:數組求和
二:數據壓棧退棧
三:函數嵌套調用??
經典例子:求階乘
?知識點:
BGT
?用于判斷?r2 > r0
,確保循環執行?恰好?r0
?次。BNE
?用于判斷?r2 ≠ r0
,會導致循環多執行一次,得到錯誤結果。
這就是階乘代碼中必須使用?BGT
?而非?BNE
?的原因。
AREA Factorial, CODE, READONLYENTRYstartLDR sp, =0x40001000 ; 初始化棧指針MOV r0, #10 ; 設置輸入值為10MOV r1, #1 ; 結果初始化為1MOV r2, #1 ; 循環計數器初始化為1loopCMP r2, r0 ; 比較計數器與輸入值BGT end_loop ; 如果計數器 > 輸入值,結束循環MUL r1, r1, r2 ; 累乘:result *= counterADD r2, r2, #1 ; 計數器加1B loop ; 繼續循環end_loopMOV r0, r1 ; 將結果存入r0
stopB stop ; 程序終止END
一:數組求和
例:編寫一個ARM匯編程序累加一個“數組”的所有元素,碰上0時停止。結果放入 r4。
area test, code, readonly ; 定義代碼段test,屬性為代碼段、只讀entry ; 程序入口標記
startldr r0,=array ; 將array的絕對地址加載到r0(正確寫法應為ldr r0, =array)
loopldr r1,[r0],#4 ; 從r0地址讀取數據到r1,然后r0自增4字節(4字節=字長,適用于32位數據)cmp r1,#0 ; 比較r1是否為0addne r4,r4,r1 ; 若r1≠0,將r1累加到r4(注意:r4未初始化,默認值不確定)bne loop ; 若r1≠0,跳轉回loop繼續遍歷
stopb stop ; 無限循環,程序在此處結束#DCD偽操作數據緩沖池技術#dcd機器碼
arraydcd 0x11 ; 定義數組元素,0x11(十進制17)dcd 0x22 ; 0x22(十進制34)dcd 0 ; 0(數組結束標記)
二:數據壓棧退棧
例:先將棧地址設置為將要壓棧的數據存入寄存器r1-r5中,然后壓棧
AREA first, CODE, READONLYCODE32ENTRYstartLDR sp, =0x40001000 ; 初始化棧指針,指向0x40001000地址; 數據準備:設置寄存器初始值MOV r1, #0x11 ; r1 = 0x11MOV r2, #0x22 ; r2 = 0x22MOV r3, #0x33 ; r3 = 0x33MOV r5, #0x55 ; r5 = 0x55 (修正中文逗號為英文逗號); 壓棧操作:保存寄存器值到棧STMFD sp!, {r1-r3, r5} ; 保存r1-r3和r5到棧,SP自動遞減; 數據清零:驗證后續恢復操作MOV r1, #0 ; 清零r1MOV r2, #0 ; 清零r2MOV r3, #0 ; 清零r3MOV r5, #0 ; 清零r5; 出棧操作:從棧恢復寄存器值LDMFD sp!, {r1-r3, r5} ; 從棧恢復r1-r3和r5,SP自動遞增stopB stop ; 無限循環結束程序END
三:函數嵌套調用??
當有多級函數嵌套,函數返回值我們不可能都存儲在通用寄存器中,必須利用ldm將程序跳轉前的寄存器值以及函數的返回地址壓棧。
AREA test, CODE, READONLYENTRYstartLDR sp, =0x40002000 ; 初始化棧指針MOV r1, #0x11 ; 設置r1 = 0x11MOV r2, #0x22 ; 設置r2 = 0x22MOV r3, #0x33 ; 修正中文逗號為英文逗號MOV r5, #0x55 ; 修正中文逗號為英文逗號BL child_func ; 調用子函數ADD r0, r1, r2 ; 計算r0 = r1 + r2
stopB stop ; 無限循環結束程序; 非葉子函數(調用其他函數的函數)
child_funcSTMFD sp!, {r1-r3, r5, lr} ; 保存寄存器和返回地址到棧MOV r1, #10 ; 修改r1的值BL child_funcl ; 調用子子函數LDMFD sp!, {r1-r3, r5, lr} ; 恢復寄存器和返回地址MOV pc, lr ; 返回主函數; 葉子函數(不調用其他函數的函數)
child_funclSTMFD sp!, {r1-r3, r5} ; 保存寄存器到棧MOV r1, #11 ; 修改r1的值LDMFD sp!, {r1-r3, r5} ; 恢復寄存器MOV pc, lr ; 返回父函數END