An exploration of ARM assembly language
来源:互联网 发布:淘宝鬼脚七离婚真相 编辑:程序博客网 时间:2024/06/02 10:11
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
- 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
- Communicating with Linux
- The size of an executable
- Communicating via C functions
This explains the basic usage well.
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$
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$
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 linuxNote 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
- An example of moving data from memory to a register
- An example of moving register data to memory
- An example of using indexed memory locations
- An example of indirect addressing
- Converting endianness
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$
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$
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$
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$
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
- A subroutine to display a vector of bytes
- A subroutine to display a vector of words
- A number of problems from projecteuler.net coded in ARM assembly language Problems here
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$
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$
上一篇:‘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...
- An exploration of ARM assembly language
- An Exploration of ARM TrustZone Technology
- arm assembly language
- The Art of Assembly Language
- A number of problems from coded in ARM assembly language Problems
- linux arm programming in assembly language
- ARM Assembly Language Programming (part 1)
- ARM Assembly Language Programming (part 2)
- ARM Assembly Language Programming (part 3)
- ARM Assembly Language Programming (part 4)
- ARM Assembly Language Programming (part 5)
- ARM Assembly Language Programming (part 6)
- ARM Assembly Language Programming (part 7)
- 汇编(The art of assembly language)
- Art of Assembly Language E-Book
- assembly language
- assembly language
- An Empirical Exploration of Recurrent Network Architectures重点
- easy ui 隐藏textbox
- ‘Hello World!’ in ARM assembly
- 虚拟机中PXE-MOF:Exiting intel PXE ROM.Operating system not found
- hibernate 4.3.X遇到的一些问题收集
- [leetcode] 339. Nested List Weight Sum 解题报告
- An exploration of ARM assembly language
- java 抽象方法
- Android自定义View小结篇
- A number of problems from coded in ARM assembly language Problems
- svn
- How much faster is assembly language?
- 从ARMASM汇编到GNU ARM ASM汇编
- 最近在chromium内核上修改完成的“内核离线缓存”功能
- java正则表达式