第12部分- Linux ARM彙編 控制指令/冰雹猜想
ARM的彙編控制如下:
- IF、ELSE及ENDIF
- WHILE及WEND
- MACRO及WEND
- MEXIT
32位示例
完成1+2+…+22。
.text
.global main
main:
mov r1, #0 /* r1 ← 0 */
mov r2, #1 /* r2 ← 1 */
loop:
cmp r2, #22 /* compare r2 and 22 */
bgt end /* branch if r2 > 22 to end */
add r1, r1, r2 /* r1 ← r1 + r2 */
add r2, r2, #1 /* r2 ← r2 + 1 */
b loop
end:
mov r0, r1 /* r0 ← r1 */
bx lr
as -g -o loop01.o loop01.s
gcc -o loop01 loop01.o
執行後通過echo $?獲得結果爲253。
修改代碼中的#22爲#100,就可以得到1+2+…+100=5050。
但是不能通過$?來獲得結果,應爲Linux中錯誤碼的返回是8位的,5050超過8位了。
5050的二進制是1001110111010,後面八位是10111010,也就是186,改成#100後,通過echo $?返回的事186,但是通過gdb調試可以去查看r1其真實爲5050。
64位示例
.arch armv8-a
.global _start
.text
_start:
mov x1, #0 /* r1 ← 0 */
mov x2, #1 /* r2 ← 1 */
loop:
cmp x2, #22 /* compare r2 and 22 */
bgt end /* branch if r2 > 22 to end */
add x1, x1, x2 /* r1 ← r1 + r2 */
add x2, x2, #1 /* r2 ← r2 + 1 */
b loop
end:
mov x0, x1 /* r0 ← r1 */
mov x8, 93
svc 0
as -g -o loop64.o loop64.s
ld -o loop64 loop64.o
執行後如下:
echo $?
253
32示例冰雹猜想
Collatz猜想:即一個正整數x,如果是奇數就乘以3再加1,如果是偶數就析出偶數因數2ⁿ,這樣經過若干個次數,最終回到1。
無論N是怎樣一個數字,最終都回到谷底1。準確地說,是無法逃出落入底部的4-2-1循環。
.text
.global main
main:
mov r1, #123 /* r1 ← 123 */
mov r2, #0 /* r2 ← 0 */
loop:
cmp r1, #1 /* compare r1 and 1 */
beq end /* branch to end if r1 == 1 */
and r3, r1, #1 /* r3 ← r1 & 1 */
cmp r3, #0 /* compare r3 and 0 */
bne odd /* branch to odd if r3 != 0 */
even:
mov r1, r1, ASR #1 /* r1 ← (r1 >> 1) */
b end_loop
odd:
add r1, r1, r1, LSL #1 /* r1 ← r1 + (r1 << 1) */
add r1, r1, #1 /* r1 ← r1 + 1 */
end_loop:
add r2, r2, #1 /* r2 ← r2 + 1 */
b loop /* branch to loop */
end:
mov r0, r2
bx lr
as -g -o collatz.o collatz.s
gcc -o collatz collatz.o
執行後如下:
./collatz
echo $?
46
表示經過了46次變化。
入參爲123,經過的步驟爲:
[123, 370, 185, 556, 278, 139, 418, 209, 628, 314, 157, 472, 236, 118, 59, 178, 89, 268, 134, 67, 202, 101, 304, 152, 76, 38, 19, 58, 29, 88, 44, 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1]
C代碼
#include <stdio.h>
#include <stdint.h>
int main ()
{
unsigned long long i,n,x = 0; //i是不斷變高的數
int count = 0;
int max = 0;
n = 123;
i = n;
while(i!=1)
{
if(i %2 == 1) //如果是個奇數
{
i=3*i+1;
}
else if(i %2 == 0) //如果是個偶數
{
i=i/2;
}
count++; //累加轉換次數
}
printf("當前:%llu[變換次數%d]\n",n, count);
return 0;
}
gcc -o collatz-c collatz.c
結果也是46次變化。
64位示例冰雹猜想
.arch armv8-a
.global _start
.text
_start:
mov x1, #123 /* r1 ← 123 */
mov x2, #0 /* r2 ← 0 */
loop:
cmp x1, #1 /* compare r1 and 1 */
beq end /* branch to end if r1 == 1 */
and x3, x1, #1 /* r3 ← r1 & 1 */
cmp x3, #0 /* compare r3 and 0 */
bne odd /* branch to odd if r3 != 0 */
even:
mov x1, x1, ASR #1 /* r1 ← (r1 >> 1) */
b end_loop
odd:
add x1, x1, x1, LSL #1 /* r1 ← r1 + (r1 << 1) */
add x1, x1, #1 /* r1 ← r1 + 1 */
end_loop:
add x2, x2, #1 /* r2 ← r2 + 1 */
b loop /* branch to loop */
end:
mov x0,x2
mov x8, 93
svc 0
as -g -o collatz64.o collatz64.s
ld -o collatz64 collatz64.o
執行後結果如下:
echo $?
46
從這裏我們可以看到32位的ARM彙編切換到64位其實是比較簡單的。需要注意的是寄存器的變化和退出的方式。