Code Monkey home page Code Monkey logo

learn_asm's Introduction

learn asm

参考:

os: linux x86_64

asm语法

参考:

x86有两个流行的汇编方言版本:Intel/Microsoft和AT&T/Linux. AT&T语法是一种相当老的语法,由GAS和一些老式汇编器使用;NASM使用Intel语法,大多数汇编器都支持intel语法, 比如TASM和MASM. 但GAS的现代版本(from v2.10+)已支持.intel_syntax指令,即允许在GAS 中使用Intel语法.

我使用英特尔语法的部分原因还有它将目的地放在左边,而源操作数放在右边,与RISC-V,ARM-32和MIPS-32的操作数顺序一致.

使用intel语法的相关改变:

  • gas : 开头加.intel_syntax noprefix ;不需要寄存器的前缀%
  • gcc : gcc -masm=intel test.c -o test // -masm = intel用于编译包含Intel语法内联汇编的源文件
  • objdump : objdump -M intel -d program_name, // 我通常使用更详细的objdump -M x86-64,intel,intel-mnemonic,intel64 -d program_name
  • 内联汇编: 参考这里

具体AT&T汇编和Intel汇编差异这里.

指令集

64 bit汇编

参考:

  1. 用户模式的系统调用依次传递的寄存器为: rdi,rsi,rdx,rcx,r8和r9
  2. 内核接口的系统调用一次传递的寄存器为: rdi,rsi,rdx,r10,r8和r9. 注意这里和用户模式的系统调用只有第4个寄存器不同,其他都相同
  3. 系统调用通过syscall指令进入,不像32位下的汇编使用的是int 0x80指令;
  4. 系统调用号放在rax寄存器里
  5. 系统调用限制最多6个参数
  6. 系统调用的返回结果,也就是syscall指令的返回放在rax寄存器中
  7. 只有整形值和内存型的值可以传递给内核

Linux 32位系统调用和64位系统调用的区别

参考:

  • *Linux syscall过程分析

  • *Linux 系统调用权威指南(2016) 翻译自The Definitive Guide to Linux System Calls

  • 系统调用号(syscall)不同

    参考:

    比如:

    • x84 sys_init(0x01) : eax = 0x01, ebx = int error_code
    • x86_64 sys_init(0x3c) : rax = 0x3c, rdi = int error_code

    手写汇编代码来发起系统调用并不是一个好主意. 其中一个重要原因是,glibc 中有 一些额外代码在系统调用之前或之后执行(而自己写的汇编代码没有做这些类似的工作). 同时内核的 ABI 可能会有不兼容更新. 而内核和 libc 实现通常(可能)会为每个系统自动选择最快的系统调用方式, 以避免出问题.

    比如使用 exit 系统调用: 事实上可以用 atexit函数向 exit 注册 回调函数,在它退出的时候就会执行. 这些函数是从 glibc 里调用的,而不是内核. 因此,如果自己写的汇编代码调用 exit,那注册的回调函数就不会被执行,因为这种方 式绕过了 glibc.

    然而,徒手写汇编来调系统调用是一次很好的学习方式.

  • 调用方法不同

    在32位下用int 0x80中断(是软中断, 对应中断函数是ia32_syscall@arch/x86/ia32/ia32entry.S)进行系统调用,而64位下需要用syscall指令进行系统调用

    64bit的syscall是为了加速系统调用所引入的新指令,通过引入新的 MSR 来存放内核态的代码和栈的段号和偏移量,从而实现快速跳转.

    在x86_64上使用int 0x80会导致发生segfault(原因: 变量地址是64bit, 用0x80号中断调用时仅用到32bit地址, 高32bit丢失, 导致内存访问时地址越界). syscall可参考这里.

    调用error说明(保存在rax中):

    • /usr/include/asm-generic/errno-base.h
    • /usr/include/asm-generic/errno.h
  • 传参方式不同(即ABI)

    32位程序,我们将系统调用号传入eax,调用参数压栈传递,系统调用返回值写入eax寄存器; 而64位程序,系统调用号传入rax,而各个参数按照rdi,rsi,rdx,rcx, r8, r9的顺序写入寄存器,系统调用返回值写入rax.

    见example的cpuid*.s的例子.

risc-v资料收集

相关书单

  • <<深入理解程序设计使用Linux汇编语言>> : 不推荐, 内容是32-bit汇编
  • <<x86/x64体系探索及编程>>, 推荐

learn_asm's People

Contributors

meilihao avatar

Watchers

 avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.