首先,我们看看GCD(Greatest Common Divisor)的CPP实现
int gcd(int a, int b)
{
if(b == 0) return a;
return gcd(b, a%b);
}
基于下面的gcd.s文件,我们尝试实现gcd函数
//gcd.s
.global main
.extern fopen, fprintf, fclose, printf, atoi
.section .data
filename: .asciz "nums.txt"
write_mode: .asciz "w"
format_str: .asciz "%d\n"
.section .text
print_num_to_file:
push {lr}
push {r0-r5}
mov r5, r0
// Open the file for writing
ldr r0, =filename
ldr r1, =write_mode
bl fopen
mov r4, r0 // Store the file pointer in r4
// Check if fopen succeeded
cmp r4, #0
beq close_file
// Write the number to the file
mov r0, r4
ldr r1, =format_str
mov r2, r5
bl fprintf
// Close the file
close_file:
mov r0, r4
bl fclose
pop {r0-r5}
pop {pc}
gcd:
push {lr}
// Replace this with your code! Return value goes in r0
mov r0, #-1
end_gcd:
pop {pc}
main:
push {r4-r7, lr}
// Check if argument count (argc) is correct
cmp r0, #3 // Expecting 3 arguments (program name and two operands)
blt exit
// Convert argument strings to integers
push {r1}
ldr r0, [r1, #4] // Load address of second argument (first operand)
bl atoi // Convert string to integer
mov r4, r0
pop {r1}
push {r4}
ldr r0, [r1, #8] // Load address of third argument (second operand)
bl atoi // Convert string to integer
mov r5, r0
pop {r4}
// Calculate the gcd of both operands
mov r0, r4
mov r1, r5
bl gcd
// Print gcd result to our file
bl print_num_to_file
exit:
// Exit
mov r0, #0
pop {r4-r7, pc}
接下来,我们尝试实现gcd函数
gcd:
push {lr}
// Base case
// if (b == 0) return a
cmp r1, #0
beq end_gcd
// Recursive case
// return gcd(b, a % b)
// Compute a % b
sdiv r2, r0, r1
mul r3, r2, r1
sub r4, r0, r3 // r4 now contains the modulus
// Now compute gcd(b, a % b)
mov r0, r1
mov r1, r4
bl gcd
基于gcd.s,我们可以看到,gcd函数的两个参数可以分别被传入到r0,r1寄存器中,然后,我们可以基于此实现base case,也就是上述代码中 b == 0的情况。
gcd:
push {lr}
// Base case
// if (b ==0) {returan a;}
cmp r1, #0
beq end_gcd
// Recursice case
值得注意的是,ARM汇编中,不直接支持modulus operation。所以,我们要进行相对复杂的等价转换。
a % b = a - (a / b) * b
int division = a/b;
int product = division * b;
int remainder = a - product;
我们尝试在汇编中实现上述逻辑,没有什么难点,需要注意SDIV用于实现 signed integer division
//Recursice case
//return gcd(b, a%b)
//a%b
// int division = a/b;
// int product = division *b;
// int remainder = a - product;
sdiv r2, r0, r1
mul r3, r2, r1
sub r4, r0, r3
在完成了recursive中参数的计算后,我们需要把它们分别传入r0,r1(现在它们在r1和r4).接下来,利用bl操作执行迭代操作。
mov r0, r1
mov r1, r4
bl gcd
执行
as gcd.s -o gcd.o
gcc --static gcd.o gcd
./gcd
在nums.txt中,我们可以看到