匯編語言


匯編:

x86指令集   CISC: RISC
    向下兼容
    變長指令
       1-15字節,多為2-3字節長度
    多種尋址方式

MIPS 32位
    Load/Store 能訪問內存
    指令格式只有3類
    R(register)  從寄存器堆中讀取兩個源操作數,計算結果寫回寄存器堆
    I(immediate) 使用一個16位的立即數作為源操作數
    J(jump), 使用一個26位立即煩亂作為跳轉的目標地址

地址: 32位, 0000 --> 0004 ,差32位,4個字節
      64位, 0000 --> 0008
     
Byte Ordering

Big Endian: Sun, PowerPC, Internet
      低位字節(Least singificant byte,LSB)占據高地址
Little Endian: x86
      低對低,高對高
     0x123456
     0x100 0x0101 0x102
        56   34     12    
        
帶符號數
   最大 TMax : 0111...1  2^w -1
        TMin : 100...0     -2^w         001
     按位取反加1(符號位不動)     1*(-2^w)+          101  -4+1   011 -3  
     
何時采用無符號數
    模運算
    按位運算
  sizeof  返回值是unsigned
 
101    

2^6 2^5 2^2

x+y = -(x+y)
-x-1

浮點數:
   
    float: 23位有效,
    
    局限性: 只能精確表示x/2^k這類形式的數據
    
    數字形式:
        (-1)^s M 2^E
        符號: s
        尾數:  M
        階碼: E
        
    編碼:
      s   exp    frac
          E       M
    單數度: exp:  8bits   fract: 23
    雙           11bits         52
      
    規格化的浮點數 (Normalized)
      exp != 0000...0   111...1
      E = Exp -Bias     Exp(exp域所表示的無符號數值)
          Bias偏置量
            單精度: 127
            雙      1023
    
    Float F = 15213.0
    15213 = 11101101101101 = 1.1101101101101 *  2^13
      M    = 1.1101101101101
      frac =   1101101101101000000000   23位
      
      E    =  13
      Bias =  127
      Exp  =  140    10001100
      
      Hex:      4   6    6    D    B    4    0    0
      Binary: 0100 0110 0110 1101 1011 0100 0000 0000
      140:     100 0110 0
      15213:            0110 1101 1011 01
      
     
    
    value     binary     Rounded   Action
    2 3/32    10.00011    10.00       down      .5 100
    2 3/16    10.00110    10.01       up
    2 7/8     10.11100    11.00
    2 5/8     10.10100    10.10

  向偶數舍入(Round-To-Even)
      
     
保護模式 (段模式)
     
32位微處理器
  8個通用寄存器
    %eax     : %ah %al
    %edx
    %ecx
    %ebx
    %esi
    %edi
    %esp
    %ebp  
  指令寄存器擴展為32位, EIP
  6個段寄存器 (CS DS SS ES FS GS)
     段寄存器長度均為16位,其中13位代表內存段的一個編號,稱為“段選擇器”
     
ESP:棧指針寄存器(extended stack pointer),
     其內存放着一個指針,該指針永遠指向系統棧最上面一個棧幀的棧頂。
EBP:基址指針寄存器(extended base pointer),
     其內存放着一個指針,該指針永遠指向系統棧最上面一個棧幀的底部。
    
---- CPU  ---------------
  P     Registers       |
  C     Condition Codes |
-------------------------

指令寄存器 (PC Process Counter)
    下一條指令的地址
    EIP(x86-32) RIP(x86-64)


gcc -O2 -S add.c -m32 -fno-omit-frame-pointer

匯編語言數據格式
  C聲明          Intel數據類型   匯編代碼后綴     大小
 char             字節             b            1
 short            字               w            2
 int              雙字             l            4
 long int         雙字             l            4
 long long int    --
 char*            雙字             l            4
 float            單精度           s            4
 double           雙精度           l            8
 long double      擴展精度         t            10/12
 
      Source      Dest
                  Reg       movl  $0x4,%eax     temp = 0x4;
      Imm         Mem       movl  $-147,(%eax)  *p = -147;
    
movl  Reg         Reg       movl %eax,%edx      temp2=temp1;
                  Mem       movl %eax,(%edx)    *p = temp;
                  
      Mem         Reg       movl (%eax),%edx    temp = *p;

   間接尋址      (R)        Mem[Reg[R]]
        movl (%ecx),%eax
        
   基址+偏移量  D(R)     Mem[Reg[R]+D]
        movl 8(%ebp),%edx
        
變址尋址:
    D(Rb,Ri,S)   Mem[Reg[Rb]+S*reg[Ri]+D]
    D:常量(地址偏移量)
    Rb:基址寄存器:8個通用寄存器之一
    Ri: 索引寄存器: %esp不作為索引寄存器
        一般%ebp也不用做這個用途
    S: 比例因子1,2,4,8
    
    0x8(%edx)       0xf000 + 0x8     0xf008
    (%edx,%ecx)     0xf000 + 0x100   0xf100
    (%edx,%ecx,4)   0xf000+4*0x100   0xf400
    0x80(,%edx,2)   2*0xf000+0x80    0x1e080
    
  尋址模式實例:
    movb
    movw
    movl
    
    movs           D <---符號擴展(S)
    movsbw
    movsbl
    movswl
    
    MOVZ   S,D     D <---零擴展(S)
    movzbw
    movzbl
    movzwl
    
    pushl
    popl  
    
  地址計算指令:
    leal Src,Dest   
        leal (%edx,%eax),%ecx    # ecx = x+y
        leal (%edx,%edx,2),%edx  # edx = 3*y
     
  雙操作數指令:
    addl Src,Dest   Dest = Dest + Src
    subl Src,Dest   Dest = Dest - Src
    imull Src,Dest  Dest = Dest * Src
    sall  Src,Dest  Dest = Dest << Src    與shll等價
    sarl  Src,Dest  Dest = Dest >> Src    算術右移
    shrl  Src,Dest  Dest = Dest >> Src    邏輯右移
    xorl  Src,Dest  Dest = Dest ^ Src
    andl  Src,Dest  Dest = Dest & Src
    orl   Src,Dest  Dest = Dest | Src
    
  單操作數指令
    incl Dest    Dest = Dest + 1
    decl Dest    Dest = Dest -1
    negl Dest    Dest = - Dest
    notl Dest    Dest = ~ Dest

     
指針在32位是4bytes, 64位8bytes
     
        
-masm=intel   Intel/Microsoft Format格式的匯編

64位:
    16個通用寄存器
    %rax %eax        %r8  %r8d
    %rdx %edx        %r9  %r9d
    %rcx %ecx        %r10 %r10d
    %rbx %ebx        %r11 %r11d
    %rsi %esi        %r12 %r12d
    %rdi %edi        %r13 %r13d
    %rsp %esp        %r14 %r14d
    %rbp %ebp        %r15 %r15d
 參數小於7個時
   rdi,rsi,rdx,rcx,r8,r9, 多於7個的放於棧中  
 
條件碼:
    CF Carry Flag,進位
        用於檢測無符號整數運算的溢出
    ZF Zero : set if t == 0        set 1
    SF Sign : set if t < 0
    OF Overflow : set if 補碼運算溢出(即帶符號整數運算)
          (a>0 && b>0 && t<0)
          || (a<0 && b<0 && t>0)
    
  比較指令
  cmpl Src2,Src1
     ZF set if a==b
     SF set if(a-b)<0
     OF set if (a>0&&b<0 && (a-b)<0) ||
     
  測試指令  and
    ZF set when a&b == 0
    SF set when a&b < 0
 
  SetX指令
    讀取當前的條件碼(或者某些條件碼的組合),並存入目的字節寄存器
 
  SetX      Condition       Description
 
  sete      ZF              Equal/Zero
  setne     ~ZF             Not Equal/Not Zero
  sets         SF                Negative
  setns     ~SF
  setg        ~(SF^OF)&~ZF    Greter(Signed)
  setge     ~(SF^OF)         Greater of Equal(Signed)
  setl        (SF^OF)            Less(Signed)
  setle        (SF^OF)|ZF        Less or Equal(Signed)
  seta        ~CF&~ZF            Above(unsigned)
  setb        CF                Below(unsigned)
 
 32位:   (movzbl 指令對目的寄存器進行"0"擴展)
    int gt(int x,int y)
    {
        return x>y;
    }
    movl 12(%ebp),%eax    # eax = y
    cmpl %eax,8(%ebp)      # compare x:y
    setg %al              # al = x>y
    movzbl %al,%eax       # zero rest of %eax
 
 64位
  int gt(long x,long y)       long lgt(long x, long y)
  {                               {
        return x>y;               return x>y;
  }                           {
 
  assem:
    xorl  %eax,%eax    # eax = 0
    cmpg  %rsi,%rdi    # Compare x:y
    setg  %al          # al = x>y
    
  跳轉指令:
    jX            Condition        Description
    
    jmp            1                Unconditional
    je            ZF                Equal/Zero
    jne
    js
    jns
    jg
    jge
    jl
    jle
    ja
    jb
    
  64:
    cmovC  stc,dest
     如果條件C成立,將數據從src傳送至dest
     
    -march=i686
    
int fact_goto(int x)
{
    int result = 1;
loop:
    result *= x;
    x = x-1;
    if(x>1)
        goto loop;
    return result;    
}

fact_goto:
    pushl %ebp
    movl  $1,%eax
    movl  8(%ebp),%edx
    
L11:
    imul %edx,%eax
    decl %edx
    cmpl $1,%edx
    jg L11
    
jump-to-middle

條件跳轉指令會引起性能損失,Branck Prediction技術被引入來進行優化

switch :
    表結構:
        每個表項(及跳轉地址占4個字節)
        基地址是.L62
    jmp .L61
    jmp *.L62(,%edx,4)  *表明這是一個間接跳轉,即目標地址存於內存地址中,數即是地址

 .section .rodata
    .allign 4
 .L62:
    .long  .L61   # x=0
    .long  .L56   # x=1
    .long  .L57   # x=2
    .long  .L58   # x=3
    .long  .L61   # x=4
    .long  .L59   # x=5
    .long  .L60   # x=6
    
   12356, 0,4沒有就跳到default
 
 64:
    .L62
        .quad  .L55   # x=0
    
 64位寄存器使用慣例:
    %rax (Return Value)     %r8  Argument #5
    %rdx Callee Saved       %r9  Argument #6
    %rcx Argument #4        %r10 Callee Saved
    %rbx Argument #3        %r11 Callee Saved
    %rsi Argument #2        %r12 Callee Saved
    %rdi Argument #1        %r13 Callee Saved
    %rsp %esp                %r14 Callee Saved
    %rbp Callee Saved       %r15 Callee Saved
    
 
  壓棧操作:
    pushl Src
    %esp = %esp -4
  出棧操作:
    popl Dest
    %esp = %esp + 4
    
  過程調用指令:
    call label  將返回地址壓入棧,跳轉至label
  過程返回指令:
    ret    跳轉至棧頂的返回地址
    

  64位:
    一次性分配整個棧幀
      將%rsp減去某個值(棧幀的大小)   128宏區
      對於棧幀內容的訪問都是基於%rsp完成的
      可以延遲分配
    釋放簡單
    

 數組訪問:    
  x86-32:
    # %edx = z       數組起始地址
    # %eax = dig    下標
    movl (%edx,%eax,4),%eax # z[dig]
        
    二維數組:
        pgh[index][dig]
            pgh + 20*index + 4*dig
    # %ecx = dig
    # %eax = index
    leal 0(,%ecx,4),%edx       # 4*dig
    leal (%eax,%eax,4),%eax    # 5*index
    movl pgh(%edx,%eax,4),%eax # *(pgh+5*index+4*dig)
    
Multi-Level Array:
  int get_univ_digit(int index,int dig){
    return univ[index][dig];
  }        
  leal 0(,%ecx,4),%edx      # 4*index
  movl univ(%edx),%edx      # Mem[univ+4*index]
  movl (%edx,%eax,4),%eax   # Mem


 "."開頭的行都是匯編指示(Directives) .file .def .text
    其中.file和.def均用於調試(可忽略)
    
  ":"

gcc -O2 -mpreferred-stack-boundary=2

編譯參數:
as -o my-object-file.o hellowrold.s
  -gstabs  //產生帶調試信息的Object文件
  --32
 
ld -o my-exe-file my-object-file.o
   -m elf_i368
   
sudo apt install g++-multilib

.text
.globl _start

_start:
    popl %ecx    # argc
    
-- helloworld.s
.data
msg:
    .ascii "Hello hhh  world\n"
    len = .-msg            # "."表示當前地址,減msg表示長度

.text                      # 代碼段
.globl _start              # 匯編程序的入口

_start:
    movl $len,%edx
    movl $msg,%ecx
    movl $1,%ebx          # 系統輸出(write系統調用)
    movl $4,%eax          # write系統調用編號是4
    int $0x80             # 中斷指令

    movl $0,%ebx          # 程序退出 exit()中的參數0
    movl $1,%eax          # 1號系統調用,就是程序退出
    int $0x80

傳給系統調用的功能號,存放到
    ebx,ecx,edx,esi,edi中,再多就放入棧中
    返回值在 eax 中獲得

部分系統調用列表:

exit-terminate current process:
    
    In          eax                 1
                ebx                    return code
    Out            
    
fork-create child process
    
    In            eax                 2
    Out            eax                    0 in the clone
                                    process id of clone
                                    
read-read from file or device:
    
    In            eax                    3
                ebx                    file descriptor
                ecx                    address of the buffer to read into
                edx                    maximum number of bytes to read
    Out         eax                    number of bytes actually read

close
    In             eax                    6
                ebx                    file descriptor
    Out            eax                    zero for success | EBADF
    
x86-32 linux系統調用的參考資料
    http://syscalls.kernelgrok.com/
    
處理命令行參數:

.text
.globl _start

_start:
    popl %ecx             # argc
vnext:
    popl %ecx            #argv
    test %ecx,%ecx      
    jz      exit          #如果為空就退出
    movl %ecx,%ebx     # 參數列表的首地址
    xorl %edx,%edx
strlen:
    movb (%ebx),%al
    inc  %edx          # 參數個數 記數
    inc  %ebx
    test %al,%al       #如果為0則表示結束了  // and ,常用於判斷是否為空
    jnz strlen
    
    movl $10,-1(%ebx)  # 10是換行符
    movl $4,%eax       # 系統調用
    movl $1,%ebx       # 文件描述符
    int $0x80
    jmp vnext
    
exit:
    movl $1,%eax
    xorl %ebx,%ebx      # 自己和自己異或,清零
    int $0x80     
    
匯編調用lib_c庫函數示例
.section .data
output:
         .asciz  "The process vendor id is '%s'\n"   # z zero,補零
.section .bss       ;可讀可寫且沒有初始化的數據區
         .lcomm  buffer,12
.section .text
.globl   _start
_start:
        movl  $0,%eax
        cpuid          ; eax傳入0,返回值在ebx,edx,ecx
        movl  $buffer,%edi
        movl  %ebx,(%edi)
        movl  %edx,4(%edi)
        movl  %ecx,8(%edi)
        push  $buffer    ; $表示取的是地址的值
        push  $output
        call  printf
        addl  $8,%esp  ;調用者恢復
        push  $0       ;c函數exit的參數
        call  exit
    
as -o cpuid.o cpuid.s --32
ld -m elf_i386 -lc -dynamic-linker  /lib/ld-linux.so.2 -o cpuid cpuid.o
        
數據段 .rodata
output:
        .ascii  "hello world."           .byte
pi:                                         .double
        .float 3.14                         .float
ages:                                    .long    32位整數,和int相同
        .int 20,10,30,40                 .octa   16字節整數
                                         .qual   8字節
                                         .short  16位
                                         .singlee 單精度浮點數
                                        
bss段
   無需聲明特定的數據類型,只需聲明為所需目的的原始內存部分即可
   .comm 聲明為未初始化全局內存區域
   .lcomm  本地 , 外部模塊不能訪問他們
   
   
冪計算:
    pushl $3
    pushl $2
    call power
    addl $8,%esp    # move the stack pointer back
    pushl %eax      # save the first anwser
    
    pushl $2
    pushl $5
    call power
    addl $8,$esp
    popl %ebx
    
    addl %eax,%ebx
    movl $1,%eax
    int $0x80     
    
    
.equ
    .equ factor,3   # 類似define

syscall 號碼:    
/usr/include/asm/unistd_64.h
32位的匯編程序請查看/usr/include/asm/unistd_32.h                                        
                         
    


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM