arm assembly snippets


概述

汇编语言是高度平台相关的,在不同的平台上还会有不同的汇编编译器. 汇编语言不是纯机器语言,在汇编语言的代码里主要有编译器处理的伪指令,和能一一映射为机器指令的指令. 不同的编译器有不同的格式,对应arm常见的两种arm官方的armasm(codewarrie)和gnu的GAS(gnu asm). 这两种是不同语句格式,这里主要讨论gnu asm,Android NDK自带了gnu编译器. 路径为:

${NDK installed dir}\toolchains\arm-linux-androideabi-x.x\prebuilt\windows-x86_64\bin\arm-linux-androideabi-as.exe
${NDK installed dir}\toolchains\arm-linux-androideabi-x.x\prebuilt\windows-x86_64\bin\arm-linux-androideabi-ld.exe

在同一目录下还有其他有用的工具.

asm文件的基本语法

label: instruction|directive|pseudo-instruction; comment

label :可选的,在preprocess阶段指示该条指令的地址,用来程序跳转和变量的定义.label需要和:紧挨着中间不能有空格,label:前后可以可以有空格.

instruction:直接对应一个机器指令,如mov add 等

pseudo-instruction: 并不是真实的机器指令,编译器会把这个指令翻译成机器指令,比如 LDR R0,=immediate;编译器会根据立即数的大小转化成不同机器指令,如立即数小于255会转化为mov,否则会转化为LDR不含等号的指令.

directive: 这个是给编译器用的,directive指令都是以.开头的如.section .align等等, 具体介绍

GNU Assembler Syntax

表达式

关于汇编中sectionrelocate相关的介绍

c和汇编实现对比

调用系统函数,以及函数调用约定

  • r0-r3 are the argument and scratch registers; r0-r1 are also the result registers
  • r4-r8 are callee-save registers
  • r9 might be a callee-save register or not (on some variants of AAPCS it is a special register)
  • r10-r11 are callee-save registers
  • r12-r15 are special registers

系统函数调用

系统函数定义位置${NDK installed dir}\platforms\android-21\arch-arm\usr\include\asm\unistd.h

对应函数参数的定义${NDK installed dir}、platforms\android-21\arch-arm\usr\include\unistd.h

系统调用的形式

  /*write hello*/
  mov R7, #4
  mov R0, #1
  ldr R2, =len1
  ldr R1, =string
  svc 0
  
  .section .data
string:
  .ascii "Hello World\n"
len1 = . - string

上面的代码是调用system call write函数打印hello world的代码. 所有的系统调用函数都可以在上面的系统函数定义的文件中找到.

system call

在系统调用中R7表示系统调用的id,比如上面的write函数对应的值为4,read函数对应的值为3.

systemcall中关于write函数的定义为:

ssize_t write(int fd, const void *buf, size_t count);

可见第一个参数为fd,上面的例子中为打印字符串到标准输出,所以第一个参数R0为标准输出的fd 为 1.

第二个参数R1为要输的内存的地址,上面的例子中赋值为字符串的地址.

第三个参数为输出字符的长度R2,上面的例子是通过preporocesor计算得到的,实际就是字符串的长度.

svc为执行系统调用的软中断指令,同(swi).

反汇编查看&pc相关地址计算

E:\code\android\test-ams>arm-linux-androideabi-objdump -d test.o
test.o:     file format elf32-littlearm
Disassembly of section .text:
00000000 <_start>:
   0:   e3a07004        mov     r7, #4
   4:   e3a00001        mov     r0, #1
   8:   e59f2060        ldr     r2, [pc, #96]   ; 70 <_start+0x70>
   c:   e59f1060        ldr     r1, [pc, #96]   ; 74 <_start+0x74>
  10:   ef000000        svc     0x00000000
  14:   e3a07003        mov     r7, #3
  18:   e3a00000        mov     r0, #0
  1c:   e3a02001        mov     r2, #1
  20:   e59f1050        ldr     r1, [pc, #80]   ; 78 <_start+0x78>
  24:   ef000000        svc     0x00000000
  28:   e3a07004        mov     r7, #4
  2c:   e3a00001        mov     r0, #1
  30:   e59f2044        ldr     r2, [pc, #68]   ; 7c <_start+0x7c>
  34:   e59f1044        ldr     r1, [pc, #68]   ; 80 <_start+0x80>
  38:   ef000000        svc     0x00000000
  3c:   e3a07004        mov     r7, #4
  40:   e3a00001        mov     r0, #1
  44:   e3a02001        mov     r2, #1
  48:   e59f1028        ldr     r1, [pc, #40]   ; 78 <_start+0x78>
  4c:   ef000000        svc     0x00000000
  50:   e3a07004        mov     r7, #4
  54:   e3a00001        mov     r0, #1
  58:   e3a02001        mov     r2, #1
  5c:   e59f1020        ldr     r1, [pc, #32]   ; 84 <_start+0x84>
  60:   ef000000        svc     0x00000000
  64:   e3a00000        mov     r0, #0
  68:   e3a07001        mov     r7, #1
  6c:   ef000000        svc     0x00000000
  70:   0000000c        .word   0x0000000c
  74:   00000000        .word   0x00000000
  78:   00000017        .word   0x00000017
  7c:   0000000b        .word   0x0000000b
  80:   0000000c        .word   0x0000000c
  84:   00000018        .word   0x00000018

这里想说的是上面的代码关于pc偏移地址的计算.要在当前的地址基础上加上8才是pc的地址. 以第一个8: e59f2060 ldr r2, [pc, #96] ; 70 <_start+0x70>为例,当前地址为8,pc地址为8+8=0x10,偏移96后的地址为 0x10+0x60(96)=0x70,正好为后面注释里写的地址.

附上一个hello world,同时读入一个字符的代码(没有优化,写的很烂).

.section .text
.global _start
_start:
  /*write hello*/
  mov R7, #4
  mov R0, #1
  ldr R2, =len1
  ldr R1, =string
  svc 0
  
  /*read one byte*/
  mov R7, #3
  mov R0, #0
  mov R2, #1
  ldr R1, =char
  svc 0
  
/* write after read*/
  mov R7, #4
  mov R0, #1
  ldr R2, =len2
  ldr R1, =str2
  svc 0
  
/* write byte*/
  mov R7, #4
  mov R0, #1
  mov R2, #1
  ldr R1, =char
  svc 0
  
  mov R7, #4
  mov R0, #1
  mov R2, #1
  ldr R1, =str3
  svc 0
  
  mov R0, #0
  mov R7, #1
  svc 0
.section .data
string:
  .ascii "Hello World\n"
len1 = . - string
str2:
    .ascii "after read:"
len2 = . - str2
char:
    .byte 0x21
str3:
    .ascii "\n"

附录: Introducing ARM assembly language

The GNU Assembler

Whirlwind Tour of ARM Assembly


Copyright © FengGuangtu 2017