<> 二

作者: 洧中苇_4187 | 来源:发表于2020-09-24 16:04 被阅读0次

    10.汇编基础

    10.1 编写一个C程序,保存为 Hello.c

    #include <stdio.h>
    int main ()
    {
        puts("Helloo ,World!\n");
        return 0;
    }
    

    10.2 使用Clang编译器将其编译成汇编代码

    clang -o2 -S -masm=intel -fno-asynchronous-unwind-tables Hello.c
    

    10.3 将汇编代码生成 .o 目标文件

    as asm_Hello -o Hello.o
    

    10.4 通过ld指令进行链接,得到可执行文件

    ld Hello.o -e _main -lsystem -arch x86_64 -macosx_version_min 10.15.4 -o Hello
    
    说明:
    -e(entry) 指定函数入口为 _main ,如果不指定 默认为_start,
    源代码中调用了系统函数puts(),所以需要-lsystem 参数链接系统的库,
    -arch表示链接为64位的应用程序,
    -macosx_version_min则指定了运行需要的最低的系统版本.
    
    双击可执行文件,终端打印如下
    
    Last login: Thu Sep 24 11:45:58 on ttys004
    /Users/yangpei1/Desktop/Hello ; exit;
    yangpei1@localhost ~ % /Users/yangpei1/Desktop/Hello ; exit;
    Helloo ,World!
    
    
    [进程已完成]
    
    直接创建Xcode工程,运行之前的Hello.s汇编代码,控制台有同样输出
    //汇编代码如下
        //以(.)开头的指令都是伪指令 剩下的如push mov call等则是X86_64指令,
        //.section指示了接下来的代码所位于的段和节取, __TEXT说明位于代码区,
       // __text说明是主程序的代码节区,后面的参数则是这个节区的属性
        .section    __TEXT,__text,regular,pure_instructions
       // macOS的最低版本为10.15
        .build_version macos, 10, 15    sdk_version 10, 15, 4
        //表示使用Intel语法
        .intel_syntax noprefix
        //_main符号可以被链接器ld使用,因为_main是程序的入口函数,
        //所以他必须被链接器使用,并将入口地址写入可执行文件的LC_MAIN加载命令
        .globl  _main                   ## -- Begin function main
        //代码对齐方式,是2^4=16字节对齐,指令空隙部分使用0x90(nop)进行填充
        .p2align    4, 0x90
    _main:                                  ## @main
    ## %bb.0:
        push    rbp
        mov rbp, rsp
        sub rsp, 16
        mov dword ptr [rbp - 4], 0
        lea rdi, [rip + L_.str]
        call    _puts
        xor ecx, ecx
        mov dword ptr [rbp - 8], eax ## 4-byte Spill
        mov eax, ecx
        add rsp, 16
        pop rbp
        ret
                                            ## -- End function
        .section    __TEXT,__cstring,cstring_literals
    L_.str:                                 ## @.str
        .asciz  "Helloo ,World!\n"
    
    //伪指令表示当前的截取可以被内联到其他代码中,
    //如果没有其他代码使用就可以被剔除掉.
    .subsections_via_symbols
    

    11.伪指令

    伪指令存在的意义:告诉汇编器指令和代码存放的节区.

    .section伪指令只是了接下来代码所在的段区和节区,并指定节区的属性,指令格式为:
    
    .section segname ,sectname [[[,type] ,attribute] ,sizeof_stub]
    
    segname 和 sectname 分别指定段 和 节区的名字,之后的三个参数为可选项,
    type指定节的类型; 
    attribute指定节的属性; 
    sizeof_stub参数值在type为symbol_stubs时需要,用于指定symbol_stubs的大小
    
    type参数常用的可选的值有以下几种
    (1)regular: regular类型可以包含任意代码,链接器不会对他做任何处理
    (2)cstring_literals: cstring_literals存储C类型的字符串字面量,
    也就是以空字符\0结尾的字符串,只保留一份实例,所有引用这个字符串的地址重定位到该实例上.
    (3)4byte_literals,8byte_literals, 16byte_literals:与cstring_literals类似,存放4,8,16字节的字面量
    (4)symbol_stubs:由编译器生成,保存未定义的函数的桩代码,一般为动态库中的函数,大小由sizeof_stub指定.
    
    对齐伪指令: .align
    X86_64架构在CPU上,以4,8字节对齐的存取速度最快.
    
    数据类型:
    (1)整形:整形数据的伪指令.byte, .short, .long, .quad,四种,代表1,2,4,8字节,作用相同,只是定义不同长度的数据结构.
    例如:
    .data
    foo: .byte 1, 2, 3, 4
    可以理解为定义了一个byte数组,其中有四个元素,通过 foo 标号引用这个数组.
    (2)浮点型: 有4字节单精度浮点型,和 8字节双精度浮点型,分别用 .single 和 .double 进行定义.
    (3)字符串:  as汇编器提供了两种定义字符串的伪指令, .asciz 用来定义C字符串;另外一种 .ascii 这种会在末尾加 0
    举例:
    .asciz "Hello"
    .ascii "Hello\0"
    .byte 'H', 'e', 'l', 'l',-x6f, 0  //0x6f是小写字母o的ASCII码值.
    
    符号导出伪指令:
    默认情况下一个编译单元(.s文件)中的符号只在本编译单元可见,在其他编译单元和链接器中是无法使用的,如果要使符号对外可见,需要使用globl伪指令(注意globl,不是global)进行导出,
    使用方法:
    .globl     symbol_name//symbol_name就是要导出的符号名,一般为某个函数或变量的标号
    包含头文件的伪指令
    .include  和 C 中的 #include效果相同.
    
    

    12.X86_64汇编基础(Intel 和 AT&T)

    寄存器相关说明

    通用寄存器:
    RSP: 栈指针寄存器--该寄存器用于存放当前任务的栈顶地址
    RBP: 基址指针寄存器--存放高级语言函数调用中栈帧的基地址
    RIP: 指令指针寄存器--存放CPU将要执行的下一条指令的地址(在32位汇编代码中无法使用)
    REFLAGS: 标志寄存器--存储着一组影响CPU行为的标志,指示上一条指令的执行状态.

    image.png

    其他寄存器:
    浮点寄存器
    段寄存器
    MMX寄存器
    SSE寄存器
    AVX寄存器
    控制寄存器
    调试寄存器

    13.汇编语法

    lab1: mov rax,123 #将rax寄存器赋值为123
    一条汇编指令包含5个部分
    lab1 : 指令的标号
    mov : 助记符,也就是执行的操作,
    rax 和 123,是mov指令需要的两个操作数,
    
    操作数分为三类:立即数,寄存器 或 内存;
    X86_64汇编不支持两个操作数都是内存操作数,
    目标操作数(这里的rax,这个操作数就是寄存器)也不可以是立即数,
    
    内存寻址:
    如何让让指令知道要操作的内存的地址以及大小;内存寻址方式有6种;
    size ptr [address]
    size表示该操作数的大小,
    可以是byte(1字节), word(2字节),  dword(4字节), qword(8字节)
    address则有6种表达方式
    (1)立即寻址: 0x123456  直接跟一个内存地址
    (2)寄存器间接寻址: address部分为一个寄存器,寄存器中保存着操作数的内存地址
    (3)寄存器相对寻址: 寄存器间接寻址的基础上加一个立即数,
    例如: byte ptr [rax + 0x100]
    (4)基址加变址寻址:  byte ptr [rax + rbx],或者 byte ptr [rax + rbx * 8]
    (5)相对基址加变址寻址:在(4)的基础上增加一个偏移量,
    例如:byte ptr [rax + rbx * 8 - 0x1234] 
    (6)在X86_64中新增一种基于RIP寄存器相对寻址,这种寻址方式就是address部分为RIP加上一个偏移量,
    例如byte ptr [rip + 0x1234]
    
    操作数大小确定的情况下可以不写 size ptr,内存操作数的大小可以确定
    例如mov rax ,qword ptr [rbx],可以简写成 mov rax ,[rbx],
    mov [rbx] ,1 这种写法是错误的,因为编译器无法确定目标操作数的大小
    
    address部分如果有偏移量,可以将偏移量写在外面
    例如 mov rax,qword ptr [rax + rbx * 8 + 0x1234],可以写成
    mov rax,qword ptr 0x1234[rax + rbx * 8]
    
    lea指令用于计算第二个操作数的有效地址,并将它存储到第一个操作数中,,例如:
    lea rax ,qword ptr [rax + rbx * 8 + 0x1234]
    这条指令会将 rax + rbx * 8 + 0x1234 的计算结果 存储到RAX寄存器中
    

    14.AT&T 与 Intel汇编差异

    1.AT&T使用立即数前面加  $, $123,Intel中:123,
    
    2.AT&T使用寄存器前面加 % , %rax,
    
    3.AT&T助记符之后需要增加一个单独的字符串来表示操作数的大小,
    比如mov 1,2,4,8字节的操作数时对应 movb, movw, movl , movq
    
    4.AT&T语法中源操作数和目标操作数与Intel语法位置相反,
    比如Intel中将RAX寄存器赋值为123,写法为 mov eax,123,
    在AT&T需要写成movq $123, %rax
    
    //这段我没看懂~
    5.AT&T语法中内存操作数的格式也与Intel语法不同,
    比如:mov byte ptr [rax + rbx * 4 + 0x1234],
    0x56对应的是AT&T格式为movb $0x56,0x1234(%rax,%rbx,4),mov byte ptr [rax + rbx],
    0x12对应的是AT&T格式为 movb $0x12,(%rax,%rbx)
    

    15.数据传送指令 mov/xchg

    mov: 将数据从一个操作数复制到另一个操作数,
    xchg: 将两个操作数交换,如果某个操作数是内存地址,xchg会对总线进行加锁,保证原子性.
    源操作数 和 目标操作数 不能同时为内存地址

    16.控制转移指令

    image.png

    1.跳转指令会将RIP设置为操作数所指定的地址,即CPU会从操作数所指定的地址处继续执行;
    2.jmp不执行任何判断,直接将RIP设置为操作数指定的地址,而其他跳转指令则会根据条件进行判断,符合才会设置RIP
    3.call指令相当于将RIP寄存器压入堆栈,然后跳转到操作数指定的地址,
    ret指令则是从栈中弹出一个值,并将这个值作为地址跳转过去

    17.栈操作指令

    一个程序运行时的内存一般可简单划分为,
    代码区:存放程序的代码
    静态数据区:存放静态变量,全局变量
    动态数据区: 堆/栈,malloc函数申请的内存都位于堆区,使用局部变量和函数参数位于栈上.

    18.运算指令

    相关文章

      网友评论

          本文标题:<> 二

          本文链接:https://www.haomeiwen.com/subject/jeyzyktx.html