程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> 匯編語言 >> 匯編語言學習指南(一)

匯編語言學習指南(一)

編輯:匯編語言

匯編語言和CPU以及內存,端口等硬件知識是連在一起的. 這也是為什麼匯編語言沒有通用性的原因. 下面簡單講講基本知識(針對INTEL x86及其兼容機)
============================
x86匯編語言的指令,其操作對象是CPU上的寄存器,系統內存,或者立即數. 有些指令表面上沒有操作數, 或者看上去缺少操作數, 其實該指令有內定的操作對象, 比如push指令, 一定是對SS:ESP指定的內存操作, 而cdq的操作對象一定是eax / edx.

在匯編語言中,寄存器用名字來訪問. CPU 寄存器有好幾類, 分別有不同的用處:

1. 通用寄存器:
EAX,EBX,ECX,EDX,ESI,EDI,EBP,ESP(這個雖然通用,但很少被用做除了堆棧指針外的用途)

這些32位可以被用作多種用途,但每一個都有"專長". EAX 是"累加器"(accumulator), 它是很多加法乘法指令的缺省寄存器. EBX 是"基地址"(base)寄存器, 在內存尋址時存放基地址. ECX 是計數器(counter), 是重復(REP)前綴指令和LOOP指令的內定計數器. EDX是...(忘了..哈哈)但它總是被用來放整數除法產生的余數. 這4個寄存器的低16位可以被單獨訪問,分別用AX,BX,CX和DX. AX又可以單獨訪問低8位(AL)和高8位(AH), BX,CX,DX也類似. 函數的返回值經常被放在EAX中.

ESI/EDI分別叫做"源/目標索引寄存器"(source/destination index),因為在很多字符串操作指令中, DS:ESI指向源串,而ES:EDI指向目標串.

EBP是"基址指針"(BASE POINTER), 它最經常被用作高級語言函數調用的"框架指針"(frame pointer). 在破解的時候,經常可以看見一個標准的函數起始代碼:

push ebp ;保存當前ebp
mov ebp,esp ;EBP設為當前堆棧指針
sub esp, xxx ;預留xxx字節給函數臨時變量.
...

這樣一來,EBP 構成了該函數的一個框架, 在EBP上方分別是原來的EBP, 返回地址和參數. EBP下方則是臨時變量. 函數返回時作 mov esp,ebp/pop ebp/ret 即可.

ESP 專門用作堆棧指針.

2. 段寄存器:
CS(Code Segment,代碼段) 指定當前執行的代碼段. EIP (Instruction pointer, 指令指針)則指向該段中一個具體的指令. CS:EIP指向哪個指令, CPU 就執行它. 一般只能用jmp, ret, jnz, call 等指令來改變程序流程,而不能直接對它們賦值.
DS(DATA SEGMENT, 數據段) 指定一個數據段. 注意:在當前的計算機系統中, 代碼和數據沒有本質差別, 都是一串二進制數, 區別只在於你如何用它. 例如, CS 制定的段總是被用作代碼, 一般不能通過CS指定的地址去修改該段. 然而,你可以為同一個段申請一個數據段描述符"別名"而通過DS來訪問/修改. 自修改代碼的程序常如此做.
ES,FS,GS 是輔助的段寄存器, 指定附加的數據段.
SS(STACK SEGMENT)指定當前堆棧段. ESP 則指出該段中當前的堆棧頂. 所有push/pop 系列指令都只對SS:ESP指出的地址進行操作.

3. 標志寄存器(EFLAGS):

該寄存器有32位,組合了各個系統標志. EFLAGS一般不作為整體訪問, 而只對單一的標志位感興趣. 常用的標志有:

進位標志C(CARRY), 在加法產生進位或減法有借位時置1, 否則為0.
零標志Z(ZERO), 若運算結果為0則置1, 否則為0
符號位S(SIGN), 若運算結果的最高位置1, 則該位也置1.
溢出標志O(OVERFLOW), 若(帶符號)運算結果超出可表示范圍, 則置1.

JXX 系列指令就是根據這些標志來決定是否要跳轉, 從而實現條件分枝. 要注意,很多JXX 指令是等價的, 對應相同的機器碼. 例如, JE 和JZ 是一樣的,都是當Z=1是跳轉. 只有JMP 是無條件跳轉. JXX 指令分為兩組, 分別用於無符號操作和帶符號操作. JXX 後面的"XX" 有如下字母:

無符號操作: 帶符號操作:
A = "ABOVE", 表示"高於" G = "GREATER", 表示"大於"
B = "BELOW", 表示"低於" L = "LESS", 表示"小於"
C = "CARRY", 表示"進位"或"借位" O = "OVERFLOW", 表示"溢出"
S = "SIGN", 表示"負"
通用符號:
E = "EQUAL" 表示"等於", 等價於Z (ZERO)
N = "NOT" 表示"非", 即標志沒有置位. 如JNZ "如果Z沒有置位則跳轉"
Z = "ZERO", 與E同.

如果仔細想一想,就會發現 JA = JNBE, JAE = JNB, JBE = JNA, JG = JNLE, JGE= JNL, JL= JNGE, ....

4. 端口

端口是直接和外部設備通訊的地方。外設接入系統後,系統就會把外設的數據接口映射到特定的端口地址空間,這樣,從該端口讀入數據就是從外設讀入數據,而向外設寫入數據就是向端口寫入數據。當然這一切都必須遵循外設的工作方式。端口的地址空間與內存地址空間無關,系統總共提供對64K個8位端口的訪問,編號0-65535. 相鄰的8位端口可以組成成一個16位端口,相鄰的16位端口可以組成一個32位端口。端口輸入輸出由指令IN,OUT,INS和OUTS實現,具體可參考匯編語言書籍。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved