天天看点

现代汇编语言现代汇编学习objconv 工具x86汇编nasmarmv8汇编系统调用库Linux 常识

文章目录

  • 现代汇编学习
    • 汇编语言类型
    • 汇编器
      • 汇编器列表
      • 汇编器都干了什么
    • 链接器
    • ld(链接器)
      • linker script
    • 加载器
    • 可执行文件格式
  • objconv 工具
  • x86汇编
    • AT&T语法
      • 函数定义
    • AVX,SSE指令
    • x64 寄存器
    • calling conv
      • ia32
    • 函数调用
      • stack unwinding
    • return value
  • nasm
    • nasm命令
    • gas
    • Hello world
  • armv8汇编
    • linux 查看CPU信息的寄存器
    • 常见的名词
    • 寄存器
      • armv7和aarch32
      • aarch64
    • calling conv
    • 寻址方式
    • arm嵌入汇编
      • 加法例子
  • 系统调用
    • x86 再来一遍calling convention
  • Linux 常识

本篇文章介绍汇编,链接等常识,同时介绍了x86-64和armv8-a的一些指令语法

现代汇编学习

之前学的

80x86

汇编太古老了,甚至连第一版

linux kernel

代码都看不懂,现在整理一下一些汇编知识,主要是针对

x86

armv8-a

架构的,但是本文并不会教具体的指令长什么样,也不会阐述怎么写一个通用汇编代码。学习汇编本身不是我们的终极目的。我们的目的是为了更好开发软件或者高性能库,因此会介绍一下编译,链接的原理和流程。

汇编语言类型

  • AT&T
    • 是这个实验室提出的一种语法,注意它和指令集是没关系的,仅仅是一种语法而已。
    • 对于x86处理器,立即数由

      $

      ,寄存器由

      %

      引用。
    • 对于arm处理器,直接使用arm官方的语言格式。
  • intel
    • 本科会学到的一种语言格式,x86汇编
    • 简单,易用
  • 汇编器的作用是把汇编语言翻译成机器语言,所以不同的汇编语言可能会使用不同的汇编器。他们的机器语言即指令。
  • GAS 汇编器可以汇编x86的汇编语言,也可以汇编arm。
  • Intel assembler 只能汇编 intel的汇编语言,就像icc。

汇编器

汇编器列表

  • AT&T assembler - as
  • Borland’s Turbo Assembler - TASM
  • GNU assembler - gas,GCC默认使用这个
  • Intel Assembler
  • Microsoft Assembler - MASM
  • Netwide Assembler - NASM
  • Yet Another Assembler - YASM

x86 gas语法

汇编器简短比较

汇编器都干了什么

  • 汇编器负责把当前源文件的所有变量,常量,宏,

    label

    解析等等并且生成相应的符号表(这时候的解析是初步的,符号表是不完整的,后续工作链接器会接手),所谓解析就是确定他们的地址。这些地址都是基于本模块计算出来的相对地址,绝对地址的计算需要到链接阶段才能做。
  • 汇编器的输出是目标文件
Assembling:
- Assembling converts source program into object program if syntactically correct and
generates an intermediate .obj file or module.
- It calculates the offset address for every data item in data segment and every
instruction in code segment.
- A header is created which contains the incomplete address in front of the generated obj
module during the assembling.
- Assembler complains about the syntax error if any and does not generate the object
module.
- Assembler creates .obj .lst and .crf files and last two are optional files that can be
created at run time.
- For short programs, assembling can be done manually where the programmer translates
each mnemonic into the machine language using lookup table.
- Assembler reads each assembly instruction of a program as ASCII character and
translates them into respective machine code.
           
  • 符号表实际上就是用于链接器定位每个目标文件的变量和函数信息比如汇编中重要的三个节

    .bss .data .text

  • 在汇编语言源代码可以调用外部文件的函数,就像C语言调用库函数一样。汇编器对这些函数或者变量无法进行地址计算。这些活由链接器干。
  • c 语言中 加了static的函数不会出现在 global section

  • 目标文件的三种类型(来自CSAPP:chapter 7)
    • Relocatable object file. Contains binary code and data in a form that can be combined with other relocatable object files at compile time to create an executable object file.
    • Executable object file. Contains binary code and data in a form that can be copied directly into memory and executed.
    • Shared object file. A special type of relocatable object file that can be loaded into memory and linked dynamically, at either load time or run time.
  • nm

    工具可以查看某个目标文件的符号(

    readelf和objdump

    都可以看符号表)
    • nm -gD yourLib.so
      
      objdump -TC 也可以(C用于c++)
      
      readelf -Ws
                 
  • 一个简单的例子:
...
int x = 0;
int y = -1;
y = x;
...
           

上面这个片段定义了两个全局标号

x y

,这两个标号实际上是一个地址,但是我们在C语言引用的时候实际上是引用值而不是地址。只有

y = &x

这个语句的含义才是将

x

这个标号的值(即

x

的地址)赋给

y

y = x

这个语句实际上会被编译成

mov eax,[x]
mov dword[y],eax
           

链接器

  • 链接器负责进一步解析所有的符号,函数名,(根据每个目标文件的符号表)把所有的目标文件链接成一个最终的可执行文件。链接器收集所有目标文件的符号表信息,合并同类的段(比如不同目标文件的代码段,数据段)等工作。最终可执行文件的符号表是完整的。
    • 比如两个.o文件都定义了函数

      void foo()

      ,这时候链接器需要判断哪个是需要被采用的
    • 在.o文件中没有在

      global

      中的函数是无法被其他.o文件调用的,实际上在汇编阶段不会出现在符号表,因此链接器也无法使用。(这些函数就是在

      c

      中加了

      static

      修饰符的变量)
This involves the converting of .OBJ module into .EXE(executable) module i.e.
executable machine code.
- It completes the address left by the assembler. 
Microprocessors lecture 5: Programming with 8086 Microprocessor
- It combines separately assembled object files.
- Linking creates .EXE, .LIB, .MAP files among which last two are optional files. 
           

链接器负责把全部的符号解析成最终的地址。它负责解析所有的符号。

  • ld

    即一个链接器
  • 命令

    readelf

    很有用
  • 链接
    • static linking

      现代汇编语言现代汇编学习objconv 工具x86汇编nasmarmv8汇编系统调用库Linux 常识
    • dynamic linking

    • runtime linking

    参考1

    quaro参考

  • 更详细的参考另外的md文件

ld(链接器)

  • 如果希望兼容32位的elf输出,这里需要使用

    -m

    选项
    ld -m elf_i386 -s -o file file.o
               

linker script

链接脚本是链接器使用的。脚本中会指定某些默认行为,比默认链接的一些标准库,比如可执行文件的入口地址。

加载器

  • loader通常由shell进程负责唤起,它将可执行文件的代码加载到内存。
It Loads the program in memory for execution.
- It resolves remaining address.
- This process creates the program segment prefix (PSP) before loading.
- It executes to generate the result. 
           

可执行文件格式

  • 常用的有ELF:executable and linkable format
    bin       flat-form binary files (e.g. DOS .COM, .SYS)
        ith       Intel hex
        srec      Motorola S-records
        aout      Linux a.out object files
        aoutb     NetBSD/FreeBSD a.out object files
        coff      COFF (i386) object files (e.g. DJGPP for DOS)
        elf32     ELF32 (i386) object files (e.g. Linux)
        elf64     ELF64 (x86_64) object files (e.g. Linux)
        elfx32    ELFX32 (x86_64) object files (e.g. Linux)
        as86      Linux as86 (bin86 version 0.3) object files
        obj       MS-DOS 16-bit/32-bit OMF object files
        win32     Microsoft Win32 (i386) object files
        win64     Microsoft Win64 (x86-64) object files
        rdf       Relocatable Dynamic Object File Format v2.0
        ieee      IEEE-695 (LADsoft variant) object file format
        macho32   NeXTstep/OpenStep/Rhapsody/Darwin/MacOS X (i386) object files
        macho64   NeXTstep/OpenStep/Rhapsody/Darwin/MacOS X (x86_64) object files
        dbg       Trace of all info passed to output stage
        elf       ELF (short name for ELF32)
        macho     MACHO (short name for MACHO32)
        win       WIN (short name for WIN32)
               

objconv 工具

  • objconv -fnasm main.o

    把目标文件反汇编成指定格式的汇编语言

x86汇编

  • .set symbol,expression

    ,把符号设为具体的值

AT&T语法

  • 指令可能会加后缀表示操作数的宽度
    • “byte” refers to a one-byte integer (suffix b)
    • “word” refers to a two-byte integer (suffix w),
    • “doubleword” refers to a four-byte integer (suffix l), and
    • “quadword” refers to an eight-byte value (suffix q).
  • MOV:

    movl,movw,movb,movq

    .(32,16,8,64)一般如果没有后缀那就是默认的长度。
mov 基本指令
如果用到扩展,mov还会有s(signed),z(zero)的后缀,
movzbl %al,%ebx 表示对al寄存器(8-bit)进行zero扩展放到ebx(64-bit)
           
mov 内存寻址方式segment:displacement(base register, index register, scale factor)
即segment:[base register + displacement + index register * scale factor]

movzwl (%rdx,%rax,2),%edx  
           

函数定义

  • .type start, @function

    表示将符号start定义成一个函数标号

AVX,SSE指令

指令参考1

x64 寄存器

现代汇编语言现代汇编学习objconv 工具x86汇编nasmarmv8汇编系统调用库Linux 常识
  • There are sixteen 64-bit registers in x86-64: %rax, %rbx, %rcx, %rdx, %rdi, %rsi, %rbp, %rsp, and %r8-r15. Of these, %rax, %rcx, %rdx, %rdi, %rsi, %rsp, and %r8-r11 are considered caller-save registers, meaning that they are not necessarily saved across function calls. By convention, %rax is used to store a function’s return value, if it exists and is no more than 64 bits long. (Larger return types like structs are returned using the stack.) Registers %rbx, %rbp, and %r12-r15 are callee-save registers, meaning that they are saved across function calls.Register**%rsp **is used as the stackpointer, a pointer to the top most element in the stack.

calling conv

  • X64 和 ia32的参数传递有所不同,后者使用栈(系统调用会使用寄存器),前者会使用寄存器以及栈
  • windows和linux参数传递也不同

###x64

  • linux和OS X: %rdi, %rsi, %rdx, %rcx, %r8, and %r9 are used to pass the first six integer or pointer parameters to called functions. Additional parameters (or large parameters such as structs passed by value) are passed on the stack.
    ;Example function call:
    extern putchar
    mov rdi,'H' ; function parameter: one char to print
    call putchar
               
  • windows则不同
    • Win64 function parameters go in registers rcx, rdx, r8, and r9.
    • Win64 functions assume you’ve allocated 32 bytes of stack space to store the four parameter registers, plus another 8 bytes to align the stack to a 16-byte boundary.
      sub rsp,32+8; parameter area, and stack alignment
      extern putchar
      mov rcx,'H' ; function parameter: one char to print
      call putchar
      add rsp,32+8 ; clean up stack
                 
    • Win64 treats the registers rdi and rsi as preserved.

ia32

  • 对于常见的C++程序,像缺省_cdecl或使用_stdcall的函数压栈顺序都是采用的从右往左压栈的
    void fun(int a, int b)
    则b先入栈,a后入栈
               
  • In 32-bit x86, the base pointer (formerly %ebp, now %rbp) was used to keep track of the base of the current stack frame, and a called function would save the base pointer of its caller prior to updating the base pointer to its own stack frame. With the advent of the 64-bit architecture, this has been mostly eliminated, save for a few special cases when the compiler cannot determine ahead of time how much stack space needs to be allocated for a particular function (see Dynamic stack allocation).

    in 32 bit mode, parameters are passed by pushing them onto the stack in reverse order, so the function’s first parameter is on top of the stack before making the call. In 32-bit mode Windows and OS X compilers also seem to add an underscore before the name of a user-defined function, so if you call a function foo from C/C++, you need to define it in assembly as “_foo”.

  • “Scratch” registers you’re allowed to overwrite and use for anything you want,“Preserved” registers serve some important purpose somewhere else, so you have to put them back (“save” the register) if you use them.

函数调用

现代汇编语言现代汇编学习objconv 工具x86汇编nasmarmv8汇编系统调用库Linux 常识
  • 注意参数的压栈动作是在caller 程序里面的,这些都是一些convention,不是硬件实现的,是由软件 即程序员实现的。
  • 发生函数调用时,caller按照convention, 将

    caller saved

    (即scratch register)压入栈,然后负责压参数 , 调用call指令,call指令会自动push返回地址。jmp到callee内部,第一件事是保存ebp到栈顶, 然后callee负责将

    callee saved

    寄存器压入栈。退出的时候是调用者负责清理参数

一个栈帧看起来应当是

现代汇编语言现代汇编学习objconv 工具x86汇编nasmarmv8汇编系统调用库Linux 常识

当然,在

x64

里,可能没有参数入栈。如果使用寄存器传参,在子程序内应当将这些寄存器的值先入栈,否则后面没法使用这些值

下图展示

armv8

函数的参数入栈顺序

void test_para(int a0, int a1, int a2, int a3, int a4,int a5,int a6, int a7,int a8,int a9,int a10,int a11, a12);  

//调用
test_para(0,1,2,3,4,5,6,7,8,9,10,11,12);
           
现代汇编语言现代汇编学习objconv 工具x86汇编nasmarmv8汇编系统调用库Linux 常识

stack unwinding

stkoverflow

return value

  • x86的返回值通常使用

    RDX:RAX

c struct返回值

nasm

  • nasm由几部分构成(layout)
    • 指令(机器语言助记符)
    • 伪指令:
      • DB

        ,

        DW

        ,

        DD

        ,

        DQ

        ,

        DT

        ,

        DO

        ,

        DY

        and

        DZ

      • RESB

        ,

        RESW

        ,

        RESD

        ,

        RESQ

        ,

        REST

        ,

        RESO

        ,

        RESY

        and

        RESZ

      • INCBIN

        : 包含一个二进制可执行文件
        incbin  "file.dat"             ; include the whole file 
        incbin  "file.dat",1024        ; skip the first 1024 bytes 
        incbin  "file.dat",1024,512    ; skip the first 1024, and actually include at most 512
                   
      • EQU

        : 定义常量。注意

        equ

        实际上等价于C中的宏,在指令中可以认为是立即数,经过汇编后就没有了(被数值替代),而

        db

        是在内存中分配了一个字节,在指令中认为是一个地址,也就是在执行过程中使用地址进行访问。下列定义中message实际上是一个地址(指针)
        message         db      'hello, world' 
        msglen          equ     $-message
                   
      • TIMES

        :用于重复指令或者数据
        zerobuf:        times 64 db 0 ;定义64个byte 全都等于0
        
        buffer: db      'hello, world' 
                times 64-$+buffer db ' ' ;;;实际上buffer和64-$+buffer都只是地址,标号之间可以做数学运算,       
                												 ;;;times有点像是循环这里因为times伪指令$
                												 ;;;这里在buffer后面生命了64个byte
                												 ;;;等价于64条语句 db ' '
                												 
         times 100 resb 1;;;timesk可以搭配指令,效果等价于resb 100,实际上它是重复执行100次指令resb 1
                   
  • Nasm的特点
    • 以点

      .

      开头的标号是本地标号leading dot is NASM’s syntax for making local labels
    • 寻址方式写成

      mov [ebx + eax * 4 + 1],1

      在gcc下是

      mov 1,1(ebx,eax,4)

  • nasm对于x86几乎是原生格式(intel syntax)
  • 汇编语句(layout):
    • [label] mnemonic [operands] [;comment]

      ,其中

      mnemonic

      包含两部分,assembler directives and instructions
    • 下图是64-bit的代码划分
    现代汇编语言现代汇编学习objconv 工具x86汇编nasmarmv8汇编系统调用库Linux 常识
  • section定义 以

    .

    开头的section是预定义好的,其属性是已经定义好的。
  • 数据定义:这部分出现在

    .bss

    或者

    data

    • message: db "Hello, World", 10

      则定义了一个字符串,在指令中就可以使用

      messege

      作为操作数了
    • 可以在

      .bss

      节预留空间不初始化使用

      res

      指令
      buffer:         resb    64              ; reserve 64 bytes
      wordvar:        resw    1               ; reserve a word
      realarray:      resq    10              ; array of ten reals
                 
db    0x55                ; just the byte 0x55
      db    0x55,0x56,0x57      ; three bytes in succession
      db    'a',0x55            ; character constants are OK
      db    'hello',13,10,'$'   ; so are string constants
      dw    0x1234              ; 0x34 0x12
      dw    'a'                 ; 0x61 0x00 (it's just a number)
      dw    'ab'                ; 0x61 0x62 (character constant)
      dw    'abc'               ; 0x61 0x62 0x63 0x00 (string)
      dd    0x12345678          ; 0x78 0x56 0x34 0x12
      dd    1.234567e20         ; floating-point constant
      dq    0x123456789abcdef0  ; eight byte constant
      dq    1.234567e20         ; double-precision float
      dt    1.234567e20         ; extended-precision float
           
  • 常数写法

后缀

H

or

X

,

D

or

T

,

Q

or

O

, and

B

or

Y

分别是 hexadecimal, decimal, octal and binary respectively,

16进制前缀

0x

or

$0

mov     ax,200          ; decimal 
        mov     ax,0200         ; still decimal 
        mov     ax,0200d        ; explicitly decimal 
        mov     ax,0d200        ; also decimal 
        mov     ax,0c8h         ; hex 
        mov     ax,$0c8         ; hex again: the 0 is required 
        mov     ax,0xc8         ; hex yet again 
        mov     ax,0hc8         ; still hex 
        mov     ax,310q         ; octal 
        mov     ax,310o         ; octal again 
        mov     ax,0o310        ; octal yet again 
        mov     ax,0q310        ; octal yet again 
        mov     ax,11001000b    ; binary 
        mov     ax,1100_1000b   ; same binary constant 
        mov     ax,1100_1000y   ; same binary constant once more 
        mov     ax,0b1100_1000  ; same binary constant yet again 
        mov     ax,0y1100_1000  ; same binary constant yet again
           

nasm命令

  • nasm -hf

    查看汇编器的支持的输出文件格式
  • 汇编时,使用

    -f

    指定输出文件格式

gas

  • gas directives

64bit很好的学习网站

Hello world

  • 32-bit
section .text
    global _start
;;; write(1, msg, len);
;;; write的系统调用号是4
;;; 参数是edx,ecx,ebx
;;; eax存放系统调用号
_start :
    mov eax,4
    mov edx,len 
    mov ecx,msg
    mov ebx,1
    int 0x80

    mov eax,1
    int 0x80

section .rodata
msg db 'Hello world',0xa;
len equ $ - msg  ; msg的长度
           
nasm -f elf32 hello.as,m -o hello.o && ld -m elf_i386 -o hello
           
  • 64-bit
global    _start

          section   .text
_start:   mov       rax, 1                  ; system call for write
          mov       rdi, 1                  ; file handle 1 is stdout
          mov       rsi, message            ; address of string to output
          mov       rdx, 13                 ; number of bytes
          syscall                           ; invoke operating system to do the write
          mov       rax, 60                 ; system call for exit
          xor       rdi, rdi                ; exit code 0
          syscall                           ; invoke operating system to exit
          
          section   .data
message:  db        "Hello, World", 10      ; note the newline at the end
           

😜

armv8汇编

linux 查看CPU信息的寄存器

Vendor Name Vendor ID
ARM 0x41
Broadcom 0x42
Cavium 0x43
DigitalEquipment 0x44
HiSilicon 0x48
Infineon 0x49
Freescale 0x4D
NVIDIA 0x4E
APM 0x50
Qualcomm 0x51
Marvell 0x56
Intel 0x69
信息存储在寄存器MIDR_EL1
其中从低至高第0-3 bit表示revision,代表固件版本的小版本号,如r1p3中的p3;
第4-15 bit表示part number(id),代表这款CPU在所在vendor产品中定义的产品代码,如在HiSilicon产品中,part_id=0xd01代表Kunpeng-920芯片;
第16-19 bit表示architecture,即架构版本,0x8即ARMv8;
第20-23 bit表示variant,即固件版本的大版本号,如r1p3中的r1;
第24-31 bit表示implementer,即vendor id,如vendor_id=0x48表示HiSilicon

文件夹/sys/devices/system/cpu里面有详细的每个核的信息

寄存器的值如果是
0x00000000481fd010 海思供应商
           
  • arm一个字是32位(single),intel的一个字是16位(word)
  • 字节(B),半字(H),字(S),双字(D)。
  • armv8支持64位的指令(A64),同时支持aarch64和aarch32两种执行状态
  • aarch64是armv8的一种执行状态,aarch32是为了兼容armv7,它是32位指令(A32)的超集。

    armv8-a中的aarch32。从aarch32的寄存器和aarch64之间的寄存器必须有一个映射关系,就像写ia32和

    X86_64的

    ax

    ,

    rax

    ,

    eax

    一样(不同模式不同的映射关系)
  • 无论aarch32以及aarch64,实际上都是在说armv8-a体系结构
  • 问题来了:一个处理器怎么决定自己是aarch64还是aarch32

AArch64 or ARM64 is the 64-bit extension of the ARM architecture.

It was first introduced with the ARMv8-A architecture.

常见的名词

ARM:

现代汇编语言现代汇编学习objconv 工具x86汇编nasmarmv8汇编系统调用库Linux 常识
  • AArch64: AArch64 is the 64-bit execution state of the ARMv8 ISA, A machine in this state executes operates on the A64 instruction set
  • AArch32:32位的运行模式,是ARMv8-a向前兼容的。也就是ARMv8-a有两种执行模式
  • A64:指令集
  • A32:32位指令集
  • ARMv8:体系结构。通常armv8指的是armv8-a.Cortex-A32 是 32-bit ARMv8-A 的CPU,大部分 ARMv8-A都是支持64-bit的。除了armv8-a,实际上还有armv8-r系列,不过这些都是32位的。
  • ISA:In computer science, an instruction set architecture (ISA) is an abstract model of a computer. It is also referred to as architecture or computer architecture. A realization of an ISA, such as a central processing unit (CPU), is called an implementation
  • 微体系架构(microarchitecture)是ISA的一个实现
    • 比方说物理寄存器有多少个,几发射,cache 一致性协议是啥,保留站项数等等
现代汇编语言现代汇编学习objconv 工具x86汇编nasmarmv8汇编系统调用库Linux 常识

寄存器

armv7和aarch32

  • 16个32位通用寄存器 (R0-R15).只用r0-13能使用
    • r14是返回地址,别名

      link register(lr)

      ,
    • r15是pc,可以使用

      mov pc,lr

      用来子程序返回
    • Arm v7是没有sp寄存器的,使用r13代替
  • 向量寄存器:32 个 64-bit 的 (D0-D31),或者16个128位的(Q0-Q15).
    现代汇编语言现代汇编学习objconv 工具x86汇编nasmarmv8汇编系统调用库Linux 常识

aarch64

  • 31 个 64-bit 通用寄存器(X0-X30) 和1个 特殊的寄存器.也可以使用32位模式去访问(W0-W30)
    • x29是frame pointer(在x86里是EBP)
    • x30是LR
    • 和armv7不一样,aarch64有专门的pc寄存器且不允许直接访问pc
  • 32 个 128-bit 向量寄存器 (V0-V31). These registers can also be viewed as 32-bit Sn registers or 64-bit Dn registers.
现代汇编语言现代汇编学习objconv 工具x86汇编nasmarmv8汇编系统调用库Linux 常识
  • aarch64通用寄存器列表
    Register Role Requirement
    X0 - X7 Parameter/result registers Can Corrupt
    X8 Indirect result location register
    X9 - X15 Temporary registers
    X16 - X17 Intra-procedure call temporary
    X18 Platform register, otherwise temporary
    X19 - X29 Callee-saved register Must preserve
    X30 Link Register(函数调用的返回地址) Can Corrupt
  • 通用寄存器映射(mode表示不同的异常状态)
现代汇编语言现代汇编学习objconv 工具x86汇编nasmarmv8汇编系统调用库Linux 常识

calling conv

arm calling convention

现代汇编语言现代汇编学习objconv 工具x86汇编nasmarmv8汇编系统调用库Linux 常识
  • armv8的参数寄存器是

    r0-r7

    ,x64的参数寄存器是

    rdi,rsi,rdx,rcx,r8,r9

    额外的参数都是在栈上(从右边开始压)
  • x8是用来接收返回值的(存放返回地址), 相比之下x86-64用于存放返回值地址的是

    rax

    寄存器

寻址方式

arm寻址方式,32位通用寄存器是是R,64是X

现代汇编语言现代汇编学习objconv 工具x86汇编nasmarmv8汇编系统调用库Linux 常识

其中

base

是寄存器或者是

SP

  • 注意:sp必须是16字节对齐的
  • arm没有push,pop指令,全都post/pre-index的str和ld
  • 从内存加载的数据的宽度由指令后缀指定
    • ldrsb =>

      signed byte extend
  • 加载到寄存器的宽度由寄存器的名字决定
    • LDRSB W4, <addr>

      目的寄存器是32位,从内存加载一个byte,高位使用signed extend扩充

uxtb, sxtb, uxth, sxth, uxtw, sxtw

Extending operators main purpose is to widen a narrower value found in a register to match the number of bits for the operation. An extending operator is of the form kxtw, where k is the kind of integer we want to widen and w is the width of the narrow value. For the former, the kind of integer can be U (unsigned) or S (signed, i.e. two’s complement). For the latter the width can be B, H or W which means respectively byte (least 8 significant bits of the register), half-word (least 16 significant bits of the register) or word (least significant 32 bits of the register).

add x0, x1, w2, sxtw // x0 ← x1 + ExtendSigned32To64(w2)

add x0, x1, w2, sxtb // x0 ← x1 + ExtendSigned8To64(w2)

add w0, w1, w2, sxtb // w0 ← w1 + ExtendSigned8To32(w2)

In both cases the least significant 8 bits of w2 are extended but in the first case they are extended to 64 bit and in the second case to 32-bit. Extension and shift

It is possible to extend a value and then shift it left 1, 2, 3 or 4 bits by specifying an amount after the extension operator. For instance

mov x0, #0 // x0 ← 0 mov x1, #0x1234 // x0 ← 0x1234

add x2, x0, x1, sxtw #1 // x2 ← x0 + (ExtendSigned16To64(x1) << 1) // this sets x2 to 0x2468

add x2, x0, x1, sxtw #2 // x2 ← x0 + (ExtendSigned16To64(x1) << 2) // this sets x2 to 0x48d0

add x2, x0, x1, sxtw #3 // x2 ← x0 + (ExtendSigned16To64(x1) << 3) // this sets x2 to 0x91a0

add x2, x0, x1, sxtw #4 // x2 ← x0 + (ExtendSigned16To64(x1) << 4) // this sets x2 to 0x12340

This may seem a bit odd and arbitrary at this point but in later chapters we will see that this is actually useful in many cases.

This is all for today.

反汇编一个例子

现代汇编语言现代汇编学习objconv 工具x86汇编nasmarmv8汇编系统调用库Linux 常识
  • nop的机器码
现代汇编语言现代汇编学习objconv 工具x86汇编nasmarmv8汇编系统调用库Linux 常识
  • 上述机器是小端,即高字节在高地址。2d8是地址从左到右依次递减,即

    d503201f

    是从高地址开始的。
  • 这个反汇编结果和x86的不太一样。。。x86的
    现代汇编语言现代汇编学习objconv 工具x86汇编nasmarmv8汇编系统调用库Linux 常识
    arm的
现代汇编语言现代汇编学习objconv 工具x86汇编nasmarmv8汇编系统调用库Linux 常识

arm嵌入汇编

cookbook

  • 语法
    asm(code_template
    :output_operand_list
    :input_operand_list
    :clobbered_register_list)
               
    其中code_template一条指令用引号括起来的
    asm (
        "TST LR, #0x40\n\t"
        "BEQ from_nonsecure\n\t"
      "from_secure:\n\t"
        "TST LR, #0x04\n\t"
        "ITE EQ\n\t"
        "MRSEQ R0, MSP\n\t"
        "MRSNE R0, PSP\n\t"
        "B hard_fault_handler_c\n\t"
      "from_nonsecure:\n\t"
        "MRS R0, CONTROL_NS\n\t"
        "TST R0, #2\n\t"
        "ITE EQ\n\t"
        "MRSEQ R0, MSP_NS\n\t"
        "MRSNE R0, PSP_NS\n\t"
        "B hard_fault_handler_c\n\t"
      );
               

加法例子

#include <stdio.h>

int add(int i, int j)
{
  int res = 0;
  __asm ("ADD %[result], %[input_i], %[input_j]"
    : [result] "=r" (res)
    : [input_i] "r" (i), [input_j] "r" (j)
  );
  return res;
}

int main(void)
{
  int a = 1;
  int b = 2;
  int c = 0;

  c = add(a,b);

  printf("Result of %d + %d = %d\n", a, b, c);
}
           
  • 使用通用寄存器做整数加减法

系统调用

  • 系统调用号:the syscall call numbers for the 32-bit ABI are in

    /usr/include/i386-linux-gnu/asm/unistd_32.h

    (same contents in

    /usr/include/x86_64-linux-gnu/asm/unistd_32.h

    ).
  • 注意系统调用怎么传参数的。(ia32和x64不太一样)
    • 32位(i386)
      • eax

        系统调用号
      • ebx ecx...

        系统调用参数
      • eax

        存放结果
      • There are six registers that stores the arguments of the system call used. These are the EBX, ECX, EDX, ESI, EDI, and EBP. These registers take the consecutive arguments, starting with the EBX register. If there are more than six arguments then the memory location of the first argument is stored in the EBX register.
  • eax

    用来放系统调用号
  • strace

    命令可以用来跟踪执行的系统调用
  • x64

    的系统调用使用指令

    syscall

    而不是

    int 0x86

  • 有两种库,静态库和动态库。静态库和动态库都是一些目标文件(即经过汇编后的文件)
    • 静态库实际上就是链接时候把这个库全部代码集成到调用库的这个主文件。

      静态库自然是静态链接的(实际上运行时候我们不再依赖于那个库文件,整个可执行文件已经包含了全部的库代码)

    • 动态库是位置无关代码。在链接时链接器不集成这些代码,只是在符号表中记录调用的函数在哪个库里面有。运行时再从这个符号表里面去找这个函数,到时候再转移即可。这有点像系统调用。
  • 名词解释
    • DSO/DLL

      :dynamic shared object/dynamic link library
  • 可能用到的工具:

    nm ldd objconv readelf

  • 参考

x86 再来一遍calling convention

和系统调用相关调用形式:Interfacing with operating system libraries requires knowing how to pass parameters and manage the stack. These details on a platform are called a calling convention.

  • Caller-saved 意思是被调程序允许随意使用这些寄存器,如果主程序在调用之前在使用这些寄存器,调用之后想继续使用,那主程序需要自己保存这些寄存器。这些寄存器就是普通的寄存器而已,保存与否取决于主程序的意愿(显然这是由caller保存)。
  • Callee-saved意思需要跨越调用保存的寄存器的值,比如常见的

    rsp ,rbp

    这些寄存器是有其他用途的,随时都必须保持在当前上下文时处于正确的值。这类寄存器必须要在使用之间保存(显然这是callee要使用的,应当由callee保存)
Caller-saved registers (AKA volatile registers, or call-clobbered) are used to hold temporary quantities that need not be preserved across calls.

For that reason, it is the caller’s responsibility to push these registers onto the stack or copy them somewhere else if it wants to restore this value after a procedure call.

It’s normal to let a

call

destroy temporary values in these registers, though.

Callee-saved registers (AKA non-volatile registers, or call-preserved) are used to hold long-lived values that should be preserved across calls.
  • microsoft x64 calling convention
  • wikipedia x86 calling convention
  • agner pdf

Linux 常识

  • Linux通常指的是linus Torvalds写的kernel,一般的linux os指的是linux distribution,比如ubuntu, debian,fedora。而GNU实际上是 richard stallman给他的project起的名字,做了很多os的软件(比如

    gcc

    ),但是没有kernel。可以粗糙理解

    linux os = linux kernel + gnu软件

  • System V 是at&t 开发的, 基于unix
  • BSD是

    Berkeley Software Distribution

    不仅是kernel,而且是整个os。
    • FreeBSD: FreeBSD is the most popular BSD, aiming for high performance and ease of use. It works well on standard Intel and AMD 32-bit and 64-bit processors.
    • NetBSD: NetBSD is designed to run on almost anything and supports many more architectures. The motto on their homepage is, “Of course it runs NetBSD.”
    • OpenBSD: OpenBSD is designed for maximum security — not just with its features, but with its implementation practices. It’s designed to be an operating system banks and other serious institutions would use for critical systems.
    There are two other notable BSD operating systems:
    • DragonFly BSD: DragonFly BSD was created with the design goal of providing an operating system that would run well in multithreaded environments — for example, in clusters of multiple computers.
    • Darwin / Mac OS X: Mac OS X is actually based on the Darwin operating system, which is based on BSD. It’s a bit different from other BSDs. While the low-level kernel and other software is open-source BSD code, most of the rest of the operating system is closed-source Mac OS code. Apple built Mac OS X and iOS on top of BSD so they wouldn’t have to write the low-level operating system themselves, just as Google built Android on top of Linux
  • 所以可以看到,MacOS实际上是基于BSD的,因此常用的软件

    编译器 sed

    等和Linux os都有所区别