简体   繁体   中英

Sorting ARM Assembly

I am newbie. I have difficulties with understanding memory ARM memory map.

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

#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. 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 ??

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.

I am writing for ARM7TDMI architecture

AREA ARM, CODE, READONLY - this marks start of section for code in the source.

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. (some AREA docs from google).

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).

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.

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.

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. 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 ).


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.

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).


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.


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):

    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:

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.

As you can see, I didn't change any thing in the __sortc . Because there's no difference in accessing stack memory, or "dcd" memory, it's the same computer memory. Once you have the address to particular word, you can ldr/str it's value with that address. 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.

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? There's also pseudo instruction ADR rX, #label doing this same thing, and maybe switching to other in case of range problem? 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.

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.

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).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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