gas Assembler Directives - 汇编指令

程序中所有以点开头的都是汇编器指令,就是给汇编器读的指令,不属于ARM指令集。

    .flie:指定了源文件名。手写可忽略
    .align:指定了代码对齐方式你后面跟的是2的次方
    .ascii:声明字符串
    .global:声明全局符号。全局符号是指在本程序外可访问的符号。
    .type:指定符号的类型,
        ".type main,%function"表示main为函数,
        ".type a, @object"指定一个符号的类型是函数类型或者是对象类型, 对象类型一般是数据
        ".section  .text.Default_Handler,"ax",%progbits"节中包含数据
        "%nobits"(节中不含数据,只是占位空间),
        "%note"(节中包含注释信息,不是程序).

    .ascii "string"...

        .ascii表示零个或多个(用逗号隔开)字符串,并把每个字符串(结尾不自动加"0"字节)中的字符放在连续的地址单元.

    .asciz
        
        z 代表"0", 即每个字符串结尾自动加一个"0"字节.

        int_msg:
            .asciz "Unknown interrupt\n"

    .btye

        .btye 表示零或多个表达式(用逗号隔开),每个表达式被放在下一个字节单元.
    
    .fill  

        形式: .fill repeat, size, value

        repeat, size, value 都是常量表达式.    fill含义是反复拷贝size个字节.

        repeat可以大于0. size也可以大于等于0,但不能超过8, 如果超过8, 也只取8.把repeat个字节以8个为一组,每组的最高4个字节内容为0,最低4字节内容置为value size and value 为可选项.如果第2个逗号和value值不存在,则假定value为0.如果第1个逗号和size不存在,则假定size 为 1.

        Linux初始化的过程中,对全局描述符表GDT进行设置的最后一句为:

         .fill NR_CPUS * 4, 8, 0    /* space fot TSS's and LDT's */ 因为每个描述符正好占8个字节,因此, .fill给每个CPU留有存放4个描述符的位置.

    .word: 用来存放地址。
    .size:设定指定符号的大小。".size main,.-main"中的"."表示当前地址,减去main符号的地址为整个main函数的大小。
    .ident:编译器标识,无实际意义。

    .quad 表示零个或多个bignums(用逗号分隔),对于每个bignum, 其缺省值是8字节整数.如果bignums超过8字节,则打印一个警告信息;并只取bignum最低8字节.

        例如, 对全局描述符表的填充就用到这个指令:

            .quad 0x00cf9a000000ffff    /* 0x10 kernel 4GB code at 0x00000000 */
            .quad 0x00cf92000000ffff    /* 0x18 kernel 4GB data at 0x00000000 */
            .quad 0x00cffa000000ffff    /* 0x23 user 4GB code at 0x00000000 */
            .quad 0x00cff2000000ffff    /* 0x2b user 4GB data at 0x00000000    */


    .rept count

        // 把.rept指令与.endr指令之间的行重复 count 次,
        .rept 3
        .long 0
        .endr

        // 相当于
        .long 0
        .long 0
        .long 0

    .space size, fill

        这个指令保留size个字节的空间,每个字节的值为fill. size and fill 都是常量表达式.如果逗号和fill 被省略,则假定fill为0.
        .space 1024        // 表示保留1024字节的空间,并且每个字节的值为0.

    .word expressions

        这个表达式表示任意一节中的一个或多个表达式(用逗号分开),表达式的值占两个字节.

        gdt_descr:
        .word GDT_ENTRIES * 8 -1        // 表示变量gdt_descr的值为GDT_ENTRIES*8-1
        
    .long expressions

        与.word类似.

/*
 * balignl
 */
    .balignl 16,0xdeadbeef        // 作用:以当前地址开始,在地址为16的倍数的指令位置的上一个指令填入为0xdeadbeef的内容。

    就是在以当前地址开始,在地址为16的倍数的指令位置的上一个指令填入为0xdeadbeef的内容,它们的作用就是为内存做标记,插在那里,这个位置往前有特殊作用的内存,禁止访问。

/*
 * section
 */
    .section section_name [, "flags"[, %type[,flag_specific_arguments]]]

    每一个段以段名为开始, 以下一个段名或者文件结尾为结束。这些段都有缺省的标志(flags),连接器可以识别这些标志。(与arm asm中的AREA相同)。下面是ELF格式允许的段标志flags:

    <标志>     含义

    a          允许段
    w          可写段
    x          执行段

    .section ".start", #alloc, #execinstr  @命名一个".start"段,该段具有可分配和可执行属性

     .section name [, "flags "[, @type [,flag_specific_arguments ]]]

        The optional flags argument is a quoted string which may contain any combination of
        the following characters:

            a section is allocatable
            w section is writable
            x section is executable
            M section is mergeable
            S section contains zero terminated strings
            G section is a member of a section group
            T section is used for thread-local-storage

/*
 * .type
 */
    该伪指令用于设置符号的类型。

    .type name , type description

    这会将符号名称的类型设置为功能符号或对象符号。为了提供与各种其他汇编程序的兼容性,类型描述字段支持五种不同的语法。

    .type <name> STT_<TYPE_IN_UPPER_CASE>
    .type <name>,#<type>
    .type <name>,@<type>
    .type <name>,%<type>
    .type <name>,"<type>"

    The types supported are:

    STT_FUNC
    function
        Mark the symbol as being a function name. 将符号标记为函数名称。

    STT_GNU_IFUNC
    gnu_indirect_function 
        Mark the symbol as an indirect function when evaluated during reloc processing. (This is only supported on Linux targeted assemblers).
        在重定位处理期间进行评估时,将符号标记为间接函数。 (这仅在针对GNU系统的汇编器上受支持)

    STT_OBJECT
    object
        Mark the symbol as being a data object. 将符号标记为数据对象。

    STT_TLS
    tls_object
        Mark the symbol as being a thead-local data object. 将符号标记为thead-local数据对象。

    STT_COMMON
    common
        Mark the symbol as being a common data object.    将符号标记为公共数据对象。

    STT_NOTYPE
    notype
        Does not mark the symbol in any way. It is supported just for completeness.
        请勿以任何方式标记该符号。 仅出于完整性目的而支持它。

    gnu_unique_object
        Marks the symbol as being a globally unique data object.The dynamic linker will make sure that in the entire process there is just one symbol with this name and type in use. (This is only supported on assemblers targeting GNU systems).
        将符号标记为全局唯一数据对象。 动态链接器将确保在整个过程中仅使用此名称和类型的一个符号。 (这仅在针对GNU系统的汇编器上受支持)

/*
 * .global
 */
    函数如果需要在其他文件中调用, 需要用到.global伪操作将函数声明为全局函数。为了不至于在其他程序在调用某个C函数时发生混乱,    对寄存器的使用我们需要遵循APCS准则。函数编译器将处理函数代码为一段.global的汇编码。

    ARMV7 函数的编写应当遵循如下规则:

        a.a1-a4寄存器(参数、结果或暂存寄存器,r0到r3 的同义字)以及浮点寄存器f0-f3(如果存在浮点协处理器)在函数中是不必保存的;
        
        b.如果函数返回一个不大于一个字大小的值,则在函数结束时应该把这个值送到 r0 中;
        
        c.如果函数返回一个浮点数,则在函数结束时把它放入浮点寄存器f0中;
        
        d.如果函数的过程改动了sp(堆栈指针,r13)、fp(框架指针,r11)、sl(堆栈限制,r10)、lr(连接寄存器,r14)、 v1-v8(变量寄存器,r4 到 r11)和 f4-f7,那么函数结束时这些寄存器应当被恢复为包含在进入函数时它所持有的值。

/*
 * .incbin
 */
    伪操作可以将原封不动的一个二进制文件编译到当前文件中,使用方法如下:
    
    .incbin "file"[,skip[,count]]

        skip表明是从文件开始跳过skip个字节开始读取文件,count是读取的字数.

    incbin指令包含当前位置的文件逐字记录。可以控制与"-I"命令行选项一起使用的搜索路径(请参见命令行选项)。文件周围需要引号。

    skip参数跳过文件开头的若干字节。count参数指示要读取的最大字节数。请注意,数据没有以任何方式对齐,因此用户有责任确保在incbin指令之前和之后都提供了正确的对齐。

/*
 * .popsection
 */
    这是ELF段堆栈操作指令之一。

    此指令将当前节(和子节)替换为节堆栈上的顶部节(和子节)。此部分从堆栈中弹出。

/*
 * .pushsection
 */
    .pushsection name [, subsection] [, "flags"[, @type[,arguments]]]

    此指令将当前节(和子节)推送到节堆栈的顶部,然后用名称和子节替换当前节和子节。可选标志、类型和参数的处理方式与.section(请参阅section)指令中的处理方式相同。

/*
 * .previous
 */
    此指令将当前节(和子节)与此节之前最近引用的节/子节对进行交换。一行中前面的多个指令将在两个部分(及其子部分)之间翻转。

        .section A
         .subsection 1
          .word 0x1234
         .subsection 2
          .word 0x5678
        .previous
         .word 0x9abc

    将0x1234和0x9abc放入第1小节,将0x5678放入第A节第2小节。同时

        .section A
        .subsection 1
          # Now in section A subsection 1
          .word 0x1234
        .section B
        .subsection 0
          # Now in section B subsection 0
          .word 0x5678
        .subsection 1
          # Now in section B subsection 1
          .word 0x9abc
        .previous
          # Now in section B subsection 0
          .word 0xdef0

    将0x1234放入节A,0x5678和0xdef0放入节B的子节0,0x9abc放入节B的子节1。

    对于节堆栈,此指令将当前节与节堆栈上的顶部节交换。

/*
 * .purgem
 */
    取消定义宏名称,以便以后不会扩展字符串的使用。    

/*
 * .macro
 */
    .macro  sum from=0, to=5
    .long   \from
    .if     \to-\from
    sum     "(\from+1)",\to
    .endif
    .endm

    With that definition, ‘SUM 0,5’ is equivalent to this assembly input:
        .long   0
        .long   1
        .long   2
        .long   3
        .long   4
        .long   5

    开始定义一个名为macname的宏。如果宏定义需要参数,请在宏名称后指定它们的名称,并用逗号或空格分隔。
    可以限定宏参数,以指示是否所有调用都必须指定非空值(通过":req"),或者是否接受所有剩余参数(通过":vararg")。
    通过在名称后面加"=deflt",可以为任何宏参数提供默认值。
    不能用相同的macname定义两个宏,除非它在两个定义之间遵循.purgem指令(请参见purgem)。
    
    .macro comm    
    定义一个名为comm的宏,它不带参数.

    .macro plus1 p, p1
    .macro plus1 p p1
    任何一个语句都开始一个名为plus1的宏的定义,它接受两个参数;在宏定义中,写入'\p'或'\p1'来计算参数。
    
    .macro reserve_str p1=0 p2
    用两个参数开始定义名为reserve_str的宏。第一个参数有默认值,但第二个参数没有。
    定义完成后,可以将宏调用为"reserve_str a,b"(将"\p1"求值为a,将"\p2"求值为b),
    也可以调用为"reserve_str,b"(将"\p1"求值为默认值,在本例中为"0",将"\p2"求值为b)。
    
    .macro m p1:req, p2=0, p3:vararg
    开始定义一个名为m的宏,至少有三个参数。
    第一个参数必须始终指定一个值,但第二个参数必须始终指定一个默认值。第三种形式将在调用时指定所有剩余的参数。

    调用宏时,可以按位置或关键字指定参数值。例如,"sum 9,17"等同于"sum to=17,from=9"。

    注意,由于每个macarg可以是与目标体系结构所允许的任何其他macarg完全相同的标识符,因此如果当某些字符出现在特殊位置时,
    目标手工对其产生特殊意义,则可能会偶尔出现问题。例如,如果冒号(:)通常允许作为符号名称的一部分,
    但特定于体系结构的代码在作为符号的最后一个字符出现(表示标签)时对其进行了特殊处理,
    那么宏参数替换代码将无法知道这一点,并将整个构造(包括冒号)视为标识符,并仅检查此标识符作为参数替换的对象

/*
 * .if
 */
    .ifb text
        如果操作数为空(空),则汇编以下代码段。

/*
 * .align
 */
    .align [abs-expr[, abs-expr[, abs-expr]]]

    .align 4
    .align 4,0x90

    将位置计数器(在当前小节中)填充到特定的存储边界。第一个表达式(必须是绝对的)是所需的对齐方式,如下所述。 如果省略此表达式,则使用默认值0,有效禁用对齐要求。

    第二个表达式(也是绝对的)给出要存储在填充字节中的填充值。它(和逗号)可以省略。如果省略,则填充字节通常为零。 但是,在大多数系统上,如果将该节标记为包含代码,并且省略了填充值,则该空间将填充无操作指令。

    第三个表达式也是绝对的,也是可选的。如果存在,则为该对齐指令应跳过的最大字节数。 如果进行对齐需要跳过的字节数超过指定的最大值,则根本不进行对齐。可以通过在所需的对齐方式之后简单地使用两个逗号来完全省略填充值(第二个参数)。如果希望在适当的时候用无操作指令填充路线,这将很有用。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值