简体   繁体   English

排序ARM程序集

[英]Sorting ARM Assembly

I am newbie. 我是新手。 I have difficulties with understanding memory ARM memory map. 我在理解内存ARM内存映射时遇到困难。

I have found example of simple sorting algorithm 我找到了简单排序算法的示例

    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

And this assembly should be called this way from C code 并且此汇编程序应从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;
}

As far as I understand this code creates array of integers on the stack and calls _sortc function which implemented in assembly. 据我了解,此代码在堆栈上创建整数数组,并调用在汇编中实现的_sortc函数。 This function takes this values from the stack and sorts them and put back on the stack. 此函数从堆栈中获取此值并对其进行排序,然后放回堆栈中。 Am I right ? 我对吗 ?

I wonder how can I implement this example using only assembly. 我想知道如何仅使用汇编来实现此示例。

For example defining array of integers 例如定义整数数组

DCD 3, 7, 2, 8, 5, 7, 2, 6

BTW Where DCD declared variables are stored in the memory ?? BTW DCD声明的变量存储在内存中的位置?

How can I operate with values declared in this way ? 如何以这种方式声明的值进行运算? Please explain how can I implement this using assembly only without any C code, even without stack, just with raw data. 请说明如何仅使用原始数据就不使用任何C代码,甚至不使用堆栈就可以使用汇编来实现此目的。

I am writing for ARM7TDMI architecture 我正在为ARM7TDMI体系结构编写

AREA ARM, CODE, READONLY - this marks start of section for code in the source. AREA ARM, CODE, READONLY这标志着源代码部分的开始。

With similar AREA myData, DATA, READWRITE you can start section where it's possible to define data like data1 DCD 1,2,3 , this will compile as three words with values 1, 2, 3 in consecutive bytes, with label data1 pointing to the first byte of first word. 使用类似的AREA myData, DATA, READWRITE您可以在开始部分的地方开始定义data1 DCD 1,2,3类的数据,这将编译为三个单词,连续字节中包含值1,2,3,标签data1指向第一个单词的第一个字节。 (some AREA docs from google). (一些来自Google的AREA文档)。

Where these will land in physical memory after loading executable depends on how the executable is linked (linker is using a script file which is helping him to decide which AREA to put where, and how to create symbol table for dynamic relocation done by the executable loader, by editing the linker script you can adjust where the code and data land, but normally you don't need to do that). 加载可执行文件后,这些文件将在物理内存中的位置取决于链接可执行文件的方式(链接器正在使用脚本文件来帮助他确定将哪个区域放置在何处,以及如何创建符号表以由可执行文件加载器进行动态重定位,通过编辑链接描述文件,您可以调整代码和数据的放置位置,但通常不需要这样做。

Also the linker script and assembler directives can affect size of available stack, and where it is mapped in physical memory. 此外,链接器脚本和汇编器指令也会影响可用堆栈的大小以及它在物理内存中的映射位置。

So for your particular platform: google for memory mappings on web and check the linker script (for start just use linker option to produce .map file to see where the code and data are targeted to land). 因此,对于您的特定平台:谷歌用于Web上的内存映射,并检查链接描述文件(开始时只需使用链接器选项来生成.map文件,以查看将代码和数据定位在何处)。

So you can either declare that array in some data area, then to work with it, you load symbol data1 into register ("load address of data1"), and use that to fetch memory content from that address. 因此,您可以在某个数据区域中声明该数组,然后使用该数组,将符号data1加载到寄存器中(“加载data1的地址”),然后使用该数组从该地址中获取内存内容。

Or you can first put all the numbers into the stack (which is set probably to something reasonable by the OS loader of your executable), and operate in the code with the stack pointer to access the numbers in it. 或者,您可以先将所有数字放入堆栈中(可能由可执行文件的OS加载程序将其设置为合理的值),然后使用堆栈指针在代码中进行操作以访问其中的数字。

You can even DCD some values into CODE area, so those words will end between the instructions in memory mapped as read-only by executable loader. 您甚至可以将一些值DCDCODE区域,因此这些字将在可执行加载程序映射为只读的内存指令之间结束。 You can read those data, but writing to them will likely cause crash. 您可以读取这些数据,但是写入它们可能会导致崩溃。 And of course you shouldn't execute them as instructions by accident (forgetting to put some ret/jump instruction ahead of DCD ). 当然,您不应该偶然地将它们作为指令执行(忘记在DCD之前放置一些ret / jump指令)。


without stack 没有堆栈

Well, this one is tricky, you have to be careful to not use any call/etc. 好吧,这很棘手,您必须小心不要使用任何呼叫/等。 and to have interrupts disabled, etc.. basically any thing what needs stack. 并禁用中断等。基本上任何需要堆栈的东西。

When people code a bootloader, usually they set up some temporary stack ASAP in first few instructions, so they can use basic stack functionality before setting up whole environment properly, or loading OS. 当人们编写引导加载程序代码时,通常他们会在前几条指令中尽快设置一些临时堆栈,因此他们可以在基本设置整个环境或加载操作系统之前使用基本的堆栈功能。 A space for that temporary stack is often reserved somewhere in/after the code, or an unused memory space according to defined machine state after reset. 临时堆栈的空间通常在代码中/之后保留,或者根据重置后定义的机器状态保留未使用的内存空间。

If you are down to the metal, without OS, usually all memory is writeable after reset, so you can then intermix code and data as you wish (just jumping around the data, not executing them by accident), without using AREA definitions. 如果您精疲力尽,没有操作系统,通常所有内存在重置后都是可写的,因此您可以根据需要混合代码和数据(只是在数据周围跳跃,而不是偶然地执行它们),而无需使用AREA定义。

But you should make your mind, whether you are creating application in user space of some OS (so you have things like stack and data areas well defined and you can use them for your convenience), or you are creating boot loader code which has to set it all up for itself (more difficult, so I would suggest at first going into user land of some OS, having C wrapper around with clib initialized is often handy too, so you can call things like printf from ASM for convenient output). 但是,无论您是要在某些OS的用户空间中创建应用程序(因此,如堆栈和数据区之类的定义都很好并且可以方便地使用它们),还是要创建必须用于自行设置所有内容(更困难,因此我建议首先进入某些OS的用户领域,使用clib初始化C包装器也很方便,因此您可以从ASM调用printf东西以方便输出)。


How can I operate with values declared in this way 如何使用以这种方式声明的值进行操作

It doesn't matter in machine code, which way the values were declared. 在机器码中,值的声明方式无关紧要。 All that matters is, if you have address of the memory, and if you know the structure, how the data are stored there. 重要的是,如果您有内存的地址,并且知道结构,那么如何将数据存储在那里。 Then you can work with them in any way you want, using any instruction you want. 然后,您可以使用所需的任何说明,以所需的任何方式与他们合作。 So body of that asm example will not change, if you allocate the data in ASM, you will just pass the pointer as argument to it, like the C does. 因此,该asm示例的主体不会发生变化,如果您在ASM中分配数据,您将像C一样将指针作为参数传递给它。


edit: some example done blindly without testing, may need further syntax fixing to work for OP (or maybe there's even some bug and it will not work at all, let me know in comments if it did): 编辑:一些未经测试而盲目完成的示例,可能需要进一步修复语法才能适用于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    

You can call it from C code as: 您可以通过C代码将其调用为:

extern void __sortasmarray();

int main()
{
    __sortasmarray();
    return 0;
}

I used among others this Introducing ARM assembly language to refresh my ARM asm memory, but I'm still worried this may not work as is. 除其他外,我还使用了这种介绍性的ARM汇编语言来刷新我的ARM asm内存,但我仍然担心这可能无法正常工作。

As you can see, I didn't change any thing in the __sortc . 如您所见,我没有更改__sortc 任何 __sortc Because there's no difference in accessing stack memory, or "dcd" memory, it's the same computer memory. 因为访问堆栈内存或“ dcd”内存没有区别,所以它是同一台计算机内存。 Once you have the address to particular word, you can ldr/str it's value with that address. 获得特定单词的地址后,您就可以使用该地址ldr / str它的值。 The __sortc receives address of first word in array to sort in both cases, from there on it's just memory for it, without any context how that memory was defined in source, allocated, initialized, etc. As long as it's writeable, it's fine for __sortc. __sortc接收数组中第一个单词的地址以在两种情况下进行排序,从那里开始只是用于存储它,而没有任何上下文说明如何在源中定义,分配,初始化存储等。只要它是可写的,就可以__sortc。

So the only "dcd" related thing from me is loading array address, and the quick search for ARM examples shows it may be done in several ways, this add rX, pc, #label way is optimal, but does work only for +-4k range? 因此,我唯一与“ dcd”相关的事情是加载数组地址,并且快速搜索ARM示例表明它可以通过几种方式来完成,这种add rX, pc, #label方式是最佳的,但仅适用于+- 4K范围? There's also pseudo instruction ADR rX, #label doing this same thing, and maybe switching to other in case of range problem? 还有伪指令ADR rX, #label做同样的事情,在范围问题的情况下可能会切换到其他指令? For any range it looks like ldr rX, = label form is used, although I'm not sure if it's pseudo instruction or how it works, check some tutorials and disassembly the machine code to see how it was compiled. 对于任何范围,它看起来都像ldr rX, = label形式,尽管我不确定它是伪指令还是它是如何工作的,请查看一些教程并反汇编机器代码以查看其编译方式。

It's up to you to learn all the ARM assembly peculiarities and how to load addresses of arrays, I don't need ARM ASM at the moment, so I didn't dig into those details. 学习所有ARM程序集的特性以及如何加载数组的地址取决于您,我目前不需要ARM ASM,因此我没有深入研究这些细节。

And there should be some equ way to define length of array, instead of calculating it in code from end address, but I couldn't find any example, and I'm not going to read full Assembler docs to learn about all it's directives (in gas I think ArrayLength equ ((.-SortArray)/4) would work). 并且应该有一些equ方法来定义数组的长度,而不是从结束地址中的代码中对其进行计算,但是我找不到任何示例,而且我也不会阅读完整的Assembler文档来了解其所有指令(在gas我认为ArrayLength equ ((.-SortArray)/4)将起作用)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM