程序入口: _start
c 语言入口: main

@:              注释;
main:           标签;

伪指令:         给汇编器读的指令;
.global main    导出符号main;

.section .text  申明以下内容存放在代码段;
.section .rodata..................只读段;
.section .data  ..................数据段;
.section .bss   ..................bss段;

.string "hello" 申明后面的内容是带尾0的字符串;
.ascii  "hello" 申明后面的内容是不带尾0的字符串;

.align  2       后面有效内容地址必须的2^2(4)的倍数;
.align  3       ......................2^3(8)......;
       
        .align 
        1) 提高数据的访问效率;
          内存硬件; 32bit一个数据块;
        2) 精简指令集(定长指令集): arm thumb
                arm : 32bit     每条指令长度固定,
                thumb : 16bit/32bit
             1. cpu解析更快;
             2. 指令也更简单;
             3. 更容易学习;
             4. 一个复杂的操作需要多条指令完成;

          复杂指令集(不定长指令集):   x86
                x86 : 每一条指令长度不定;
             1. 一个复杂的操作只是需要一条指令完成;

寄存器:         通用寄存器, 特殊寄存器;
通用寄存器:     位于arm 核内部, r0-r15描述;

ATPCS调用规范:  规定:
                r15 -> pc;
                pc  程序指针;
                r14 -> lr;
                lr  用于保存函数调用返回地址;
                r13 -> sp
                sp  栈指针; 指向栈底部;

                规定:
                r0  作为返回值使用;
               
                规定:
                传参:小于等于4个参数, 分别使用r0 r1 r2 r3;
                      大于4个参数, 大出4 个的参数使用内存栈传递;

指令:
分支指令:
b               跳转;
    b   label  

bl              函数调用;
    bl  label       mov lr, pc
                    b   label

bx              跳转;
    bx  rd      rd代表目标寄存器;

数据处理指令:
mov =
mvn =~
lsl <<
asl <<
lsr >>
asr >>
ror
rrx
add +
adc
sub -
sbc
rsb 反-
rsc
and &
orr |
eor ^
bic &~

mov                     移动;
    mov rd, #num        rd代表目标寄存器;
                        rd = num;
                        #num : 立即数;(数字常量);

                        合法立即数:
                            可以由一个8位数, 循环右移偶数位得到的立即数;

    mov rd, rn          rd代表目标寄存器;
                        rn代表源寄存器;
                        rd = rn;
   
    mov rd, #(10 - 20 * 2 / 20)     #(10 - 20 * 2 / 20)是编译器翻译
                        rd = 10 - 20 * 2 /20

    mov rd, rn, LSL ri          rd = rn << ri
    mov rd, rn, LSL #10         rd = rn <<10       #10 在0-31之间
                ^ 逻辑左移
                LSR     逻辑右移
                ASL     算术左移
                ASR     算术右移    符号位为1,右移补1
                                            0       0
                ROR     32bit 数据循环右移     
                RRX     C+32bit数据循环右移1 位   

lsl
    lsl rd, rn, #10
    同于
    mov rd, rn, lsl #10

lsr
asl
asr
ror
rrx
    同上

mvn
    mvn rd,#num        rd = ~num
                        0x0         -> 0xffffffff
                        0xff000000 -> 0x00ffffff
                        0x00ff0000  -> 0xff00ffff
add
    add rd, rn, rm      rd = rn + rm
                        rd代表目标寄存器;
                        rn代表源寄存器;
                        rm代表操作数;

    add rd, rn, #10     rd = rn + 10
    add rd, #10, rn     X
    add rd, rn, #(10 - 4 / 2 * 7)
    add rd, rn, rm, LSL ri
    add rd, rn, rm, LSL #20
                    asl
                    lsr
                    asr
                    ror
                    rrx

    add rd, rd, #1
    add rd, #1          rd ++;
    add rd, #10         rd += 10
    add rd, rn          rd += rn

sub
    sub rd,rn, rm      rd = rn - rm

    sub rd,rn, #12
    同上

rsb
    rsb rd,rn, rm      rd = rm - rn

    rsb rd,rn, #100    rd = 100 - rn
    同上
   
and                     测试某一位是否为1, 或者清除某一个位;
    and rd, rn, rm      rd = rn & rm
    and rd, rn, #100    rd = rn & 100
    and rd, rn, #(1<<8) rd = rn & (1<<8)
    and rd, rn, rm, LSL #8

orr                     某一位置1;
    orr rd,rn, rm      rd = rn | rm
    orr rd, rn, #(1<<5) rd = rn | (1<<5)
    orr rd, rn, #20     rd = rn | 20
    orr rd, rn, rm, lsl #4 
                        rd = rn | (rm<< 4)

eor                     反转某些位;
    eor rd,rn, rm      rd = rn ^ rm
    eor rd,rn, #(1<<5)
    eor rd,rn, #10
    eor rd,rn, rm, LSL #2

bic                     清除某一位;
    bic rd,rn, rm      rd = rn & (~rm)
    bic rd,rn, #(1<<3)
    bic rd,rn, #20
    bic rd,rn, rm, LSL #4 

乘法指令:
mul
    mul rd,rn, rm      rd = rn * rm   
   
    mul rd,rn, #100    X

div                     armv6   X
                        armv7   V

内存访问指令:
ldr
    ldr rd, =label      rd = label

push
    push {rn, rm, ri, ...}      把rn rm ri压到栈中;

pop
    pop {rn, rm, ri, ...}       把rn rm ri从栈中取出来;

练习:
    1. printf("val = %d \n",1023 * 23 - (34 + 12) >> 3 | (1<<14) + 3487 & (0x37<<12)^ 0xff);
    2. r1 = 0xff;
      把r1第3 位清零;             
    3. r1 = 0xff;
      把r1第3 5 7位清零;         
    4. r1 = 0xf0;
      把r1第3 位置1;              
    5. r1 = 0xff00;
      把r1第3 5 7位置1;          
    6. r1 = 0xff37;
      把r1第3~12位设置成0x327;   
    7. r1 = 0xff37;
       把r1第3~12位设置成取反;    
    8. r1 = 0xff37
      把r1第3~12位打印出来;      

================================================
CPSR:   当前程序状态寄存器  (user模式下只能修改高5位)
    [31] [30] [29] [28]
     N   Z    C    V

杂指令:
mrs     (与平台相关指令)
    mrs rd,cpsr        rd = cpsr      
msr
    msr cpsr,rd        cpsr = rd

数据处理指令:
adc:    同add
    adc rd, rn, rm          rd = rn + rm + Cbit
                                           ^进位
    ...

sbc:    同sub
    sbc rd,rn, rm          rd = rn - rm - 1 +Cbit
    ...

rsc:    同rsb
    rsc rd, rn, rm          rd = rm - rn - 1 + Cbit
    ...
       
指令+s 后缀
    表示该指令会更新cpsr;
   
========================================
cmp                    
    cmp rn,rm
    等同于:
    subs rd, rn, rm     rd > 0
                        rd < 0
                        rd == 0
                        rd != 0
    N   Z

tst                     测试某个位是否为1
    tst rn, rm
    等同于
    ands rd, rn, rm        

teq                     测试两个数是否相等
    teq rn,rm
    等同于
    eors rd, rn, rm

cmn                     测试两个数想加是否有进位
    cmn rn, rm
    等同于
    adds rd, rn, rm

1.顺序结构
2.分支结构

    if(...)
        ....

    if(...)     > < == !=
        ...
    else
        ...

    if(...)
        ...                 b   out
    else if(...)
        ...                 b   out
    else if(...)
        ...                 b   out
    else
        ...

    switch()
    {
        case:               eq
            ....;
            break;          b   out
        case:               eq
            ....;
            break;          b   out
        case:               eq
            ....;
            break;          b   out
    }  

    1 23 257 123 1098 76 13 3  
   
    1 3 13 23 76 123 257 1098
1)  二分查找;

    132 120 117 123 128 134 137 121

    117         120121     123 128 132 134 137
2) 哈希表;
    -117   
    0   1  2   3   4   5   6   7   ... 11  15  17  20
    do1 outout do2 do3 out do4 out     do5 do7 do8do9

3.循环结构
    while(1)            1:                  b   .(.表示当前地址)
        ;                   b   1b

    while(...)          1:  cmp ....
        ...;                b   1b
   
    for(...; ...; ...)      mov ...
        ...             1:  cmp ...
                            b   1b

                        1:
    do{                     xxxx
        ...                 xxxx
    }while(...);            cmp ...
                            b   1b
    label:
        goto    label

arm 指令的条件执行:
    mov == moval
    addlt ==> 小于条件成立执行
后缀决定条件:
    al  无条件执行;
    ne  !=              Z = 0
    eq  ==              Z = 1
    lt  <               N
    le  <=              N Z
    gt  >               N
    ge  >=              N Z

homework:
1.  if( i > 10 && i <20)
        printf("i > 10 &&i < 20\n");
    else if( i > 20 && i <60 )
        printf("i > 20 &&i < 60\n");
    else if( i > 60 && i <90 )
        printf("i > 60 &&i < 90\n");
    else if( i < 10 || i > 90)
       printf("other\n");

    (注意: cmp后不要加条件)
   
2.  输出1-100的奇数;
3.  输出100个随机数;    random();
4.  输出100个随机奇数;
5.  输出100个256内随机奇数;
6.  9*9 乘法表;
7.
    高从1 到 10的三角;     **********
                            ^    ^ ^
*
**
***
****        高为4;
***
**
*

8.
    半径从1 到 10的菱形;

    *
   ***
  *****
 *******    半径为4 ;
  *****
   ***
    *

代码效率:
if(...)
    for()
        ...
else
    for()
        ...

for()
{
    if()
        ...
    else
        ...
}

指令的执行:
        取出指令    翻译指令    执行指令
        取指        译码        执行
                        (条件判断)
流水线:
mov                                         3T
sub                                         1T
add                                         1T
mov                                         1T 
nop                                         1Tpc  
b                               V           1T
nop                 V
nop     V
nop

for(1000w)         
    ...             3000w

for(1000w)
    ...             1000w+2

for(i = 0; i < 1000w; i++)
    sum ++;         3000w   流水线没有被使用到;                    

循环展开:
for(i = 0; i < 100w; i++)       1200W
{
    sum++;          3T          12T
    sum++;          1T
    ...     10次;   ...
    sum++;          1T
    sum++;          1T
}

CACHE:  缓存;
    取指快了;  

分支预测:
    静态预测;
    动态预测;
    减少分支指令下一条和下下一条指令的取指和译码;  

if(...)
    1000w
else
    1000w

分支汇编效率:
cmp xxx, xxx
addeq
subeq
muleq       浪费了1000w个取指译码周期;
lsleq
....        1000w
xxxne
xxxne
xxxne
xxxne      
....        1000w

以下效率更高:
cmp xxx, xxx
beq do1     多了两条指令;
bne do2

do1:
    ...     1000w

do2:
    ...     1000w

内存拷贝效率:
for(i = 0; i < 1000w; i++)
{
    br[i] = ar[i];      ldr r0, [r5, r4, lsl #2]; str r0, [r6, r4, lsl #2]
}

for(i = 0; i < 100w; i++)
{
    ldr
    str
    ...     10个ldr str
    ldr
    str
}

for(i = 0; i < 100w; i++)
    ldm
    stm     1个拷贝10个数据

硬件拷贝: (没有代码)
    DMA     直接内存访问;

内存访问指令:
ldr     取
    ldr rd, [rn]        rd = *(unsigned int *)rn
    ldr rd, [rn, #(1+2-1*2+3)]
    ldr rd, [rn, #4]    rd = *(unsigned int *)(rn + 4)
                 ^      #4范围 -4K ~ 4K
    ldr rd, [rn, rm]    rd = *(unsigned int *)(rn + rm)
    ldr rd, [rn, rm, lsl #2]   
                        rd = *(unsignedint *)(rn + (rm << 2))
       
    ldr rd, [rn], #4    rd = *(unsigned int *)(rn)
                        rn += 4;

    ldr rd, [rn, #4]!   rd = *(unsigned int *)(rn + 4)
                        rn += 4;

    ldrh rd, [rn]       rd = *(unsigned short*)rn
    ldrb rd, [rn]       rd = *(unsigned char *)rn

伪指令:
ldr    
1.
    ldr rd, =.LC0       rd = .LC0       访问的标签.LC0可以跨段;(绝对地址)
    ==>                                                 跨文件;
    ldr rd, [pc, #?]
    ...         ^ 汇编器计算所得;
    .word   .LC0
            ^ 连接器替换成具体的地址;

2. 
    ldr rd, .L0     rd = *(u32*)(.L0)   访问的标签.L0不能跨段;(相对地址)
    ...                                            不能跨文件;
.L0:
    .word   .LC0
    ==>
    ldr rd, [pc, #?]
    ...         ^ 汇编器计算所得;
                 ^ -4K ~ 4K
.L0:
    .word   .LC0

3. 
    adr rd,.L0     rd = .L0            访问的标签.L0不能跨段;(相对地址)
                                                   不能跨文件;
    =>
    add rd, pc, #?
                -?
                ^ 汇编器计算所得;

str     存
    str rd, [rn]        *(unsigned int *)rn = rd
    str rd, [rn, #(1+2-1*2+3)]
    str rd, [rn, #4]
    str rd, [rn, rm]
    str rd, [rn, rm, lsl #2]
    str rd, [rn], #4
    str rd, [rn, #4]!
    strh
    strb

atpcs:  规定
        r13 -> sp
        sp 栈指针, 指向栈底;
        满递减栈
       
        开辟num 字节空间: sub sp, sp, #num
        释放num 字节空间: add sp, sp, #num

练习:
    1.  int i;
       int ar[100];
        for(i = 0; i < 100; i++)
            ar[i] = i;
        for(i = 0; i < 100; i++)
            printf("ar[%d] =%d\n", i, ar[i]);
   
    2. inti;
        int ar[100];
        int br[100];
        srandom(getpid());
        for(i = 0; i < 100; i++)
            ar[i] = random() % 256;
        for(i = 0; i < 100; i++)
            br[i] = ar[i];
        for(i = 0; i < 100; i++)
            printf("ar[%d] = %d br[i]= %d\n", i, ar[i], i, br[i]);
       
    3. int i;
        int ar[100];
        int br[100];
        srandom(getpid());
        for(i = 0; i < 100; i++)
            ar[i] = random() % 256;
        for(i = 0; i < 100; i++)
            br[i] = ar[i];
        qsort(br, 100, 4, cmp_int);
        for(i = 0; i < 100; i++)
            printf("ar[%d] = %d br[i]= %d\n", i, ar[i], i, br[i]);
       
    4. char *p = "hello world\n";
        char str[mystrlen(p) + 1];
        mystrcpy(str, p);
        printf(str);
   
内存访问指令:
    ldr str ldm stm

ldr:
cpu -> AMBA -> ADDR -> dramc -> BANK -> RAW -> COL ->DDR3
    <-      <-DATA
ldr:
cpu -> addr -> dramc -> ADDR -> DDR3
    <-              <- DATA
ldr:
cpu -> addr -> dramc -> ADDR -> DDR3
    <-              <- DATA
ldr:
cpu -> addr -> dramc -> ADDR -> DDR3
    <-              <- DATA
str:

ldm:
cpu -> addr -> dramc -> ADDR -> DDR3
    <-              <- DATA            突发访问;
    <-              <- DATA
    <-              <- DATA
    <-              <- DATA
stm:

f : 满
e : 空
d : 递减
a : 递增

stmfd       stmfa       stmed       stmea
ldmfd       ldmfa       ldmed       ldmea
满递减栈    满递增栈    空递减栈    空递增栈
^
ATPCS

push    ==> stmfd sp!, {...}
pop     ==> ldmfd sp!, {...}

stmfd sp!, {lr}     *(u32 *)(sp - 4) = lr;!: sp -= 4;
stmfd sp, {lr}      *(u32 *)(sp - 4) =lr;
                    - 4
                    递减: -
                    减后再存: 满栈;

ldmfd sp!, {pc}     pc = *(u32 *)sp; !: sp+= 4;   
ldmfd sp, {pc}      pc = *(u32 *)sp;

f: stm:先加减, 再存;
   ldm:先取, 再减加;

e: stm:先存, 再加减;
   ldm:先减加, 再取;

d: stm:递减;
   ldm:递增;

a: stm:递增;
   ldm:递减;

i : 增;
d : 减;
a : 后;
b : 先;

ib  : 先增;
ia  : 后增;
db  : 先减;
da  : 后减;

stmib : 先增, 后存; (stmfa)
stmia : 先存, 后增; (stmea)
stmdb : 先减, 后存; (stmfd)
stmda : 先存, 后减; (stmed)

ldmib : 先增, 后取; (ldmed)
ldmia : 先取, 后增; (ldmfd)
ldmdb : 先减, 后取; (ldmea)
ldmda : 先取, 后减; (ldmfa)

ATPCS:
    r15 : pc    程序指针, 指向要取指的指令;
    r14 : lr    返回地址;
    r13 : sp    栈指针, 指向栈底;
    r12 : ip    临时寄存器; 临时保存sp;
    r11 : fp    幀指针寄存器; 当前函数栈内数据访问; 恢复sp;
                [fp,#-4]   [fp, #-8]
   
    r0-r3 参数<=4;参数>4 (sp);
    r0 返回值;
    push -> stmfd
    pop -> ldmfd

====================================================
上层开发:
    策略;
底层开发:
    机制;

tiny4412    EXYNOS4412      ARM CORTEX-A9
友善之臂    三星soc         ARMV7 ARMV6

查手册查找指令用法:
arm:                armv1 armv2 armv3armv4
    32bit  
    mov r0, r1
        4   4  
thumb:              ..................thumbv1  
    16bit

    add r1,r0, #6 

ARM --> THUMB
THUMB --> ARM
    bx  r0          r0[0] = 1 : ---> THUMB
                    r0[0] = 0 : --->ARM
    blx

相对跳转:
    bl  printf      (相对于当前pc跳转+/-32M地址)

绝对跳转:
    mov lr, pc
    ldr pc, =printf (直接对pc赋值, 跳转范围是32bit 地址)

homework:
(1)通过手册找指令用法, 并且转换二进制:  arm-linux-gcc -c
1.
    cpylt   r1,r3
    10110001101000000001000000000011

2.
    revgt   r1,r2
    11000110101111110001111100110010

3.
    smlalbtlt   r4, r3, r1, r2
    10110001010000110100001011000001

(2)通过二进制找到汇编指令:              arm-linux-objdump-D
4.
    0x00000010 
    andeq r0, r0, r0, lsl r0

5.
    0xe28fc600 
    1110 0010 1000 1111 1100 0110 00000000
    adr ip, 0x0
    add ip, pc, #0x0

(3)汇编实现以下代码:
    1. 打开一个文件passwd;
    2. 把文件中每一行数据进行排序; 
        if(d1 > d2)
            return 1;
    3. 把文件中所有行数据进行排序;
        if(strcmp(str1, str2) >0)
            return 1;
    4. 写回到文件中;
   
4)汇编实现单链表/双向链表;

ARM v7汇编与相关练习的更多相关文章

  1. ARM标准汇编与GNU汇编

    ARM标准汇编与GNU汇编 http://www.cnblogs.com/hnrainll/archive/2011/05/17/2048315.html

  2. ARM 常用汇编指令

    ARM 汇编程序的框架结构 .section .data <初始化的数据> .section.bss <未初始化的数据> .section .text .global _sta ...

  3. ARM 内核 汇编指令 的 8种 寻址方式

    str: store register ->指令将寄存器内容存到内存空间中, ldr:  load register 将内存内容加载到通用寄存器, ldr/str 组合来实现ARM CPU 和内 ...

  4. ARM常用汇编指令介绍

    b     跳转指令(跳转范围为32Mb) bl    带返回地址的跳转,指令自动将下一条指令的地址复制到R14寄存器,然后跳转到指定地址去执行,执行完后返回到下一条指令处执行 pc    寄存器R1 ...

  5. 【安卓逆向】ARM常见汇编指令总结

    跳转指令 B 无条件跳转 BL 带链接的无条件跳转 BX 带状态切换的无条件跳转 BLX 带链接和状态的无条件跳转 存储器与寄存器交互数据指令(核心) 存储器:主存和内存 寄存器中放的数据:可以是字符 ...

  6. VisualStudio 编写汇编代码相关设置

    VS编写汇编代码方法 新建空项目,不创建解决方案 项目右键,Build Customizations,选择masm 新建源文件,后缀为.ASM 编写代码 .386 ; Tells MASM to us ...

  7. arm中断汇编

    IRQ_Handler: push {lr} /* 保存 lr 地址 */ push {r0-r3, r12} /* 保存 r0-r3,r12 寄存器 */ mrs r0, spsr /* 读取 sp ...

  8. ARM常用汇编指令列表 --- 转自百度文库

  9. STM32,ARM,Keil工具相关

    One ELF Section per Function https://blog.csdn.net/iceiilin/article/details/6091575 因此,可以得出,选项One EL ...

随机推荐

  1. CRM客户关系管理系统(五)

    第五章.分页功能开发 5.1.修改BaseKingAdmin和完善前段页面显示 现在访问没有注册的model会报错,因为基类中没有写list_display和list_filter. 在基类中设置一个 ...

  2. Codeforces Round #417 (Div. 2)-A. Sagheer and Crossroad

    [题意概述] 在一个十字路口 ,给定红绿灯的情况, 按逆时针方向一次给出各个路口的左转,直行,右转,以及行人车道,判断汽车是否有可能撞到行人 [题目分析] 需要在逻辑上清晰,只需要把所有情况列出来即可 ...

  3. swing JTable

    JTable 实例 import java.awt.Dimension; import java.awt.GridBagConstraints; import java.awt.GridBagLayo ...

  4. springMVC源码分析--ViewResolver视图解析器(一)

    SpringMVC用于处理视图最重要的两个接口是ViewResolver和View.ViewResolver的主要作用是把一个逻辑上的视图名称解析为一个真正的视图,SpringMVC中用于把View对 ...

  5. 分布式服务框架Dubbo

    随着互联网的发展,网站应用的规模不断扩大,常规的垂直应用架构已无法应对,分布式服务架构以及流动计算架构势在必行,亟需一个治理系统确保架构有条不紊的演进. 单一应用架构 当网站流量很小时,只需一个应用, ...

  6. Bootstrap3 排版-页面主体

    Bootstrap 将全局 font-size 设置为 14px,line-height 设置为 1.428.这些属性直接赋予 元素和所有段落元素.另外,<p> (段落)元素还被设置了等于 ...

  7. 热烈庆祝自已厉精13年开发的 DB查询分析器 7.01(最新版本) 在中关村在线本月获得近6000次的下载量

    中国本土程序员马根峰(CSDN专访马根峰:海量数据处理与分析大师的中国本土程序员)推出的个人作品----万能数据库查询分析器,中文版本 DB 查询分析器.英文版本DB Query Analyzer.它 ...

  8. Scikit-learn:分类classification

    http://blog.csdn.net/pipisorry/article/details/53034340 支持向量机SVM分类 svm分类有多种不同的算法.SVM是非常流行的机器学习算法,主要用 ...

  9. 源码推荐:移动端商城(微信小程序源代码) WebView离线缓存

    移动端商城(微信小程序源代码)(上传者:腾讯攻城师jack) 功能包括:商品橱窗,商品搜索,购物车,结账等功能. TableView嵌套webView自适应高度(上传者:linlinchen) tab ...

  10. JavaEE介绍

    相关术语 为什么需要JavaEE 我们编写的JSP代码中,由于大量的显示代码和业务逻辑混淆在一起,彼此嵌套,不利于程序的维护和扩展.当业务需求发生变化的时候,对于程序员和美工都是一个很重的负担.为了程 ...