An exploration of ARM assembly language

来源:互联网 发布:淘宝鬼脚七离婚真相 编辑:程序博客网 时间:2024/06/02 10:11
http://www.fourtheye.org/armasm.shtml


Introduction

This documents my investigation into assembly language programming on the ARM processor running my SheevaPlug. This runs Debian GNU/Linux. I use the GNU assembler, gas, the GNU linker, ld and the GNU debugger, gdb.

I referred to GNU-ARM-Assy-Quick-Ref.pdf and More Assembler Directives. The instruction set is defined here

More links are here, here and here

For most of the examples I followed those supplied with the excellent X86 assembly language book,Professional Assembly Language by Richard Blum.

The code is at git@github.com:bobblestiltskin/professional_assembly_language.git if you want to play with it.

Getting Started

  1. Familiarity with gdb is useful.
    • Use b _start to set a break point at the label _start:
    • Use run to run to the break point.
    • s to step through from the break point
    • inspect registers or abbreviate to i r
    • x/4d &data to eXamine 4 decimal items of data

    This explains the basic usage well.

  2. Communicating with Linux
  3. We can invoke a system call to the operating system, which allows us to pass back one parameter, as the exit code of the program.

    .global_start_start:movr0, #42@ the value in r0 is returned as the exit status of the processmovr7, #1@ set r7 to 1 - the syscall for exit@ calls listed in /usr/include/asm/unistd.hswi0@ then invoke the syscall from linux
    bob@poland:~/src/asm$ /usr/bin/as -gstabs -o syscall.o syscall.sbob@poland:~/src/asm$ /usr/bin/ld -o syscall syscall.obob@poland:~/src/asm$ ./syscall bob@poland:~/src/asm$ echo $?42bob@poland:~/src/asm$
  4. The size of an executable
  5. The following 3 programs show the size allocated for uninitialised data.

    # sizetest1.s ? A sample program to view the executable size.section .text.globl _start_start:movr0, #0@ set exit code to 0mov     r7, #1@ set r7 to 1 - the syscall for exitswi     0@ then invoke the syscall from linux
    # sizetest2.s - A sample program to view the executable size.section .bss   .lcomm buffer, 10000.section .text.globl _start_start:        mov     r0, #0          @ set exit code to 0        mov     r7, #1          @ set r7 to 1 - the syscall for exit        swi     0               @ then invoke the syscall from linux
    # sizetest3.s - A sample program to view the executable size.section .databuffer:   .fill 10000.section .text.globl _start_start:        mov     r0, #0          @ set exit code to 0        mov     r7, #1          @ set r7 to 1 - the syscall for exit        swi     0               @ then invoke the syscall from linux
    bob@poland:~/www/examples$make sizetest1 sizetest2 sizetest3/usr/bin/as -gstabs -o sizetest1.o sizetest1.s/usr/bin/ld -o sizetest1 sizetest1.o/usr/bin/as -gstabs -o sizetest2.o sizetest2.s/usr/bin/ld -o sizetest2 sizetest2.o/usr/bin/as -gstabs -o sizetest3.o sizetest3.s/usr/bin/ld -o sizetest3 sizetest3.obob@poland:~/www/examples$ls -l sizetest?-rwxr-xr-x 1 bob bob   938 Jul  3 16:17 sizetest1-rwxr-xr-x 1 bob bob  1072 Jul  3 16:17 sizetest2-rwxr-xr-x 1 bob bob 11072 Jul  3 16:17 sizetest3bob@poland:~/www/examples$
  6. Communicating via C functions
  7. We can call C functions and pass parameters to them.

    .section.rodata.align2string:.asciz "Sum of %d and %d is %d\n".text.align2.globalmain.typemain, %functionmain:stmfdsp!, {lr}@ stash link register on stackldrr0, =string@ store address of start of string to r0movr1, #1@ then each parameter to subsequent registersmovr2, #41movr3, #42blprintf@ call the c function to display informationldmfdsp!, {pc}@ retrieve stashed link register to program countermovr7, #1@ set r7 to 1 - the syscall for exitswi0@ then invoke the syscall from linux
    Note that we change _start to main since we use gcc to assemble and link because we want to link in the C library so that we can access printf.
    bob@poland:~/src/asm$ gcc -o printf printf.sbob@poland:~/src/asm$ ./printf Sum of 1 and 41 is 42bob@poland:~/src/asm$

Moving Data

  1. An example of moving data from memory to a register
  2. I write a makefile to build the software and use rodata (for my read-only data).

    # movtest1.s@ An example of moving data from memory to a register        .global _start.section .rodatavalue: .byte 42        .align 2        .text_start:ldrr1, =valueldrbr0, [r1], #1@ load the byte at address r1 to r0mov     r7, #1@ set r7 to 1 - the syscall for exitswi     0@ then invoke the syscall from linux
    bob@poland:~/www/examples$ make movtest1/usr/bin/as -gstabs -o movtest1.o movtest1.s/usr/bin/ld -o movtest1 movtest1.obob@poland:~/www/examples$ ./movtest1 bob@poland:~/www/examples$ echo $?42bob@poland:~/www/examples$
  3. An example of moving register data to memory
  4. Read a value to r0, and store it to memory. Double the value of r0 then read back to r0. Our return code is the same as that stored rather than the doubled version. By implication, our store and load were executed correctly.

    @ An example of moving register data to memory        .global _start.section .datavalue: .byte 42        .align 2        .text_start:        ldrr1, =valuemovr0, #9        strbr0, [r1], #0@store the byte at address r1 to r0addr0, r0, r0        ldrb    r0, [r1], #0    @ load the byte at address r1 to r0        mov     r7, #1@ set r7 to 1 - the syscall for exit        swi     0                       @ then invoke the syscall from linux
    bob@poland:~/www/examples$ make movtest2/usr/bin/as -gstabs -o movtest2.o movtest2.s/usr/bin/ld -o movtest2 movtest2.obob@poland:~/www/examples$ ./movtest2 bob@poland:~/www/examples$ echo $?9bob@poland:~/www/examples$
  5. An example of using indexed memory locations
  6. The .equ directive is introduced which aliases a value to a name. We do so because we can easily change from using bytes for storage of the value to using half-words (of 2 bytes) or words (of 4 bytes) in the data section and modification of the ldrb instruction to ldrh or ldr respectively.

    Again we use gcc rather than as to assemble since we use the C function, printf.

    # movtest3.s ? Another example of using indexed memory locations.equ datum_size,1.globl main.align 2.section .rodataoutput:.asciz "The value is %d\n"values:.byte 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60endvalues:.align 2.textmain:stmfdsp!, {r4, r5, r6, lr} @ save the registers we usemovr4, #0ldrr5, =endvaluesldrr6, =valuesloop:ldrbr1, [r6], #datum_sizeldrr0, =outputbl printfcmpr6, r5bneloopldmfdsp!, {r4, r5, r6, pc} @ restore registers before exit        mov     r7, #1                  @ set r7 to 1 - the syscall for exit        swi     0                       @ then invoke the syscall from linux
    bob@poland:~/www/examples$ make movtest3/usr/bin/gcc -gstabs -o movtest3 movtest3.sbob@poland:~/www/examples$ ./movtest3The value is 10The value is 15The value is 20The value is 25The value is 30The value is 35The value is 40The value is 45The value is 50The value is 55The value is 60bob@poland:~/www/examples$
  7. An example of indirect addressing
  8. We write a constant to the second element of the vector and then read and return it.

    # movtest4.s ? An example of indirect addressing.equ datum_size,1.globl _start.align 2.section .datavalues:   .byte 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60.text.align 2_start:ldrr4, =valuesmovr5, #100strbr5, [r4, #datum_size]!@ write back the incremented data pointerldrbr0, [r4]@ load that value to r0 for return to OS        mov     r7, #1@ set r7 to 1 - the syscall for exit        swi     0                       @ then invoke the syscall from linux
    bob@poland:~/www/examples$ make movtest4/usr/bin/as -gstabs -o movtest4.o movtest4.s/usr/bin/ld -o movtest4 movtest4.obob@poland:~/www/examples$ ./movtest4 bob@poland:~/www/examples$ echo $?100bob@poland:~/www/examples$
  9. Converting endianness
  10. ARM v6 has a rev instruction to convert big- and little-endian values. A sheevaplug uses ARM v5TE so we have to do the inversion explicitly

    # swaptest.s ? Converting big-endian to little-endian and vice-versa# In Arm V6 we can use the  rev instruction - but not supported here.globl _start.section .datavstart:.word 0x12345678.text.align 2_start:ldrr1, =vstartldrr0, [r1]@ load word to r0andr2, r0, #0xff000000@ load the top 2 bytes to r2andr3, r0, #0x00ff0000@ load the next 2 bytes to r3andr4, r0, #0x0000ff00@ load the next 2 bytes to r4andr5, r0, #0x000000ff@ load the bottom 2 bytes to r5movr0, r2, lsr #24@ shift r2 bytes to bottom and store to r0orrr0, r3, lsr #8@ or the remaining shifted dataorrr0, r4, lsl #8orrr0, r5, lsl #24_stop:mov     r7, #1@ set r7 to 1 - the syscall for exitswi     0@ then invoke the syscall from linux
    bob@poland:~/www/examples$ grep architecture /proc/cpuinfoCPU architecture: 5TEbob@poland:~/www/examples$bob@poland:~/www/examples$ gdb endianGNU gdb (GDB) 7.0.1-debianCopyright (C) 2009 Free Software Foundation, Inc.License GPLv3+: GNU GPL version 3 or later This is free software: you are free to change and redistribute it.There is NO WARRANTY, to the extent permitted by law.  Type "show copying"and "show warranty" for details.This GDB was configured as "arm-linux-gnueabi".For bug reporting instructions, please see:...Reading symbols from /home/bob/www/examples/endian...done.(gdb) b _startBreakpoint 1 at 0x8078: file endian.s, line 10.(gdb) b _stopBreakpoint 2 at 0x80a0: file endian.s, line 21.(gdb) runStarting program: /home/bob/www/examples/endian Breakpoint 1, _start () at endian.s:1111ldrr0, [r1]@ load word to r0Current language:  autoThe current source language is "auto; currently asm".(gdb) x/x &vstart0x100a8 :0x12345678(gdb) contContinuing.Breakpoint 2, _stop () at endian.s:2222swi     0@ then invoke the syscall from linux(gdb) p/x $r0$2 = 0x78563412(gdb) quitA debugging session is active.Inferior 1 [process 17053] will be killed.Quit anyway? (y or n) ybob@poland:~/www/examples$

    So we see the inverted data in r0 when the program stops.

Structured Programs

  1. A subroutine to display a vector of bytes
  2. We abstract the program given above as movtest3.s as follows.

    The subroutine to print is given by

    # this subroutine prints vectors of bytes## inputs#   r0 - start of vector#   r1 - number of elements to print#   r2 - pointer to start of string used to print each element## no outputs#.globl _vprintb.equ datum_size,1.align 2_vprintb:stmfdsp!, {r4, r5, r6, lr}movr4, r0movr5, r1movr6, r2vprintb_loop:ldrbr1, [r4], #datum_sizemovr0, r6bl printfnopsubsr5, r5, #1bnevprintb_loopldmfdsp!, {r4, r5, r6, pc}

    A simple test harness to use the subroutine is given by

    .equ datum_size,1.globl main.align 2.section .rodataoutput:.asciz "The value is %d\n"values:.byte 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60endvalues:.align 2.textnopmain:nopldrr0, =valuesmovr1, #11ldrr2, =outputbl_vprintb        mov     r7, #1                  @ set r7 to 1 - the syscall for exit        swi     0                       @ then invoke the syscall from linux
    bob@poland:~/www/examples$ make test_vprintb/usr/bin/gcc -gstabs -o test_vprintb test_vprintb.s vprintb.sbob@poland:~/www/examples$ ./test_vprintbThe value is 10The value is 15The value is 20The value is 25The value is 30The value is 35The value is 40The value is 45The value is 50The value is 55The value is 60bob@poland:~/www/examples$
  3. A subroutine to display a vector of words
  4. Start to change movtest3.s as follows.

    The subroutine to print is given by

    # this subroutine prints vectors of words## inputs#   r0 - start of vector#   r1 - number of elements to print#   r2 - pointer to start of string used to print first element#   r3 - pointer to start of string used to print subsequent elements## no outputs#.globl _vprintw.equ datum_size,4.align 2_vprintw:stmfdsp!, {r4, r5, r6, r7, lr}@ save registers on the stackcmpr1, #0@ exit if no elementsblelastmovr4, r0@ copy the parameters to localsmovr5, r1movr6, r2movr7, r3ldrr1, [r4], #datum_size@ load first vector element to r0 and bump pointermovr0, r6@ address of first string to r0bl printf@ and print ittnopsubsr5, r5, #1@ decrement counterbeqlast@ and fall out if zerovprintw_loop:ldrr1, [r4], #datum_size@ load next vector item to r0 and bump pointermovr0, r7@ address of subsequent string to r0bl printf@ and print itnopsubsr5, r5, #1@ decrement counterbnevprintw_loop@ and loop if non-zerolast:ldmfdsp!, {r4, r5, r6, r7, pc}@ restore registers from stack and return

    A simple test harness to use the subroutine is given by

    .equ datum_size,4.globl main.align 2.section .rodatafirst:.asciz "Vector of words - values : %d"subsequent:.asciz ", %d"final:.asciz "\n"values:.word 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60endvalues:.align 2.textnopmain:nopldrr0, =valuesmovr1, #11ldrr2, =firstldrr3, =subsequentbl_vprintwldrr0, =finalblprintf        mov     r7, #1                  @ set r7 to 1 - the syscall for exit        swi     0                       @ then invoke the syscall from linux
    bob@poland:~/www/examples$ make test_vprintw/usr/bin/gcc -gstabs -o test_vprintw test_vprintw.s vprintw.sbob@poland:~/www/examples$ ./test_vprintwVector of words - values : 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60bob@poland:~/www/examples$

    A more complex example - a bubble sort

    A bubble sort function

    # this subroutine bubble sorts vectors of words## inputs#   r0 - start of vector#   r1 - number of elements to sort## no outputs## locals#   r4 - current pointer#   r5 - inner counter#   r6 - keep_going flag#   r7 - first element#   r8 - second element.equ datum_size,4.globl _bubble.align 2        .text_bubble:nop        stmfdsp!, {r4, r5, r6, r7, r8, lr}@ save variables to stackcmpr1, #1@ number of elements must be > 1bleend_outer@ stop if nothing to do        subr5, r1, #1@ need n-1 comparisons        movr4, r0@ initialise current pointermovr6, #0@ this register set when we swaploop_start:nopldrr7, [r4], #datum_size@ load one elementldrr8, [r4]@ and next onecmpr7, r8@ compare thembleno_swap@ branch if second greatermovr6, #1@ set keep_going flagsubr4, r4, #datum_size@ reset pointer to first elementswpr8, r8, [r4]@ exchange value in r8 and address in r4strr8, [r4, #datum_size]!@ store new r8 to incremented addressno_swap:nopsubsr5, r5, #1@ decrement counterbneloop_start@ and restart loop if more neededend_inner:nopcmpr6, #0@ check keep_going flagbeqend_outer@ and leave if not setmovr6, #0@ clear keep_going flag movr4, r0@ reset pointer        sub     r5, r1, #1@ reset counterbloop_start@ start another iterationend_outer:nop        ldmfd   sp!, {r4, r5, r6, r7, r8, pc}@ restore state from stack and leave subroutime

    A bubble sort test harness to use the subroutine

    # movtest1.s@ An example of moving data from memory to a register.globl main.equ items,16#.equ items,0#.equ items,1.equ datum_size,4        .align 2.section .rodatabefore:.asciz "Before sorting, values are : %d" after:.asciz "After sorting,  values are : %d"comma:.asciz ", %d"new_line:.asciz "\n"ok:.asciz "ok\n".section .datavalues:.word 105, -7, 235, 61, 28, 315, 456, 63, 134, 97, 221, 53, 1000899, 145, 117, 5evalues:.word 1, 2, 3        .align 2        .textmain:nopldrr0, =valuesmovr1, #itemsldrr2, =beforeldrr3, =commabl_vprintwldrr0, =new_linebl printf@ldrr0, =ok@bl printfldrr0, =valuesmovr1, #itemsbl_bubble@ldrr0, =ok@bl printfldrr0, =valuesmovr1, #itemsldrr2, =afterldrr3, =commabl_vprintwldrr0, =new_linebl printfmov     r7, #1@ set r7 to 1 - the syscall for exitswi     0@ then invoke the syscall from linux
    bob@poland:~/www/examples$ make bubble/usr/bin/gcc -gstabs -o bubble bubble.s bubble_sub.s vprintw.sbob@poland:~/www/examples$ ./bubble Before sorting, values are : 105, -7, 235, 61, 28, 315, 456, 63, 134, 97, 221, 53, 1000899, 145, 117, 5After sorting,  values are : -7, 5, 28, 53, 61, 63, 97, 105, 117, 134, 145, 221, 235, 315, 456, 1000899bob@poland:~/www/examples$
  5. A number of problems from projecteuler.net coded in ARM assembly language
  6. Problems here
<script>window._bd_share_config={"common":{"bdSnsKey":{},"bdText":"","bdMini":"2","bdMiniList":false,"bdPic":"","bdStyle":"0","bdSize":"16"},"share":{}};with(document)0[(getElementsByTagName('head')[0]||body).appendChild(createElement('script')).src='http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion='+~(-new Date()/36e5)];</script>
阅读(1031) | 评论(0) | 转发(0) |
0

上一篇:‘Hello World!’ in ARM assembly

下一篇:A number of problems from coded in ARM assembly language Problems

相关热门文章
  • SHTML是什么_SSI有什么用...
  • shell中字符串操作
  • 卡尔曼滤波的原理说明...
  • 关于java中的“错误:找不到或...
  • shell中的特殊字符
  • linux dhcp peizhi roc
  • 关于Unix文件的软链接
  • 求教这个命令什么意思,我是新...
  • sed -e "/grep/d" 是什么意思...
  • 谁能够帮我解决LINUX 2.6 10...
给主人留下些什么吧!~~
原创粉丝点击