首先要实现的冒泡排序C语言代码如下:
#include <cstdio>
int main()
{
int data1[] = {1, 5, 3, 34, -2, 1, 0};
int size = sizeof(data1) / sizeof(data1[0]);
for(int i = 0; i < size - 1; i++)
{
for(int j = 0; j <size - i - 1; j++)
{
if(data1[j] > data1[j + 1])
{
int temp = data1[j];
data1[j] = data1[j+1];
data1[j+1] = temp;
}
}
}
for(int i = 0; i < size; i++)
printf("%d ",data1[i]);
printf("\r\n");
return 0;
}
在Ubuntu上运行结果:
汇编对应的汇编代码如下:
.equ len, 6 @数组长度减一,对应size - 1
.global _start
_start:
ldr r0, =data1 @r0存储数组首地址
mov r1, #0 @r1存储外层循环的计数值 --- i
mov r2, #0 @r2存储内层循环的计数值 --- j
loopi: @外层循环
mov r3, #len
sub r3, r3, r1 @r3存储内层循环计数上限,对应于size - i - 1
b loopj
next:
add r1, #1
mov r2, #0
cmp r1, #len
bne loopi
b finish
loopj: @内层循环
cmp r2, r3
beq next @满足循环条件才执行内层循环代码,否则继续执行外层循环
add r4, r0, r2, lsl #2 @r4用来存储内层循环数组指针[r4] == data1[r2]
ldr r5, [r4] @r5存储data1[r2]
ldr r6, [r4, #4] @r6存储data1[r2+1]
add r2, #1
cmp r5, r6 @比较R5,R6
blt loopj @R5 > R6则交换数组内对应位置的值,否则不交换继续运行内存循环
str r5, [r4, #4] @交换操作,直接写到存储器内
str r6, [r4]
b loopj
finish:
b _start
.data
data1:
.word 1, 5, 3, 34, -2, 1, 0
汇编代码运行调试环境:CPUlator ARMv7 System Simulator
调试:
红框内就是初始化未经过排序的数组的值,依次为:1, 5, 3, 34, -2, 1, 0
运行完程序后该数组的值依次为:-2 0 1 1 3 5 34 ,程序运行正确
---------------------------------------------------------------------------------------------------------------------------------
反汇编分析:
在线反汇编地址:Compiler Explorer
为了使反汇编程序尽量简单,这里将所有变量定义为全局变量并赋初值,减少出入栈操作,修改后C语言代码如下:
反汇编代码如图:
.LBB0_1段代表外层for循环的条件判断部分,对应:
i < size - 1
.LBB0_3段代表内层for循环的条件判断部分,对应:
j <size - i - 1
这里面有一个MVN R2, R2的操作,就是将R2的值取反,而将一个正数n按位取反就会得到 -(n + 1)的补码,即n = 2时,~n = - 3,这一步其实相当于做了 MOV R2, -(i + 1) @仅为示意代码。我认为这一步非常巧妙,在编写汇编代码时可以好好利用该特性。
.LBB0_4段 执行的是if判断语句
.LBB0_5段执行的则是交换顺序
.LBB0_7段是内存for循环的j++操作
.LBB0_9段是外层for循环的i++操作
剩下的就是一些变量初始化代码。
总体来看,反汇编生成的代码与我编写的汇编代码思路是一致的,并没有太大的差异,让我惊喜的是反汇编代码对于MVN的运用。