luckfollowme arm学习篇(10) ---- Gas Directive

查看 34|回复 1
作者:2016976438   
luckfollowme arm学习篇(10) ---- Gas Directive
这篇主要是理解 gas assembly 指令指示符。 并手写 gas 汇编文件并与 c/c++ 交互
(感谢大家支持,我的被标记精华了,哈哈哈~)
大概在有几章就结束了,没有啥资料可以学了。
gas 指令指示符
我们修改上一章的代码,在之前的代码中 加入 全局变量 。
#include
#include "stdint.h"
// 测试全局变量 的 int64 和 string 类型
uint64_t glob_num = 100;
const char* glob_str = "sum:%d\n";
int add(int a,int b){
    return a + b + glob_num;
}
int main(int argc, char const *argv[])
{
    while (1)
    {
        int a = 10;
        int b = 30;
        int sum = add(a,b);
        printf(glob_str,sum);
        getchar();
    }
    /* code */
    return 0;
}
生成 assembly
        .text
        .file        "HelloAssembly.c"
        .globl        add                             // -- Begin function add
        .p2align        2
        .type        add,@function
add:                                    // @add
        .cfi_startproc
// %bb.0:
        sub        sp, sp, #16
        .cfi_def_cfa_offset 16
        str        w0, [sp, #12]
        str        w1, [sp, #8]
        ldr        w8, [sp, #12]
        ldr        w9, [sp, #8]
        add        w9, w8, w9
        adrp        x8, glob_num
        ldr        x8, [x8, :lo12:glob_num]
        add        x8, x8, w9, sxtw
        mov        w0, w8
        add        sp, sp, #16
        ret
.Lfunc_end0:
        .size        add, .Lfunc_end0-add
        .cfi_endproc
                                        // -- End function
        .globl        main                            // -- Begin function main
        .p2align        2
        .type        main,@function
main:                                   // @main
        .cfi_startproc
// %bb.0:
        sub        sp, sp, #48
        stp        x29, x30, [sp, #32]             // 16-byte Folded Spill
        add        x29, sp, #32
        .cfi_def_cfa w29, 16
        .cfi_offset w30, -8
        .cfi_offset w29, -16
        stur        wzr, [x29, #-4]
        stur        w0, [x29, #-8]
        str        x1, [sp, #16]
        b        .LBB1_1
.LBB1_1:                                // =>This Inner Loop Header: Depth=1
        mov        w8, #10
        str        w8, [sp, #12]
        mov        w8, #30
        str        w8, [sp, #8]
        ldr        w0, [sp, #12]
        ldr        w1, [sp, #8]
        bl        add
        str        w0, [sp, #4]
        adrp        x8, glob_str
        ldr        x0, [x8, :lo12:glob_str]
        ldr        w1, [sp, #4]
        bl        printf
        bl        getchar
        b        .LBB1_1
.Lfunc_end1:
        .size        main, .Lfunc_end1-main
        .cfi_endproc
                                        // -- End function
        .type        glob_num,home.php?mod=space&uid=245521                // @glob_num
        .data
        .globl        glob_num
        .p2align        3
glob_num:
        .xword        100                             // 0x64
        .size        glob_num, 8
        .type        .L.str,@object                  // @.str
        .section        .rodata.str1.1,"aMS",@progbits,1
.L.str:
        .asciz        "sum:%d\n"
        .size        .L.str, 8
        .type        glob_str,@object                // @glob_str
        .data
        .globl        glob_str
        .p2align        3
glob_str:
        .xword        .L.str
        .size        glob_str, 8
        .ident        "Android (8490178, based on r450784d) clang version 14.0.6 (https://android.googlesource.com/toolchain/llvm-project 4c603efb0cca074e9238af8b4106c30add4418f6)"
        .section        ".note.GNU-stack","",@progbits
debug 信息
在生成的 assembly 中,经过我的测试,有几项指令应该是 用于调试 debug 使用的
.file 指令 应该表示汇编的文件
.cfi_指令cfi_ 开头的指令貌似用于描述 stack frame 栈帧信息,比较常见的就是
.cfi_startproc 方法的开始
.cfi_endproc 方法的结束
.cfi_def_cfa_offset 栈偏移
.cfi_endproc 栈结束
.section 描述段信息
.ident 构建信息
当然我测过了的,它们可以删除,删除后的样子如下:
        .text
        .globl        add                             // -- Begin function add
        .p2align        2
        .type        add,@function
add:                                    // @add
// %bb.0:
        sub        sp, sp, #16
        str        w0, [sp, #12]
        str        w1, [sp, #8]
        ldr        w8, [sp, #12]
        ldr        w9, [sp, #8]
        add        w9, w8, w9
        adrp        x8, glob_num
        ldr        x8, [x8, :lo12:glob_num]
        add        x8, x8, w9, sxtw
        mov        w0, w8
        add        sp, sp, #16
        ret
.Lfunc_end0:
        .size        add, .Lfunc_end0-add
                                        // -- End function
        .globl        main                            // -- Begin function main
        .p2align        2
        .type        main,@function
main:                                   // @main
// %bb.0:
        sub        sp, sp, #48
        stp        x29, x30, [sp, #32]             // 16-byte Folded Spill
        add        x29, sp, #32
        stur        wzr, [x29, #-4]
        stur        w0, [x29, #-8]
        str        x1, [sp, #16]
        b        .LBB1_1
.LBB1_1:                                // =>This Inner Loop Header: Depth=1
        mov        w8, #10
        str        w8, [sp, #12]
        mov        w8, #30
        str        w8, [sp, #8]
        ldr        w0, [sp, #12]
        ldr        w1, [sp, #8]
        bl        add
        str        w0, [sp, #4]
        adrp        x8, glob_str
        ldr        x0, [x8, :lo12:glob_str]
        ldr        w1, [sp, #4]
        bl        printf
        bl        getchar
        b        .LBB1_1
.Lfunc_end1:
        .size        main, .Lfunc_end1-main
                                        // -- End function
        .type        glob_num,@object                // @glob_num
        .data
        .globl        glob_num
        .p2align        3
glob_num:
        .xword        100                             // 0x64
        .size        glob_num, 8
        .type        .L.str,@object                  // @.str
.L.str:
        .asciz        "sum:%d\n"
        .size        .L.str, 8
        .type        glob_str,@object                // @glob_str
        .data
        .globl        glob_str
        .p2align        3
glob_str:
        .xword        .L.str
        .size        glob_str, 8
add
我们先来分析 add 方法 以及它用到的指令
截取出来是这样的
        .text
        .globl        add                             // -- Begin function add
        .p2align        2
        .type        add,@function
add:                                    // @add
// %bb.0:
        sub        sp, sp, #16
        str        w0, [sp, #12]
        str        w1, [sp, #8]
        ldr        w8, [sp, #12]
        ldr        w9, [sp, #8]
        add        w9, w8, w9
        adrp        x8, glob_num
        ldr        x8, [x8, :lo12:glob_num]
        add        x8, x8, w9, sxtw
        mov        w0, w8
        add        sp, sp, #16
        ret
.Lfunc_end0:
        .size        add, .Lfunc_end0-add        
我们依次从上往下分析
text section
.text 表示代码开始的 代码段
global symbol
.global 代表声明全局符号 可提供外部使用
.globl        add    代表定义 add 的全局symbol
p2align
表示内存对齐
p2align        2 表示对齐 2*2 = 4 字节的内存
.type
定义符号类型
.type        add,home.php?mod=space&uid=1435519表示 add symbol 是一个 方法
add arm
接下来是分析 当中的 arm 汇编。里面存在 伪指令引用 全局符号 glob_num 看我的注释意思即可
add:                                 
        # 开辟局部变量的栈空间
        sub        sp, sp, #16
        # 将 a 和 b 的参数 放入 栈空间
        str        w0, [sp, #12]
        str        w1, [sp, #8]
        # 获取 a 和 b
        ldr        w8, [sp, #12]
        ldr        w9, [sp, #8]
        # a + b
        add        w9, w8, w9
        # 伪指令 获取基于 pc + glob_num 的 4kb 内存页对齐
        adrp        x8, glob_num
        #  :lo12: 表示取 低12位内的glob_num地址  也就是4kb内的偏移
        ldr        x8, [x8, :lo12:glob_num]
        # 将 glob_num + a + b  (sxtw 表示 x8 转 w8 也就是 word 32 位)
        add        x8, x8, w9, sxtw
        # 剩下就是 返回值 和 恢复栈了
        mov        w0, w8
        add        sp, sp, #16
        ret
对应 c 的代码:
int add(int a,int b){
    return a + b + glob_num;
}
方法结束
.Lfunc_end0: 表示结束方法的标签,这个标签名字可以自定义
.size 表示这个方法的大小
.Lfunc_end0:
        # add 方法的大小 = Lfunc_end0 - add开始地址
        .size        add, .Lfunc_end0-add
main
至于 main 方法 指令都见过,我就直接分析了
        # 定义main symbol
        .globl        main                            // -- Begin function main
        # 4 字节 内存对齐
        .p2align        2
        # main symbol 类型是 方法
        .type        main,@function
main:                                   // @main
        # 分配栈空间
        sub        sp, sp, #48
        # x29(FP) x30(LR) 入栈 方法结束时候恢复
        stp        x29, x30, [sp, #32]             // 16-byte Folded Spill
        # 表示 x29 以栈低开始
        add        x29, sp, #32
        # wzr(zero) 用于清零 [x29 - 4] = 0
        stur        wzr, [x29, #-4]
        # [x29 -8] = w0
        stur        w0, [x29, #-8]
        # [sp + 16] = x1
        str        x1, [sp, #16]
        # 跳入死循环
        b        .LBB1_1
.LBB1_1:                                // =>This Inner Loop Header: Depth=1
        # a = 10
        mov        w8, #10
        str        w8, [sp, #12]
        # b = 30
        mov        w8, #30
        str        w8, [sp, #8]
        # add方法 传参 a  b
        ldr        w0, [sp, #12]
        ldr        w1, [sp, #8]
        # 调用 add
        bl        add
        # w0 = 返回值
        str        w0, [sp, #4]
        # 获取 glob_str 4kb 内存页地址
        adrp        x8, glob_str
        # printf方法 传参
        # 获取 glob_str 低12(4kb 内) 位的偏移
        ldr        x0, [x8, :lo12:glob_str]
        # add方法 返回值
        ldr        w1, [sp, #4]
        bl        printf
        bl        getchar
        # 重复循环
        b        .LBB1_1
.Lfunc_end1:
        # main 方法结束 size = Lfunc_end1-main
        .size        main, .Lfunc_end1-main
全局变量
定义全局变量一般格式为:
        # 符号类型为 @object        
        .type        符号,@object        
        # 数据段 还有一个就是 text 代码段
        .data
        # 全局符号
        .globl        glob_num
        # 内存对齐 看数据长度
        .p2align        3
glob_num
        # glob_num 符号是 对象类型
        .type        glob_num,@object                // @glob_num
        # 数据段
        .data
        # 定义 glob_num 全局符号
        .globl        glob_num
        # 2^3 = 8 字节内存对齐
        .p2align        3
        # glob_num 符号的数据定义
glob_num:
        # 使用 64 位 整数 值是 100
        # 当然还有 个 word 是 32位
        .xword        100                             // 0x64
        # 数据大小是 8字节
        .size        glob_num, 8
glob_str
这个比较麻烦了,因为它是个字符串。
# 定义本地标签数据段 不会被外部引用
.L.str:
        # ascii 字符串数据
        .asciz        "sum:%d\n"
        # 长度是8
        .size        .L.str, 8
    # 定于 glob_str 符号类型是 @object
        .type        glob_str,@object                // @glob_str
        # 数据段
        .data
        # 全局 symol
        .globl        glob_str
        # 8 字节对齐
        .p2align        3
glob_str:
        # 引用 .L.str 数据
        .xword        .L.str
        #  长度是 8
        .size        glob_str, 8
到这里分析就差不多了。接下来我们就尝试手动写 add assembly 方法,并提供给 c/c++ 使用
手写 gas 文件
为了方便,您先下载 gnu assembler 插件 可以帮助您完成部分 intellSence
首先我创建一个 assembly_add.S 的 gas 汇编文件
并写入 add 方法的汇编
    .text
    .globl add
    .p2align 2
    .type add,@function
add:
    sub sp,sp,#16
    // 第一个参数
    str w0,[sp,#12]
    // 第二个参数
    str w1,[sp,#8]
    ldr w0,[sp,#12]
    ldr w1,[sp,#8]
    // a + b
    add w0,w0,w1
    // 还原栈
    add sp,sp,#16        
    ret
.Lfunc_end0:
    //方法结束 size = 当前 - add
    .size add, .-add   
在写个 assembly_add_demo1.cpp
#include "stdio.h"
// extern C 表示方法是标准C的
// 且 方法是从外部链接过来的
extern "C"{
    int add(int a,int b);
}
int main(int argc, char const *argv[])
{
    int a = 99;
    int b = 1;
    int ret = add(a,b);
    printf("ret:%d",ret);
    return 0;
}
接下来在 CMakeLists.txt 中加入如下片段:
set(assmbly_add_demo1
    ./source/assembly/assembly_add.S
    ./source/assembly/aseembly_add_demo1.cpp
)
# 测试 gas 汇编文件与 c++ 交互
add_executable(assmbl-add-demo1 ${assmbly_add_demo1})
然后修改 ndb_builder.pyadb_execute_arm64.bat 方法进行构建和运行
至此,您已经会 如何在 c/c++ 中写 arm
下一章就开始讲解手写 inline hook

方法, 指令

debug_cat   

学习进度跟不上了
您需要登录后才可以回帖 登录 | 立即注册

返回顶部