我是新手。我很难理解记忆手臂记忆图。
我找到了简单排序算法的例子。
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架构写作的
发布于 2016-10-31 20:49:59
AREA ARM, CODE, READONLY --这标志着源代码中代码部分的开始。
使用类似的AREA myData, DATA, READWRITE,您可以从可以定义数据(如data1 DCD 1,2,3 )的部分开始,这将编译为三个单词,值1、2、3为连续字节,标签data1指向第一个单词的第一个字节。(一些面积,面积文档来自谷歌)。
加载可执行文件后,这些文件在物理内存中的位置取决于可执行文件的链接方式(链接器使用的脚本文件帮助他决定放置哪个区域,以及如何为可执行加载程序完成的动态重定位创建符号表,通过编辑链接器脚本,您可以调整代码和数据所在的位置,但通常不需要这样做)。
此外,链接器脚本和汇编程序指令可能会影响可用堆栈的大小,以及它在物理内存中的映射位置。
因此,对于您的特定平台: google用于web上的内存映射并检查链接器脚本(首先,只需使用链接器选项生成.map文件,以查看代码和数据指向何处)。
因此,您可以在某个数据区域声明该数组,然后使用它将符号data1加载到寄存器("load address of data1")中,并使用它从该地址获取内存内容。
或者,您可以首先将所有数字放入堆栈(您的可执行文件的OS加载程序可能将其设置为合理的数字),然后使用堆栈指针在代码中操作,以访问其中的数字。
您甚至可以将一些值DCD到CODE区域,因此这些单词将结束在内存中的指令之间,这些指令被可执行加载程序映射为只读。您可以读取这些数据,但是写入这些数据可能会导致崩溃。当然,您不应该意外地将它们作为指令执行(忘记在DCD之前放置一些ret/跳转指令)。
无栈
嗯,这是一个棘手的问题,你必须小心不要使用任何调用/等等,并禁用中断,等等。基本上,任何需要堆栈的东西。
当人们编写引导程序时,通常会在前几条指令中尽快设置一些临时堆栈,这样他们就可以在正确设置整个环境或加载OS之前使用基本的堆栈功能。该临时堆栈的空间通常在代码中/之后的某个位置保留,或者根据重置后的机器状态保留未使用的内存空间。
如果你是金属,没有操作系统,通常所有的内存在重置后都是可写的,所以你可以随意混合代码和数据(只是跳过数据,而不是偶然地执行它们),而不需要使用区域定义。
但是,您应该考虑一下,是在某些OS的用户空间中创建应用程序(因此您有定义良好的堆栈和数据区域,并且您可以为您的方便使用它们),或者您正在创建引导加载程序代码,这些代码必须自行设置(更困难,因此我建议您首先进入某些OS的用户域,使用带有clib初始化的C包装器通常也很方便,这样您就可以从ASM调用诸如printf之类的东西,以获得方便的输出)。
如何对以这种方式声明的值进行操作?
在机器代码中,声明值的方式并不重要。重要的是,如果您有内存的地址,如果您知道结构,数据是如何存储在那里的。然后你可以用任何你想要的方式和他们一起工作,使用你想要的任何指令。所以ASM示例的主体不会改变,如果您在asm中分配数据,您将把指针作为参数传递给它,就像C一样。
编辑:有些示例在没有测试的情况下盲目地完成,可能需要进一步修改语法才能适用于OP (或者甚至有一些bug,它根本不起作用,如果有的话,请在注释中告诉我):
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内存,但我仍然担心这可能不能正常工作。
如您所见,我没有在中更改任何内容。因为访问堆栈内存或"dcd“内存没有区别,所以它是同一台计算机内存。一旦您有了特定单词的地址,您就可以使用该地址获得ldr/str它的值。__sortc接收数组中第一个字的地址,以便在这两种情况下进行排序,从这两种情况下它只是内存,没有任何上下文--在源中如何定义该内存、如何分配、初始化等等。只要它是可写的,对于__sortc来说也是可以的。
因此,我唯一与"dcd“相关的东西是加载数组地址,快速搜索ARM示例表明它可以通过几种方式完成,这种add rX, pc, #label方法是最优的,但是只在+-4k范围内工作吗?也有伪指令ADR rX, #label做同样的事情,或者在发生范围问题时切换到其他的?对于任何范围,它看起来都像是使用了ldr rX, = label表单,尽管我不确定它是伪指令还是它是如何工作的,请检查一些教程并反汇编机器代码以查看它是如何编译的。
这取决于您学习所有ARM程序集的特性和如何加载数组的地址,我现在不需要ARM ASM,所以我没有深入这些细节。
应该有一些equ方法来定义数组的长度,而不是用end地址的代码来计算它,但是我找不到任何例子,我也不会阅读完整的汇编程序文档来了解它的所有指令(在gas中,我认为ArrayLength equ ((.-SortArray)/4)会工作)。
https://stackoverflow.com/questions/40349817
复制相似问题