ARM汇编学习拾贝 (持续更新)

  1. 基本知识
     ldrmeans load from memory, in which case Rd is the destination, and str means store to memory, so Rd would be the source there.

    基本的函数调用模板
     	.text
     	.align	2
     	.global	functionName
     	.type	functionName, %function
     functionName:
     	mov	ip, sp
     	stmfd	sp!, {fp, ip, lr, pc}
     	sub	fp, ip, #4  @ Space for local variables
     	sub	sp, sp, #8
     
     	sub	sp, fp, #12
     	ldmfd	sp, {fp, sp, lr}
     	bx	lr  -->用bx是因为是得arm和thumb之间的跳转能够正常执行
    


    Immediate addressing,Any number that can be expressed in 8 bits constant, plus 5 bits in rotation is allowed. Anything other that that must be declared as a constant, and loaded from memory. Examples of valid values are 0x10, 0x100 (both using the constant alone), and 0x40000 (using rotate to left)


    如何返回保存的地址执行:
        1. 返回地址保存在当前异常模式的r14时, 因为目标地址是pc,所以这几条指令后面都要加S(它们都会影响CPSR的值).
            • To return from a SWI or undefined instruction trap use:
               MOVS pc, r14
            • To return from an IRQ, FIQ or prefetch abort use:
               SUBS pc, r14, #4  --- 返回前一条指令
            • To return from a data abort to retry the data access use:
              SUBS pc, r14, #8   --- 返回前两条指令

        2. 返回地址保存在堆栈时:
            LDMFD r13!, (r0-r3, pc) -

    ARM异常的优先级:
        1. reset (highest priority);
        2. data abort;
        3. FIQ;
        4. IRQ;
        5. prefetch abort;
        6. SWI, undefined instruction (including absent coprocessor). These are mutually
            exclusive instruction encodings and therefore cannot occur simultaneously.
        这里有一个很trick的优先级逻辑:
            同时两个异常(FIQ&IRQ), FIQ时,会屏蔽掉IRQ。所以,如果只有在FIQ结束并使能IRQ之后,才会再响应之后的IRQ。
            同时三个异常(FIQ&IRQ&非reset和非数据异常), 先执行FIQ,当FIQ&IRQ都结束后,程序返回到产生第三个异常的指令
            同时三个异常(FIQ&IRQ&非reset和数据异常),因为数据异常没有屏蔽FIQ,所以此时程序首先进入到数据异常,此时马上转到执行FIQ,当FIQ结束后,程序返回到数据异常里继续执行。

    ARM汇编学习拾贝 (持续更新)_第1张图片

优化相关
2.1 使用条件执行代替转移指令(因为转移指定需要花费更多的指令周期)
     摘录自:Addison.Wesley.ARM.System_on_Chip.Architecture.2nd.Edition,第三章
     ARM汇编学习拾贝 (持续更新)_第2张图片

2.2 摘自《ARM System Developer's Guide: Designing and Optimizing System Software》第五章
  • 使用32位的数据类型,无论是在参数还是内部计算, 这样可以使得编译器编译的代码更加有效,避免编译器生成不必要的检测边界及强制转换类型的指令
    对于除法,无符号数效率更高
  • 关于循环结构
    使用递减的循环结构代替递增,这可以节省对于是否为0的判断,因为该值已经在标志位中得到反映。同时,这里使用无符号数,并且循环条件应该是i!=0.
    使用do-while的结构代替for,尤其是那种递减到0的for循环
    适当的展开循环,减少循环次数。但是这里要小心,不要导致代码过分增加,降低关键的cache优化

  • 关于寄存器的使用
    局部变量的个数多少,影响到编译器对于所分配的寄存器的使用。(过多会使用栈来保存,从而降低性能)

  • 关于函数调用
    大于4个(对于C++来说是3个,因为还有一个是this)的参数,应该组成结构体,通过传递结构体的指针来传递这些参数。这样节省了编译器对其的堆栈操作。
    比较小的调用及被调用函数放在一个文件中,先定义后调用。同时用好inline

  •  关于指针别名
    不要依赖编译器来消除包含存储器访问的公共子表达式,而应该建立一个新的局部变量来保存这个表达式的值,这样可以保证只对这个表达式求一次值
    避免使用局部变量的地址,否则对这个变量的访问效率会比较低

  •  
  •  
  •  



  1. 资源
    相当好的关于arm的一些限制的讲解:http://www.coranac.com/tonc/text/asm.htm
    如关于shift的用途, 为什么arm的汇编对于立即数的限制(12bit),

    The only valid immediate values are rotated bytes

    When instructions allow immediate values, the only permissible values are those that can be reduced to a byte rotated by an even number. 0xFF and 0x100 are allowed, but 0x101 is not. This has consequences for data operations, but also for memory addressing since it will not be possible to load a full 32bit address in one go. You can either construct the larger value out of smaller parts, or use a load-assignment construct: ‘ldr Rd,=num’ which the assembler will convert into a mov if possible, or a PC-relative load if not.


    常用makefile配置
    AS      := arm-eabi-gcc
    ASFLAGS := -x assembler-with-cpp
    
    # Rule for assembling .s -> .o files
    $(SOBJ) : %.o : %.s
    	$(AS) $(ASFLAGS) -c $< -o $@
    
  2. ARM指令集
    很有用的一篇ppt, 由台湾的黄敬群写的, 可以在slideshare.net上找到http://www.slideshare.net/jserv/arm-and-soc-traning-part-ii-system
    <探索嵌入式 ARM 平台與 SoC part II>











你可能感兴趣的:(汇编,System,FP,makefile,编译器,variables)