[英]Sorting ARM Assembly
我是新手。 我在理解内存ARM内存映射时遇到困难。
我找到了简单排序算法的示例
AREA ARM, CODE, READONLY
CODE32
PRESERVE8
EXPORT __sortc
; r0 = &arr[0]
; r1 = length
__sortc
stmfd sp!, {r2-r9, lr}
mov r4, r1 ; inner loop counter
mov r3, r4
sub r1, r1, #1
mov r9, r1 ; outer loop counter
outer_loop
mov r5, r0
mov r4, r3
inner_loop
ldr r6, [r5], #4
ldr r7, [r5]
cmp r7, r6
; swap without swp
strls r6, [r5]
strls r7, [r5, #-4]
subs r4, r4, #1
bne inner_loop
subs r9, r9, #1
bne outer_loop
ldmfd sp!, {r2-r9, pc}^
END
并且此汇编程序应从C代码中以这种方式调用
#define MAX_ELEMENTS 10
extern void __sortc(int *, int);
int main()
{
int arr[MAX_ELEMENTS] = {5, 4, 1, 3, 2, 12, 55, 64, 77, 10};
__sortc(arr, MAX_ELEMENTS);
return 0;
}
据我了解,此代码在堆栈上创建整数数组,并调用在汇编中实现的_sortc
函数。 此函数从堆栈中获取此值并对其进行排序,然后放回堆栈中。 我对吗 ?
我想知道如何仅使用汇编来实现此示例。
例如定义整数数组
DCD 3, 7, 2, 8, 5, 7, 2, 6
BTW DCD声明的变量存储在内存中的位置?
如何以这种方式声明的值进行运算? 请说明如何仅使用原始数据就不使用任何C代码,甚至不使用堆栈就可以使用汇编来实现此目的。
我正在为ARM7TDMI
体系结构编写
AREA ARM, CODE, READONLY
这标志着源代码部分的开始。
使用类似的AREA myData, DATA, READWRITE
您可以在开始部分的地方开始定义data1 DCD 1,2,3
类的数据,这将编译为三个单词,连续字节中包含值1,2,3,标签data1
指向第一个单词的第一个字节。 (一些来自Google的AREA文档)。
加载可执行文件后,这些文件将在物理内存中的位置取决于链接可执行文件的方式(链接器正在使用脚本文件来帮助他确定将哪个区域放置在何处,以及如何创建符号表以由可执行文件加载器进行动态重定位,通过编辑链接描述文件,您可以调整代码和数据的放置位置,但通常不需要这样做。
此外,链接器脚本和汇编器指令也会影响可用堆栈的大小以及它在物理内存中的映射位置。
因此,对于您的特定平台:谷歌用于Web上的内存映射,并检查链接描述文件(开始时只需使用链接器选项来生成.map文件,以查看将代码和数据定位在何处)。
因此,您可以在某个数据区域中声明该数组,然后使用该数组,将符号data1
加载到寄存器中(“加载data1的地址”),然后使用该数组从该地址中获取内存内容。
或者,您可以先将所有数字放入堆栈中(可能由可执行文件的OS加载程序将其设置为合理的值),然后使用堆栈指针在代码中进行操作以访问其中的数字。
您甚至可以将一些值DCD
到CODE
区域,因此这些字将在可执行加载程序映射为只读的内存指令之间结束。 您可以读取这些数据,但是写入它们可能会导致崩溃。 当然,您不应该偶然地将它们作为指令执行(忘记在DCD
之前放置一些ret / jump指令)。
没有堆栈
好吧,这很棘手,您必须小心不要使用任何呼叫/等。 并禁用中断等。基本上任何需要堆栈的东西。
当人们编写引导加载程序代码时,通常他们会在前几条指令中尽快设置一些临时堆栈,因此他们可以在基本设置整个环境或加载操作系统之前使用基本的堆栈功能。 临时堆栈的空间通常在代码中/之后保留,或者根据重置后定义的机器状态保留未使用的内存空间。
如果您精疲力尽,没有操作系统,通常所有内存在重置后都是可写的,因此您可以根据需要混合代码和数据(只是在数据周围跳跃,而不是偶然地执行它们),而无需使用AREA定义。
但是,无论您是要在某些OS的用户空间中创建应用程序(因此,如堆栈和数据区之类的定义都很好并且可以方便地使用它们),还是要创建必须用于自行设置所有内容(更困难,因此我建议首先进入某些OS的用户领域,使用clib初始化C包装器也很方便,因此您可以从ASM调用printf
东西以方便输出)。
如何使用以这种方式声明的值进行操作
在机器码中,值的声明方式无关紧要。 重要的是,如果您有内存的地址,并且知道结构,那么如何将数据存储在那里。 然后,您可以使用所需的任何说明,以所需的任何方式与他们合作。 因此,该asm示例的主体不会发生变化,如果您在ASM中分配数据,您将像C一样将指针作为参数传递给它。
编辑:一些未经测试而盲目完成的示例,可能需要进一步修复语法才能适用于OP(或者甚至可能存在一些错误,并且根本无法使用,如果可以,请在评论中告诉我):
AREA myData, DATA, READWRITE
SortArray
DCD 5, 4, 1, 3, 2, 12, 55, 64, 77, 10
SortArrayEnd
AREA ARM, CODE, READONLY
CODE32
PRESERVE8
EXPORT __sortasmarray
__sortasmarray
; if "add r0, pc, #SortArray" fails (code too far in memory from array)
; then this looks like some heavy weight way of loading any address
; ldr r0, =SortArray
; ldr r1, =SortArrayEnd
add r0, pc, #SortArray ; address of array
; calculate array size from address of end
; (as I couldn't find now example of thing like "equ $-SortArray")
add r1, pc, #SortArrayEnd
sub r1, r1, r0
mov r1, r1, lsr #2
; do a direct jump instead of "bl", so __sortc returning
; to lr will actually return to called of this
b __sortc
; ... rest of your __sortc assembly without change
您可以通过C代码将其调用为:
extern void __sortasmarray();
int main()
{
__sortasmarray();
return 0;
}
除其他外,我还使用了这种介绍性的ARM汇编语言来刷新我的ARM asm内存,但我仍然担心这可能无法正常工作。
如您所见,我没有更改__sortc
任何 __sortc
。 因为访问堆栈内存或“ dcd”内存没有区别,所以它是同一台计算机内存。 获得特定单词的地址后,您就可以使用该地址ldr / str它的值。 __sortc
接收数组中第一个单词的地址以在两种情况下进行排序,从那里开始只是用于存储它,而没有任何上下文说明如何在源中定义,分配,初始化存储等。只要它是可写的,就可以__sortc。
因此,我唯一与“ dcd”相关的事情是加载数组地址,并且快速搜索ARM示例表明它可以通过几种方式来完成,这种add rX, pc, #label
方式是最佳的,但仅适用于+- 4K范围? 还有伪指令ADR rX, #label
做同样的事情,在范围问题的情况下可能会切换到其他指令? 对于任何范围,它看起来都像ldr rX, = label
形式,尽管我不确定它是伪指令还是它是如何工作的,请查看一些教程并反汇编机器代码以查看其编译方式。
学习所有ARM程序集的特性以及如何加载数组的地址取决于您,我目前不需要ARM ASM,因此我没有深入研究这些细节。
并且应该有一些equ
方法来定义数组的长度,而不是从结束地址中的代码中对其进行计算,但是我找不到任何示例,而且我也不会阅读完整的Assembler文档来了解其所有指令(在gas
我认为ArrayLength equ ((.-SortArray)/4)
将起作用)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.