欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
LINUX匯編(匯編語(yǔ)言程序設計讀書(shū)筆記)
http://blog.chinaunix.net/u2/63996/showart_499472.html
原文鏈接:http://linuxsir.org/bbs/showthread.php?t=289776


獻給與我一樣喜歡學(xué)習的人?。?! ^_^, 用了不到一個(gè)星期的時(shí)間把匯編語(yǔ)言程序設計這本書(shū)給大致
看了一遍, 其中下面這些省略了浮點(diǎn)數及IA-32如SSE FPU等特殊的指令集部分, 我覺(jué)得重要的是學(xué)習
linux匯編的語(yǔ)法及編譯原理和程序控制流程, 具體的指令細節就不那么重要了。 有什么問(wèn)題大家可以
一起交流: aishen944@163.com

################################################################################################
# 一, IA-32 硬件特性
################################################################################################

寄存器:
1, 通用寄存器, 用于存放正在處理的數據
EAX 用于操作數和結果數的累加器
EBX 指向數據內存斷中的數據的指針
ECX 字符串和循環(huán)操作的計數器
EDX IO指針
EDI 用于字符串操作的目標的數據指針
ESI 用于字符串操作的源的數據指針
ESP 堆棧指針
EBP 堆棧數據指針

其中寄存器EAX, EBX, ECX, EDX又可以通過(guò)16位和8位寄存器名稱(chēng)引用
如EAX, AX 引用EAX低16位, AL 引用EAX低8位, AH 引用AL之后的高8位



2, 段寄存器:
IA-32平臺允許使用3中內存模型: 平坦內存模式 分段內存模式 實(shí)地址模式

平坦內存: 把全部的系統內存表示為連續的地址空間, 通過(guò)線(xiàn)性地址的特定地址
訪(fǎng)問(wèn)內存位置.

分段內存: 把系統內存劃分為獨立的段組, 通過(guò)位于寄存器中的指針進(jìn)行引用. 每
個(gè)段用于包含特定類(lèi)型的數據。 一個(gè)段用于包含指令碼, 另一個(gè)段包
含數據元素, 第三個(gè)段包含數據堆棧。
段中的內存位置是通過(guò)邏輯地址引用的, 邏輯地址是由段地址加上偏移
量構成, 處理器把邏輯地址轉換為相應的線(xiàn)性地址以便訪(fǎng)問(wèn)。


段寄存器:
CS 代碼段
DS 數據段
SS 堆棧段
ES 附加段指針
FS 附加段指針
GS 附加段指針

每個(gè)段寄存器都是16位的, 包含指向內存特定段起始位置的指針,程序不能
顯示加載或改變CS寄存器, DS, ES, FS, GS都用于指向數據段, 通過(guò)4個(gè)獨立
的段, 程序可以分隔數據元素, 確保他們不會(huì )重疊, 程序必須加載帶有段的
正確指針值的數據段寄存器, 并且使用偏移值引用各個(gè)內存的位置。
SS段寄存器用于指向堆棧段, 堆棧包含傳遞給函數和過(guò)程的數據值。

實(shí)地址: 如果實(shí)地址模式, 所有段寄存器都指向線(xiàn)性0地址, 并且都不會(huì )被程序改動(dòng),
所有的指令碼 數據元素 堆棧元素 都是通過(guò)他們的線(xiàn)性地址直接訪(fǎng)問(wèn)的。



3, 指令指針寄存器
是EIP寄存器, 它跟蹤要執行程序的下一條指令代碼, 應用程序不能修改指令指針本身,不
能指定內存地址把它拖放EIP寄存器中,相反必須通過(guò)一般的跳轉指令來(lái)改變預存取緩存的
下一條指令。

在平坦內存模型中, 指令指針包含下一條指令碼的線(xiàn)性地址, 在分段模型中指令指針包含
邏輯地址指針, 通過(guò)CS寄存器的內存引用。



4, 控制寄存器
CRO 控制操作模式 和 處理器當前狀態(tài)的系統標志
CR1 當前沒(méi)有使用
CR2 內存頁(yè)面錯誤信息
CR3 內存頁(yè)面目錄信息
CR4 支持處理器特性和說(shuō)明處理器特性能力的標志

不能直接訪(fǎng)問(wèn)控制寄存器, 但是能把控制寄存器中的值傳遞給通用寄存器,如果必須改動(dòng)控制
寄存器的標志, 可以改動(dòng)通用寄存器的值, 然后把內容傳遞給控制寄存器。





標志:
IA-32使用單一的寄存器來(lái)包含一組狀態(tài)控制和系統標志, EFLAGS寄存器包含32位標志信息

1, 狀態(tài)標志
標志 位 說(shuō)明
CF 0 進(jìn)位標志, 如果無(wú)符號數的數學(xué)操作產(chǎn)生最高有效位的進(jìn)位或者借位, 此時(shí)值為1
PF 2 奇偶校驗標志, 用于表明數學(xué)操作的結果寄存器中的是否包含錯誤數據
AF 4 輔助進(jìn)位標志, 用于二進(jìn)制編碼的10進(jìn)制(BCD)的數學(xué)操作中, 如果用于運算的
寄存器的第三位發(fā)生進(jìn)位或借位, 該值為1
ZF 6 0標志, 如果操作為0, 則該值為1
SF 7 符號標志, 設置為結果的最高有效位, 這一位是符號位表明結果是正值還是負值
OF 11 溢出標志

2, 控制標志
當前只定義了一個(gè)控制標志DF即方向標志, 用于控制處理器處理字符串的方式
如果設置為1, 字符串指令自動(dòng)遞減內存地址以便到達字符串中的下一字節。
反之。

3, 系統標志
標志 位 說(shuō)明
TF 8 陷阱標志, 設置為1時(shí)啟用單步模式, 在單步模式下處理器每次只執行一條命令。
IF 9 中斷使能標志, 控制處理器如響應從外部源接收到的信號。
IOPL 12和13 IO特權級別標志, 表明當前正在運行任務(wù)的IO特權級別, 它定義IO地址空間的
特權訪(fǎng)問(wèn)級別, 該值必須小于或者等于訪(fǎng)問(wèn)I/O地址空間的級別; 否則任何訪(fǎng)問(wèn)
IO空間的請求都會(huì )被拒絕!
NT 14 嵌套任務(wù)標志控制當前運行的任務(wù)是否連接到前一個(gè)任務(wù), 它用于連接被中斷
和被調用的任務(wù).
RF 16 恢復標志用于控制在調試模式中如何響應異常。
VM 17 虛擬8086模式, 表明處理器在虛擬8086模式中而不是保護模式或者實(shí)模式。
AC 18 對準檢查標志, 用于啟用內存引用的對準檢查
VIF 19 虛擬中斷標志, 當處理器在虛擬模式中操作時(shí), 該標志起IF標志的作用.
VIP 20 虛擬中斷掛起標志, 在虛擬模式操作時(shí)用于表示一個(gè)中斷正在被掛起。
ID 21 表示CPU是否支持cpuid指令, 如果處理器能夠設置或者清零這個(gè)標志, 表示
處理器支持該指令。






################################################################################################
# 二,GNU匯編工具系列
################################################################################################
1, 二進(jìn)制工具系列
addr2line 把地址轉換成文件名或者行號

ar 創(chuàng )建 修改或者展開(kāi)文件存檔

as 把匯編語(yǔ)言代碼匯編成目標代碼
常用選項:
-a -> 指定輸出中包含那些清單
-D -> 包含它用于向下兼容 但是被忽略
--defsym -> 在匯編代碼之前定義符號和值
-f -> 快速匯編跳過(guò)注釋和空白
--gstabs -> 包含每行源代碼的調試信息
--gstats+ -> 包含gdb專(zhuān)門(mén)的調試信息
-I -> 指定包含文件的目錄
-J -> 不警告帶符號溢出
-L -> 在符號表中保存本地符號
-o -> 給定輸出目標名
-R -> 把數據段合并進(jìn)文本段
--statistics -> 顯示匯編使用的最大空間和總時(shí)間
-v -> 顯示as的版本號
-W -> 不顯示警告信息

c++filt 還原c++符號的過(guò)濾器

gprof 顯示程序簡(jiǎn)檔信息的程序

ld 把目標代碼文件轉換成可執行文件的轉換器
常用選項:
-d -> 指定目標代碼輸入文件的格式
-Bstatic -> 只使用靜態(tài)庫
-Bdynamic -> 只使用動(dòng)態(tài)庫
-Bsymbolic-> 把引用捆綁到共享庫中的全局符號
-c -> 從指定的命令文件讀取命令
-cref -> 創(chuàng )建跨引用表
-defsym -> 在輸出文件中創(chuàng )建指定的全局符號
-demangle -> 在錯誤消息中還原符號名稱(chēng)
-e -> 使用指定的符號作為程序的初始執行點(diǎn)
-E -> 對于elf文件把所有的符號添加到動(dòng)態(tài)符號表
-share -> 創(chuàng )建共享庫
-Ttext -> 使用指定的地址作為文本段的起始點(diǎn)
-Tdata -> 使用指定的地址作為數據段的起始點(diǎn)
-Tbss -> 使用指定的地址作為bss段的起始點(diǎn)
-L -> 把指定的路徑添加到庫搜索清單
-O -> 生成優(yōu)化的輸出文件
-o -> 指定輸出名
-oformat -> 指定輸出文件的二進(jìn)制格式
-R -> 從指定的文件讀取符號和地址
-rpath -> 把指定的位置添加到運行時(shí)庫搜索路徑
-rpath-link-> 指定搜索運行時(shí)共享庫的路徑
-X -> 刪除本地所有臨時(shí)符號
-x -> 刪除本地所有符號

nm 列出目標文件中的符號

objcopy 復制或翻譯目標文件

objdump 顯示來(lái)自目標文件的信息

ranlib 生成存檔文件內容的索引

readelf 按照elf格式顯示目標文件信息

size 列出目標文件或者存檔文件的段長(cháng)度

strings 顯示目標文件中可打印字符串

strip 丟棄符號

windres 編譯Microsoft Windows資源文件

2, GNU編譯器
gcc
常用選項:
-c 編譯或者匯編代碼但不進(jìn)行連接
-S 編譯后停止但不進(jìn)行匯編
-E 預處理后停止但不進(jìn)行編譯
-o 指定輸出文件名
-v 顯示每個(gè)編譯階段使用的命令
-std 指定使用的語(yǔ)言標準
-g 生成調試信息
-pg 生成gprof制作簡(jiǎn)檔要使用的額外代碼
-O 優(yōu)化可執行代碼
-W 設置編譯器警告級別
-I 指定包含文件清單
-L 指定庫文件目錄
-D 預定義源代碼中使用的宏
-U 取消任何定義了的宏
-f 指定控制編譯器行為的選項
-m 指定與硬件相關(guān)的選項

3, GNU調試程序
gdb
常用選項:
-d 指定遠程調試時(shí)串行接口的線(xiàn)路速度
-batch 以批處理模式運行
-c 指定要分析的核心轉儲文件
-cd 指定工作目錄
-d 指定搜索源文件的目錄
-e 指定要執行的文件
-f 調試時(shí)以標準格式輸出文件名和行號
-q 安靜模式
-s 指定符號的文件名
-se 指定符號和要執行的文件名
-tty 設置標準輸出和輸入設備
-x 從指定的文件執行g(shù)db命令

由于gnu調試時(shí)忽略開(kāi)始處斷點(diǎn), 需要在開(kāi)始標簽處執行一個(gè)空指令
如:
.globl _start
_start:
nop
此時(shí)斷點(diǎn)可以設置成 break *_start+1
查看寄存器狀態(tài)info registers
使用print命令查看特定寄存器或者變量的值, 加上修飾符可以得到不同的輸出格式:
print/d 顯示十進(jìn)制數字
print/t 顯示二進(jìn)制數字
print/x 顯示16進(jìn)制數字
使用x命令可以查看特定內存的值:
x/nyz
其中 n為要顯示的字段數
y時(shí)輸出格式, 它可以是:
c 用于字符, d用于十進(jìn)制, x用于16進(jìn)制
z是要顯示的字段長(cháng)度, 它可以是:
b用于字節, h用于16字節, w用于32位字
如:
x/42cb 用于顯示前42字節


################################################################################################
# 三, GNU匯編語(yǔ)言結構
################################################################################################
主要包括三個(gè)常用的段:
data 數據段 聲明帶有初始值的元素
bss 數據段 聲明使用0或者null初始化的元素
text 正文段 包含的指令, 每個(gè)匯編程序都必須包含此段

使用.section 指令定義段, 如:
.section .data
.section .bss
.section .text

起始點(diǎn):
gnu匯編器使用_start標簽表示默認的起始點(diǎn), 此外如果想要匯編內部的標簽能夠被外部程序訪(fǎng)問(wèn),
需要使用.globl 指令, 如:.globl _start


使用通用庫函數時(shí)可以使用:
ld -dynamic-linker /lib/ld-linux.so.2




################################################################################################
# 四, 數據傳遞
################################################################################################
1, 數據段
使用.data聲明數據段, 這個(gè)段中聲明的任何數據元素都保留在內存中并可以被匯編程序的指令讀取,
此外還可以使用.rodata聲明只讀的數據段, 在聲明一個(gè)數據元素時(shí), 需要使用標簽和命令:

標簽:用做引用數據元素所使用的標記, 它和c語(yǔ)言的變量很相似, 它對于處理器是沒(méi)有意義的, 它
只是用做匯編器試圖訪(fǎng)問(wèn)內存位置時(shí)用做引用指針的一個(gè)位置。

指令:這個(gè)名字指示匯編器為通過(guò)標簽引用的數據元素保留特定數量的內存, 聲明命令之后必須給出
一個(gè)或多個(gè)默認值。

聲明指令:
.ascii 文本字符串
.asciz 以空字符結尾的字符串
.byte 字節值
.double 雙精度浮點(diǎn)值
.float 單精度浮點(diǎn)值
.int 32位整數
.long 32位整數, 和int相同
.octa 16字節整數
.quad 8字節整數
.short 16位整數
.single 單精度浮點(diǎn)數(和float相同)


例子:
output:
.ascii "hello world."

pi:
.float 2.14

聲明可以在一行中定義多個(gè)值, 如:
ages:
.int 20, 10, 30, 40


定義靜態(tài)符號:
使用.equ命令把常量值定義為可以在文本段中使用的符號,如:
.section .data
.equ LINUX_SYS_CALL, 0x80
.section .text
movl $LINUX_SYS_CALL, %eax



2, bss段
和data段不同, 無(wú)需聲明特定的數據類(lèi)型, 只需聲明為所需目的保留的原始內存部分即可。
GNU匯編器使用以下兩個(gè)命令聲明內存區域:
.comm 聲明為未初始化的通用內存區域
.lcomm 聲明為未初始化的本地內存區域

兩種聲明很相似, 但.lcomm是為不會(huì )從本地匯編代碼之外進(jìn)行訪(fǎng)問(wèn)的數據保留的, 格式為:
.comm/.lcomm symbol, length

例子:
.section .bss
.lcomm buffer, 1000
該語(yǔ)句把1000字節的內存地址賦予標簽buffer, 在聲明本地通用內存區域的程序之外的函數是
不能訪(fǎng)問(wèn)他們的.(不能在.globl命令中使用他們)


在bss段聲明的好處是, 數據不包含在可執行文件中。在數據段中定義數據時(shí), 它必須被包含在
可執行程序中, 因為必須使用特定值初始化它。 因為不使用數據初始化bss段中聲明的數據區域,
所以?xún)却鎱^域被保留在運行時(shí)使用, 并且不必包含在最終的程序中




3, 傳送數據
move 指令:
格式 movex 源操作數, 目的操作數。 其中x為要傳送數據的長(cháng)度, 取值有:
l 用于32位的長(cháng)字節
w 用于16位的字
b 用于8位的字節值


立即數前面要加一個(gè)$符號, 寄存器前面要加%符號。

8個(gè)通用的寄存器是用于保存數據的最常用的寄存器, 這些寄存器的內容可以傳遞
給其他的任何可用的寄存器。 和通用寄存器不同, 專(zhuān)用寄存器(控制, 調試, 段)
的內容只能傳送給通用寄存器, 或者接收從通用寄存器傳過(guò)來(lái)的內容。


在對標簽進(jìn)行引用時(shí):
例:
.section .data
value:
.int 100
_start:
movl value, %eax
movl $value, %eax
movl %ebx, (%edi)
movl %ebx, 4(%edi)

其中:movl value, %eax 只是把標簽value當前引用的內存值傳遞給eax
movl $value, %eax 把標簽value當前引用的內存地址指針傳遞給eax
movl %ebx, (%edi) 如果edi外面沒(méi)有括號那么這個(gè)指令只是把ebx中的
值加載到edi中, 如果有了括號就表示把ebx中的內容
傳送給edi中包含的內存位置。
movl %ebx, 4(%edi) 表示把edi中的值放在edi指向的位置之后的4字節內存位置中
movl %ebx, -4(%edi) 表示把edi中的值放在edi指向的位置之前的4字節內存位置中



cmove 指令(條件轉移):
cmovex 源操作數, 目的操作數. x的取值為:
無(wú)符號數:
a/nbe 大于/不小于或者等于
ae/nb 大于或者等于/不小于
nc 無(wú)進(jìn)位
b/nae 小于/不大于等于
c 進(jìn)位
be/na 小于或等于/不大于
e/z 等于/零
ne/nz 不等于/不為零
p/pe 奇偶校驗/偶校驗
np/po 非奇偶校驗/奇校驗

有符號數:
ge/nl 大于或者等于/不小于
l/nge 小于/不大于或者等于
le/ng 小于或者等于/不大于
o 溢出
no 未溢出
s 帶符號(負)
ns 無(wú)符號(非負)





交換數據:
xchg 在兩個(gè)寄存器之間或者寄存器和內存間交換值
如:
xchg 操作數, 操作數, 要求兩個(gè)操作數必須長(cháng)度相同且不能同時(shí)都是內存位置
其中寄存器可以是32,16,8位的


bswap 反轉一個(gè)32位寄存器的字節順序

如: bswap %ebx


xadd 交換兩個(gè)值 并把兩個(gè)值只和存儲在目標操作數中

如: xadd 源操作數,目標操作數
其中源操作數必須是寄存器, 目標操作數可以是內存位置也可以是寄存器
其中寄存器可以是32,16,8位的

cmpxchg
cmpxchg source, destination
其中source必須是寄存器, destination可以是內存或者寄存器, 用來(lái)比較
兩者的值, 如果相等,就把源操作數的值加載到目標操作數中, 如果不等就把
目標操作數加載到源操作數中,其中寄存器可以是32,16,8位的, 其中源操作
數是EAX,AX或者AL寄存器中的值


cmpxchg8b 同cmpxchg, 但是它處理8字節值, 同時(shí)它只有一個(gè)操作數
cmpxchg8b destination
其中destination引用一個(gè)內存位置, 其中的8字節值會(huì )與EDX和EAX寄存器中
包含的值(EDX高位寄存器, EAX低位寄存器)進(jìn)行比較, 如果目標值和EDX:EAX
對中的值相等, 就把EDX:EAX對中的64位值傳遞給內存位置, 如果不匹配就把
內存地址中的值加載到EDX:EAX對中



4, 堆棧
ESP 寄存器保存了當前堆棧的起始位置, 當一個(gè)數據壓入棧時(shí), 它就會(huì )自動(dòng)遞減,
反之其自動(dòng)遞增

壓入堆棧操作:
pushx source, x取值為:
l 32位長(cháng)字
w 16位字

彈出堆棧操作:
popx source
其中source必須是16或32位寄存器或者內存位置, 當pop最后一個(gè)元素時(shí)ESP值應該
和以前的相等


5,壓入和彈出所有寄存器
pusha/popa 壓入或者彈出所有16位通用寄存器
pushad/popad 壓入或者彈出所有32位通用寄存器
pushf/popf 壓入或者彈出EFLAGS寄存器的低16位
pushfd/popfd 壓入或者彈出EFLAGS寄存器的全部32位


6,數據地址對齊
gas 匯編器支持.align 命令, 它用于在特定的內存邊界對準定義的數據元素, 在數據段
中.align命令緊貼在數據定義的前面




#######################################################
#########################################
# 五,控制流程
################################################################################################
無(wú)條件跳轉:
1, 跳轉
jmp location 其中location為要跳轉到的內存地址, 在匯編中為定義的標簽

2,調用
調用指令分為兩個(gè)部分:
1, 調用call address 跳轉到指定位置
2, 返回指令ret, 它沒(méi)有參數緊跟在call指令后面的位置

執行call指令時(shí),它把EIP的值放到堆棧中, 然后修改EIP以指向被調用的函數地址, 當被調用
函數完成后, 它從堆棧獲取過(guò)去的EIP的值, 并把控制權返還給原始程序。

3,中斷
由硬件設備生成中斷。 程序生成軟件中斷
當一個(gè)程序產(chǎn)生中斷調用時(shí), 發(fā)出調用的程序暫停, 被調用的程序接替它運行, 指令指針被轉移到
被調用的函數地址, 當調用完成時(shí)使用中斷返回指令可以返回調原始程序。



條件跳轉:
條件跳轉按照EFLAGS中的值來(lái)判斷是否該跳轉, 格式為:

jxx address, 其中xx是1-3個(gè)字符的條件代碼, 取值如下:
a 大于時(shí)跳轉
ae 大于等于
b 小于
be 小于等于
c 進(jìn)位
cxz 如果CX寄存器為0
ecxz 如果ECS寄存器為0
e 相等
na 不大于
nae 不大于或者等于
nb 不小于
nbe 不小于或等于
nc 無(wú)進(jìn)位
ne 不等于
g 大于(有符號)
ge 大于等于(有符號)
l 小于(有符號)
le 小于等于(有符號)
ng 不大于(有符號)
nge 不大于等于(有符號)
nl 不小于
nle 不小于等于
no 不溢出
np 不奇偶校驗
ns 無(wú)符號
nz 非零
o 溢出
p 奇偶校驗
pe 如果偶校驗
po 如果奇校驗
s 如果帶符號
z 如果為零


條件跳轉不支持分段內存模型下的遠跳轉, 如果在該模式下進(jìn)行
程序設計必須使用程序邏輯確定條件是否存在, 然后實(shí)現無(wú)條件
跳轉, 跳轉前必須設置EFLAGS寄存器



比較:
cmp operend1, operend2


進(jìn)位標志修改指令:
CLC 清空進(jìn)位標志(設置為0)
CMC 對進(jìn)位標志求反(把它改變?yōu)橄喾吹闹?
STC 設置進(jìn)位標志(設置為1)


循環(huán):
loop 循環(huán)直到ECX寄存器為0
loope/loopz 循環(huán)直到ecx寄存器為0 或者沒(méi)有設置ZF標志
loopne/loopnz 循環(huán)直到ecx為0或者設置了ZF標志

指令格式為: loopxx address 注意循環(huán)指令只支持8位偏移地址



################################################################################################
# 六,數字
################################################################################################

IA-32平臺中存儲超過(guò)一字節的數都被存儲為小尾數的形式但是把數字傳遞給寄存器時(shí), 寄存器里面保存是按照大尾數
的形式存儲


把無(wú)符號數轉換成位數更大的值時(shí), 必須確保所有的高位部分都被設置為零

把有符號數轉換成位數更大的數時(shí):
intel 提供了movsx指令它允許擴展帶符號數并保留符號, 它與movzx相似, 但是它假設要傳送的字節是帶符號數形式


浮點(diǎn)數:
fld 指令用于把浮點(diǎn)數字傳送入和傳送出FPU寄存器, 格式:
fld source
其中source可以為32 64或者80位整數值


IA-32使用FLD指令用于把存儲在內存中的單精度和雙精度浮點(diǎn)值FPU寄存器堆棧中, 為了區分這兩種長(cháng)度GNU匯編器使用
FLDS加載單精度浮點(diǎn)數, FLDL加載雙精度浮點(diǎn)數

類(lèi)似FST用于獲取FPU寄存器堆棧中頂部的值, 并且把這個(gè)值放到內存位置中, 對于單精度使用FSTS, 對于雙精度使用FSTL



################################################################################################
# 七,基本數學(xué)運算
################################################################################################
1, 加法
ADD source, destination 把兩個(gè)整數相加
其中source可以是立即數內存或者寄存器, destination可以是內存或者寄存器, 但是兩者不能同時(shí)都是內存位置


ADC 和ADD相似進(jìn)行加法運算, 但是它把前一個(gè)ADD指令的產(chǎn)生進(jìn)位標志的值包含在其中, 在處理位數大于32(如64)
位的整數時(shí), 該指令非常有用

2, 減法
SUB source, destination 把兩個(gè)整數相減
NEG 它生成值的補碼
SBB 指令, 和加法操作一樣, 可以使用進(jìn)位情況幫助執行大的無(wú)符號數值的減法運算. SBB在多字節減法操作中利用
進(jìn)位和溢出標志實(shí)現跨數據邊界的的借位特性

3,遞增和遞減
dec destination 遞減
inc destination 遞增

其中dec和inc指令都不會(huì )影響進(jìn)位標志, 所以遞增或遞減計數器的值都不會(huì )影響程序中涉及進(jìn)位標志的其他任何運算

4, 乘法
mul source 進(jìn)行無(wú)符號數相乘
它使用隱含的目標操作數, 目標位置總是使用eax的某種形式, 這取決與源操作數的長(cháng)度, 因此根據源操作數的長(cháng)度,
目標操作數必須放在A(yíng)L, AX, EAX中。 此外由于乘法可能產(chǎn)生很大的值, 目標位置必須是源操作數的兩倍位置, 源為
8時(shí), 應該是16, 源為16時(shí), 應該為32, 但是當源為16位時(shí)intel為了向下兼容, 目標操作數不是存放在eax中, 而
是分別存放在DX:AX中, 結果高位存儲在DX中, 地位存儲在A(yíng)X中。對于32位的源, 目標操作數存儲在EDX:EAX中, 其中
EDX存儲的是高32位, EAX存儲的是低32位

imul source 進(jìn)行有符號數乘法運算, 其中的目標操作數和mul的一樣

imul source, destination 也可以執行有符號乘法運算, 但是此時(shí)可以把目標放在指定的位置, 使用這種格式的缺陷
在與乘法的操作結果被限制為單一目標寄存器的長(cháng)度.

imul multiplier, source, destination
其中multiplier是一個(gè)立即數, 這種方式允許一個(gè)值與給定的源操作數進(jìn)行快速的乘法運算, 然后把結果存儲在通用
寄存器中


5, 除法
div divisor 執行無(wú)符號數除法運算
除數的最大值取決與被除數的長(cháng)度, 對于16位被除數 ,除數只能為8位, 32或64位同上
被除數 被除數長(cháng)度 商 余數
AX 16位 AL AH
DX:AX 32位 AX DX
EDX:EAX 64位 EAX EDX

idiv divisor 執行有符號數的除法運算, 方式和div一樣

6, 移位
左移位:
sal 向左移位
sal destination 把destination向左移動(dòng)1位
sal %cl, destination 把destination的值向左移動(dòng)CL寄存器中指定的位數
sal shifter, destination 把destination的值向左移動(dòng)shifter值指定的位數
向左移位可以對帶符號數和無(wú)符號數執行向左移位的操作, 移位造成的空位用零填充, 移位造成的超過(guò)數據長(cháng)度的任何位
都被存放在進(jìn)位標志中, 然后在下一次移位操作中被丟棄

右移位:
shr向右移位
sar向右移位
SHR指令清空移位造成的空位, 所以它只能對無(wú)符號數進(jìn)行移位操作
SAR指令根據整數的符號位, 要么清空, 要么設置移位造成的空位, 對于負數, 空位被設置為1

循環(huán)移位:
和移位指令類(lèi)似, 只不過(guò)溢出的位被存放回值的另一端, 而不是丟棄
ROL 向左循環(huán)移位
ROR 向右循環(huán)移位
RCL 向左循環(huán)移位, 并且包含進(jìn)位標志
RCR 向右循環(huán)移位, 并且包含進(jìn)位標志

7, 邏輯運算
AND OR XOR
這些指令使用相同的格式:
and source, destination
其中source可以是8位 16 位或者32位的立即值 寄存器或內存中的值, destination可以是8位 16 位或者
32位寄存器或內存中的值, 不能同時(shí)使用內存值作為源和目標。 布爾邏輯功能對源和目標執行按位操作。
也就是說(shuō)使用指定的邏輯功能按照順序對數據的元素的每個(gè)位進(jìn)行單獨比較。

NOT指令使用單一操作數, 它即是源值也是目標結果的位置
清空寄存器的最高效方式是使用OR指令對寄存器和它本身進(jìn)行異或操作.當和本身進(jìn)行XOR操作時(shí), 每個(gè)設置為
1的位就變?yōu)?, 每個(gè)設置為0的位也變位0。

位測試可以使用以上的邏輯運算指令, 但這些指令會(huì )修改destination的值, 因此intel提供了test指令, 它不
會(huì )修改目標值而是設置相應的標志



################################################################################################
# 八,字符串處理
################################################################################################
1, 傳送字符串
movs 有三種格式
movsb 傳送單一字節
movsw 傳送一個(gè)字
movsl 傳送雙字

movs指令使用隱含的源和目的操作數, 隱含的源操作數是ESI, 隱含的目的操作數是EDI, 有兩種方式加載內存地址到
ESI和EDI, 第一種是使用標簽間接尋址 movl $output, %ESI, 第二種是使用lea指令, lea指令加載對象的地址到指定
的目的操作數如lea output, %esi, 每次執行movs指令后, 數據傳送后ESI和EDI寄存器會(huì )自動(dòng)改變,為另一次傳送做
準備, ESI和EDI可能隨著(zhù)標志DF的不同自動(dòng)遞增或者自動(dòng)遞減, 如果DF標志為0則movs指令后ESI和EDI會(huì )遞增, 反之會(huì )
遞減, 為了設置DF標志, 可以使用一下指令:
CLD 將DF標志清零
STD 設置DF標志

2,rep前綴
REP 指令的特殊之處在與它不執行什么操作, 這條指令用于按照特定次數重復執行字符串指令, 有ECX寄存器控制,
但不需要額外的loop指令, 如rep movsl

rep的其他格式:
repe 等于時(shí)重復
repne 不等于時(shí)重復
repnz 不為零時(shí)重復
repz 為零時(shí)重復

3, 存儲和加載字符串
LODS 加載字符串, ESI為源, 當一次執行完lods時(shí)會(huì )遞增或遞減ESI寄存器, 然后把字符串值存放到EAX中

STOS 使用lods把字符串值加載到EAX后, 可以使用它把EAX中的值存儲到內存中去:
stos使用EDI作為目的操作數, 執行stos指令后, 會(huì )根據DF的值自動(dòng)遞增或者遞減EDI中的值

4, 比較字符串
cmps 和其他的操作字符串的指令一樣, 隱含的源和目標操作數都為ESI和EDI, 每次執行時(shí)都會(huì )根據DF的值把
ESI和EDI遞增或者遞減, cmps指令從目標字符串中減去源字符串, 執行后會(huì )設置EFLAGS寄存器的狀態(tài).


5,掃描字符串
scas 把EDI作為目標, 它把EDI中的字符串和EAX中的字符串進(jìn)行比較 ,然后根據DF的值遞增或者遞減EDI



################################################################################################
# 九,使用函數
################################################################################################
GNU匯編語(yǔ)言定義函數的語(yǔ)法:
.type 標簽(也就是函數名), @function
ret 返回到調用處



################################################################################################
# 十,linux系統調用
################################################################################################
linux系統調用的中斷向量為0x80

1, 系統調用標識存放在%eax中
2, 系統調用輸入值:
EBX 第一個(gè)參數
ECX 第二個(gè)參數
EDX 第三個(gè)參數
ESI 第四個(gè)參數
EDI 第五個(gè)參數

需要輸入超過(guò)6個(gè)輸入參數的系統調用, EBX指針用于保存指向輸入參數內存位置的指針, 輸入參數按照連續的的順序
存儲, 系統調用的返回值存放在EAX中

################################################################################################
# 十一,匯編語(yǔ)言的高級功能
################################################################################################
1,gnu內聯(lián)匯編的語(yǔ)法:
asm或__asm__("匯編代碼");
指令必須包含在引號里
如果包含的指令超過(guò)一行 必須使用新行分隔符分隔


使用c全局變量, 不能在內聯(lián)匯編中使用局部變量, 注意在匯編語(yǔ)言代碼中值被用做內存位置, 而不是立即數值

如果不希望優(yōu)化內聯(lián)匯編, 則可以volatile修飾符如:__asm__ volatile("code");

2,GCC內聯(lián)匯編的擴展語(yǔ)法
__asm__("assembly code":output locations:input operands:changed registers);
第一部分是匯編代碼
第二部分是輸出位置, 包含內聯(lián)匯編代碼的輸出值的寄存器和內存位置列表
第三部分是輸入操作數,包含內聯(lián)匯編代碼輸入值的寄存器和內存位置的列表
第四部分是改動(dòng)的寄存器, 內聯(lián)匯編改變的任何其他寄存器的列表
這幾個(gè)部分可以不全有, 但是沒(méi)有的還必須使用:分隔

1, 指定輸入值和輸出值, 輸入值和輸出值的列表格式為:
"constraint"(variable), 其中variable是程序中聲明的c變量, 在擴展asm格式中, 局部和全局變量都可以使用,
使用constrant(約束)定義把變量存放到哪(輸入)或從哪里傳送變量(輸出)
約束使用單一的字符, 如下:
約束 描述
a 使用%eax, %ax, %al寄存器
b 使用%ebx, %bx, %bl寄存器
c 使用%ecx, %cx, %cl寄存器
d 使用%edx, %dx, %dl寄存器
S 使用%esi, %si寄存器
D 使用%edi, %di寄存器
r 使用任何可用的通用寄存器
q 使用%eax, %ebx, %ecx,%edx之一
A 對于64位值使用%eax, %edx寄存器
f 使用浮點(diǎn)寄存器
t 使用第一個(gè)(頂部)的浮點(diǎn)寄存器
u 使用第二個(gè)浮點(diǎn)寄存器
m 使用變量的內存位置
o 使用偏移內存位置
V 只使用直接內存位置
i 使用立即整數值
n 使用值已知的立即整數值
g 使用任何可用的寄存器和內存位置


除了這些約束之外, 輸出值還包含一個(gè)約束修飾符:
輸出修飾符 描述
+ 可以讀取和寫(xiě)入操作數
= 只能寫(xiě)入操作數
% 如果有必要操作數可以和下一個(gè)操作數切換
& 在內聯(lián)函數完成之前, 可以刪除和重新使用操作數

如:
__asm__("assembly code": "=a"(result):"d"(data1),"c"(data2));
把c變量data1存放在edx寄存器中, 把c變量data2存放到ecx寄存器中, 內聯(lián)匯編的結果
將存放在eax寄存器中, 然后傳送給變量result


在擴展的asm語(yǔ)句塊中如果要使用寄存器必須使用兩個(gè)百分號符號


不一定總要在內聯(lián)匯編代碼中指定輸出值, 一些匯編指令假定輸入值包含輸出值, 如movs指令


其他擴展內聯(lián)匯編知識:
1, 使用占位符
輸入值存放在內聯(lián)匯編段中聲明的特定寄存器中, 并且在匯編指令中專(zhuān)門(mén)使用這些寄存器.
雖然這種方式能夠很好的處理只有幾個(gè)輸入值的情況, 但對于需要很多輸入值的情況, 這
中方式顯的有點(diǎn)繁瑣. 為了幫助解決這個(gè)問(wèn)題, 擴展asm格式提供了占位符, 可以在內聯(lián)
匯編代碼中使用它引用輸入和輸出值.

占位符是前面加上百分號的數字, 按照內聯(lián)匯編中列出的每個(gè)輸入和輸出值在列表中的位置,
每個(gè)值被賦予從0開(kāi)始的地方. 然后就可以在匯編代碼中引用占位符來(lái)表示值。


如果內聯(lián)匯編代碼中的輸入和輸出值共享程序中相同的c變量, 則可以指定使用占位符作為
約束值, 如:
__asm__("imull %1, %0"
: "=r"(data2)
: "r"(data1), "0"(data2));
如輸入輸出值中共享相同的變量data2, 而在輸入變量中則可以使用標記0作為輸入參數的約束

2, 替換占位符
如果處理很多輸入和輸出值, 數字型的占位符很快就會(huì )變的很混亂, 為了使條理清晰 ,GNU匯編
器(從版本3.1開(kāi)始)允許聲明替換的名稱(chēng)作為占位符.替換的名稱(chēng)在聲明輸入值和輸出值的段中
定義, 格式如下:
%[name]"constraint"(variable)
定義的值name成為內聯(lián)匯編代碼中變量的新的占位符號標識, 如下面的例子:
__asm__("imull %[value1], %[value2]"
: [value2] "=r"(data2)
: [value1] "r"(data1), "0"(data2));

3, 改動(dòng)寄存器列表
編譯器假設輸入值和輸出值使用的寄存器會(huì )被改動(dòng), 并且相應的作出處理。程序員不需要在改動(dòng)的
寄存器列表中包含這些值, 如果這樣做了, 就會(huì )產(chǎn)生錯誤消息. 注意改動(dòng)的寄存器列表中的寄存器
使用完整的寄存器名稱(chēng), 而不像輸入和輸出寄存器定義的那樣僅僅是單一字母。 在寄存器名稱(chēng)前面
使用百分號符號是可選的。

改動(dòng)寄存器列表的正確使用方法是, 如果內聯(lián)匯編代碼使用了沒(méi)有被初始化地聲明為輸入或者輸出
值的其他任何寄存器 , 則要通知編譯器。編譯器必須知道這些寄存器, 以避免使用他們。如:
int main(void) {
int data1 = 10;
int result = 20;

__asm__("movl %1, %%eax\n\t"
"addl %%eax, %0"
: "=r"(result)
: "r"(data1), "0"(result)
: "%eax");
printf("The result is %d\n", result);
return 0;
}

4, 使用內存位置
雖然在內聯(lián)匯編代碼中使用寄存器比較快, 但是也可以直接使用c變量的內存位置。 約束m用于引用輸入值
和輸出值中的內存位置。 記住, 對于要求使用寄存器的匯編指令, 仍然必須使用寄存器, 所以不得不定義
保存數據的中間寄存器。如:
int main(void) {
int dividentd = 20;
int divisor = 5;
int result;

__asm__("divb %2\n\t"
"movl %%eax, %0"
: "=m"(result)
: "a"(dividend), "m"(divisor));
printf("The result is %d\n", result);
return 0;
}

5, 處理跳轉
內聯(lián)匯編語(yǔ)言代碼也可以包含定義其中位置的標簽。 可以實(shí)現一般的匯編條件分支和無(wú)條件分支, 如:
int main(void) {
int a = 10;
int b = 20;
int result;

__asm__("cmp %1, %2\n\t"
"jge greater\n\t"
"movl %1, %0\n\t"
"jmp end\n"
"greater:\n\t"
"movl %2, %0\n"
"end:"
:"=r"(result)
:"r"(a), "r"(b));
printf("The larger value is %d\n", result);
return 0;
}

在內聯(lián)匯編代碼中使用標簽時(shí)有兩個(gè)限制。 第一個(gè)限制是只能跳轉到相同的asm段內的標簽,
不能從-個(gè)asm段跳轉到另一個(gè)asm段中的標簽。第二個(gè)限制更加復雜一點(diǎn)。 以上程序使用
標簽greater和end。 但是, 這樣有個(gè)潛在的問(wèn)題, 查看匯編后的代碼清單, 可以發(fā)現內聯(lián)
匯編標簽也被編碼到了最終匯編后的代碼中。 這意味著(zhù)如果在c代碼中還有另一個(gè)asm段, 就
不能再次使用相同的標簽, 否則會(huì )因為標簽重復使用而導致錯誤消息。還有如果試圖整合使用
c關(guān)鍵字(比如函數名稱(chēng)或者全局變量)的標簽也會(huì )導致錯誤。



################################################################################################
# 十二,優(yōu)化你的代碼
################################################################################################
GNU編譯器提供-O選項供程序優(yōu)化使用:
-O 提供基礎級別的優(yōu)化
-O2 提供更加高級的代碼優(yōu)化
-O3 提供最高級的代碼優(yōu)化
不同的優(yōu)化級別使用的優(yōu)化技術(shù)也可以單獨的應用于代碼。 可以使用-f命令行選項引用每個(gè)
單獨的優(yōu)化技術(shù)。

1, 編譯器優(yōu)化級別1
在優(yōu)化的第一個(gè)級別執行基礎代碼的優(yōu)化。 這個(gè)級別試圖執行9種單獨的優(yōu)化功能:
-fdefer-pop: 這種優(yōu)化技術(shù)與匯編語(yǔ)言代碼在函數完成時(shí)如何進(jìn)行操作有關(guān)。 一般
情況下, 函數的輸入值被保存在堆棧種并且被函數訪(fǎng)問(wèn)。 函數返回時(shí), 輸入值還在
堆棧種。 一般情況下, 函數返回之后, 輸入值被立即彈出堆棧。這樣做會(huì )使堆棧種
的內容有些雜亂。

-fmerge-constans: 使用這種優(yōu)化技術(shù), 編譯器試圖合并相同的常量. 這一特性有
時(shí)候會(huì )導致很長(cháng)的編譯時(shí)間, 因為編譯器必須分析c或者c++程序中用到的每個(gè)常量,
并且相互比較他們.

-fthread-jumps: 使用這種優(yōu)化技術(shù)與編譯器如果處理匯編代碼中的條件和非條件
分支有關(guān)。 在某些情況下, 一條跳轉指令可能轉移到另一條分支語(yǔ)句。 通過(guò)一連串
跳轉, 編譯器確定多個(gè)跳轉之間的最終目標并且把第一個(gè)跳轉重新定向到最終目標。

-floop-optimize: 通過(guò)優(yōu)化如何生成匯編語(yǔ)言中的循環(huán), 編譯器可以在很大程序上
提高應用程序的性能。 通常, 程序由很多大型且復雜的循環(huán)構成。 通過(guò)刪除在循環(huán)
內沒(méi)有改變值的變量賦值操作, 可以減少循環(huán)內執行指令的數量, 在很大程度上提高
性能。 此外優(yōu)化那些確定何時(shí)離開(kāi)循環(huán)的條件分支, 以便減少分支的影響。

-fif-conversion: if-then語(yǔ)句應該是應用程序中僅次于循環(huán)的最消耗時(shí)間的部分。
簡(jiǎn)單的if-then語(yǔ)句可能在最終的匯編語(yǔ)言代碼中產(chǎn)生眾多的條件分支。 通過(guò)減少
或者刪除條件分支, 以及使用條件傳送 設置標志和使用運算技巧來(lái)替換他們, 編譯
器可以減少if-then語(yǔ)句中花費的時(shí)間量。

-fif-conversion2: 這種技術(shù)結合更加高級的數學(xué)特性, 減少實(shí)現if-then語(yǔ)句所
需的條件分支。

-fdelayed-branch: 這種技術(shù)試圖根據指令周期時(shí)間重新安排指令。 它還試圖把
盡可能多的指令移動(dòng)到條件分支前, 以便最充分的利用處理器的治理緩存。

-fguess-branch-probability: 就像其名稱(chēng)所暗示的, 這種技術(shù)試圖確定條件分支最可
能的結果, 并且相應的移動(dòng)指令, 這和延遲分支技術(shù)類(lèi)似。 因為在編譯時(shí)預測代碼的安排,
所以使用這一選項兩次編譯相同的c或者c++代碼很可能會(huì )產(chǎn)生不同的匯編語(yǔ)言代碼, 這取決
于編譯時(shí)編譯器認為會(huì )使用那些分支。 因為這個(gè)原因, 很多程序員不喜歡采用這個(gè)特性, 并且
專(zhuān)門(mén)地使用-fno-guess-branch-probability選項關(guān)閉這個(gè)特性

-fcprop-registers: 因為在函數中把寄存器分配給變量, 所以編譯器執行第二次檢查以便減少
調度依賴(lài)性(兩個(gè)段要求使用相同的寄存器)并且刪除不必要的寄存器復制操作。
本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
《深入理解計算機系統》讀書(shū)筆記 —— 第三章 程序的機器級表示
AT&T匯編學(xué)習筆記
AT&T匯編語(yǔ)言與GCC內嵌匯編簡(jiǎn)介
SSE指令集優(yōu)化心得(二)
lea指令與mov指令
GCC-Inline-Assembly-HOWTO(C語(yǔ)言嵌入匯編)
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久