內 容 簡 介本書是風靡美國的經典匯編語言暢銷書籍的最新版,美國計算機領域著名作者Jeff Duntemann的力作。作者以其淵博的專業知識,豐富的實戰經驗,結合生動詳盡的實例,全面系統地介紹了Linux環境下如何使用匯編語言進行程序設計以及與之有關的背景知識和相關工具的使用。本書寫作風格獨特,全書采用作者最有特色的對話式風格,結合大量源于生活的暗喻,將晦澀難懂的知識點條分縷析地呈現出來,以便讀者能以輕松愉快的心情學習。本書適合剛涉足Linux環境下匯編語言的讀者,也可作為相關技術人員的參考書。目錄
第1章 又一個令人愉快的星期六 1
1.1 一切盡在計劃之中 1
1.1.1 步驟和測試 2
1.1.2 不止兩種方式 3
1.1.3 計算機像我們一樣
思考 4
1.2 如果這是真實情況 4
1.3 此路不通,請繞行 5
1.3.1 Big Bux游戲 6
1.3.2 玩Big Bux游戲 8
1.4 像棋盤游戲一樣的匯編語言
編程 9
1.4.1 代碼和數據 10
1.4.2 地址 11
1.4.3 隱喻,將軍 12
第2章 外星基數 14
2.1 新數學怪物歸來 14
2.2 在火星上計數 15
2.2.1 火星數字剖析 17
2.2.2 數字基數的本質 19
2.3 八進制:綠色精怪怎樣偷走
8和9的 19
2.4 十六進制:解決數字的短缺 23
2.5 從十六進制到十進制,從十進制
到十六進制 27
2.5.1 從十六進制到十進制 27
2.5.2 從十進制到十六進制 28
2.5.3 練習!練習!
再練習 30
2.6 十六進制運算 31
2.6.1 列和進位 34
2.6.2 減法和借位 34
2.6.3 跨多列借位 36
2.6.4 意義何在 37
2.7 二進制 37
2.7.1 二進制值 39
2.7.2 為什么使用二進制 41
2.8 二進制簡寫方式:十六進制 42
第3章 摘下面具 44
3.1 RAXie,我們怎么不認識你 44
3.2 開關、晶體管和存儲器 46
3.2.1 如果走陸路,就是1 47
3.2.2 晶體管開關 47
3.2.3 難以置信的位縮水 49
3.2.4 隨機訪問 51
3.2.5 存儲器訪問時間 52
3.2.6 字節,字,雙字,
四字 53
3.2.7 精致的芯片排成一行 54
3.2.8 車間工長和流水線 57
3.2.9 對話內存 57
3.2.10 駕馭數據總線 58
3.2.11 車間工長的口袋 59
3.2.12 流水線 60
3.3 遵循計劃行事的盒子 60
3.3.1 取指和執行 61
3.3.2 車間工長的內臟 62
3.3.3 改變航向 64
3.4 是什么vs.怎么做:體系結構和
微體系結構 65
3.4.1 體系結構的演變 66
3.4.2 地下室里的秘密機制 67
3.5 工廠經理 68
3.5.1 操作系統:角落
辦公室 69
3.5.2 BIOS:是軟件,但并
不軟 69
3.5.3 多任務魔術 70
3.5.4 內核提升 71
3.5.5 內核爆炸 73
3.5.6 計劃 73
第4章 位置,位置,位置 74
4.1 內存模式的樂趣 74
4.1.1 16 位將帶來64K
存儲空間 75
4.1.2 兆字節的本質 79
4.1.3 向后兼容和虛擬
86模式 80
4.1.4 16位眼罩 80
4.2 段的本質 81
4.2.1 一個界限,而非
一個位置 84
4.2.2 用兩個16位寄存器
構成20位地址 84
4.3 16位和32位寄存器 87
4.3.1 通用寄存器 88
4.3.2 半寄存器 90
4.3.3 指令指針寄存器 91
4.3.4 標志寄存器 92
4.4 三種主要的匯編編程模型 93
4.4.1 實模式平面模型 93
4.4.2 實模式段模型 95
4.4.3 保護模式平面模型 97
4.5 保護模式下不再允許我們做的
事情 100
4.5.1 內存映射視頻系統 100
4.5.2 直接訪問端口硬件 101
4.5.3 直接調用BIOS 102
4.6 展望未來:64位“長模式” 102
第5章 匯編的權利 105
5.1 文件及其包含的內容 106
5.1.1 二進制文件 vs.
文本文件 106
5.1.2 用 Bless 編輯器查看
文件內容 108
5.1.3 解釋原始數據 112
5.1.4 “字節序” 113
5.2 文本進去, 代碼出來 116
5.2.1 匯編語言 117
5.2.2 注釋 119
5.2.3 當心“只寫”
源代碼 120
5.2.4 目標代碼和連接器 120
5.2.5 重定位能力 123
5.3 匯編語言開發過程 124
5.3.1 工作目錄規范 125
5.3.2 編輯源代碼文件 126
5.3.3 編譯源代碼文件 126
5.3.4 匯編錯誤 127
5.3.5 回到編輯器 129
5.3.6 匯編警告 129
5.3.7 連接目標代碼文件 130
5.3.8 連接錯誤 131
5.3.9 測試.EXE文件 131
5.3.10 錯誤vs.漏洞 132
5.3.11 我們還在那里嗎 133
5.3.12 調試器和調試 133
5.4 沿著匯編小路旅行 134
5.4.1 安裝軟件 135
5.4.2 第1步:在編輯器中
編輯程序 137
5.4.3 第2步:使用NASM
編譯程序 138
5.4.4 第3步:使用LD
連接器 140
5.4.5 第4步:測試可執行
文件 141
5.4.6 第5步:在調試器中
觀察程序運行 142
5.4.7 準備好要來
真格的了嗎 148
第6章 有地兒,有工具 149
6.1 Kate 編輯器 151
6.1.1 安裝Kate編輯器 151
6.1.2 啟動Kate 152
6.1.3 配置 154
6.1.4 Kate 會話 156
6.1.5 Kate編輯器的
文件管理 158
6.1.6 向工具欄添加
菜單項 161
6.1.7 Kate編輯器的
編輯控制 162
6.1.8 編程期間使用Kate
編輯器 166
6.2 Linux 和終端 169
6.2.1 Linux 控制臺 169
6.2.2 Konsole中的字符
編碼 170
6.2.3 三個標準Unix文件 172
6.2.4 I/O 重定向 173
6.2.5 簡易文本過濾器 175
6.2.6 使用轉義序列進行終
端控制 177
6.2.7 為什么不用匯編語言編寫
GUI應用程序呢 178
6.3 使用Linux Make 179
6.3.1 依賴條件 180
6.3.2 文件何時最新 182
6.3.3 依賴鏈 182
6.3.4 從Kate編輯器內部
調用Make實用工具 184
6.3.5 使用touch命令強制
執行生成操作 187
6.4 Insight 調試器 187
6.4.1 運行Insight 188
6.4.2 Insight的眾多窗口 189
6.4.3 快速體驗Insight 190
6.4.4 拿起你的工具 193
第7章 跟蹤指令 194
7.1 為自己建立一個沙盒 194
7.1.1 一個最小的NASM
程序 195
7.1.2 指令及其操作數 197
7.1.3 源操作數和目標
操作數 197
7.1.4 立即數 198
7.1.5 寄存器數據 200
7.1.6 內存數據 202
7.1.7 混淆數據和它的
地址 203
7.1.8 內存數據的尺寸 204
7.1.9 糟糕的過去 204
7.2 CPU的標志位 205
7.2.1 標志規范 208
7.2.2 使用INC指令和DEC
指令加1和減1 208
7.2.3 從Insight中觀察
標志 209
7.2.4 標志如何改變程序的
執行 211
7.3 有符號值和無符號值 214
7.3.1 補碼和NEG 214
7.3.2 符號擴展和MOVSX 217
7.4 隱式操作數和Mul 219
7.4.1 MUL 和進位標志 221
7.4.2 使用DIV實現無符號
除法 221
7.4.3 x86中的“慢動作”
指令 223
7.5 閱讀和使用匯編語言參考資料 223
7.5.1 對于復雜記憶的喚醒
文件 224
7.5.2 初學者匯編語言參考
指南 224
7.5.3 標志 225
7.6 NEG:求補(求補碼;即,
與-1相乘) 225
7.6.1 合法形式 227
7.6.2 操作數符號 227
7.6.3 示例 228
7.6.4 注解 228
7.6.5 這里沒有包含的
內容 229
第8章 我們的崇高目標 230
8.1 匯編語言程序的基本框架 230
8.1.1 最開始處的注釋塊 232
8.1.2 .data段 233
8.1.3 .bss?段 233
8.1.4 .text段 234
8.1.5 標號 234
8.1.6 已初始化變量 235
8.1.7 字符串變量 235
8.1.8 通過EQU和$推導
字符串的長度 237
8.2 通過堆棧實現后進先出 239
8.2.1 每小時500個盤子 239
8.2.2 堆棧的內容上下
顛倒 241
8.2.3 Push-y指令 242
8.2.4 POP 指令 244
8.2.5 臨時存儲 246
8.3 通過INT80使用Linux內核
服務 247
8.3.1 不中斷任何事情的
中斷 247
8.3.2 再次返回 252
8.3.3 通過使用 INT 80h
退出一個程序 253
8.3.4 軟件中斷VS硬件
中斷 254
8.3.5 INT 80h和可移植性
盲目崇拜 255
8.4 設計一個有價值的程序 256
8.4.1 問題定義 257
8.4.2 從偽代碼開始 258
8.4.3 連續改進 259
8.4.4 不可避免的“哎呀!”
時刻 263
8.4.5 掃描緩沖區 264
8.4.6 緩沖溢出(“Off By One”)
錯誤 266
8.4.7 進一步學習 271
第9章 位、標志、分支和表 272
9.1 位就是二進制位(字節也是
二進制位) 272
9.1.1 位編號 273
9.1.2 邏輯操作 273
9.1.3 與指令 274
9.1.4 位屏蔽 275
9.1.5 或指令 276
9.1.6 異或指令 276
9.1.7 非指令 278
9.1.8 段寄存器對邏輯操作
沒有反應 278
9.2 移位操作 279
9.2.1 根據什么進行移位
操作 279
9.2.2 移位指令的工作
原理 279
9.2.3 將位移入進位標志 280
9.2.4 循環移位指令 280
9.2.5 將已知值存入進位
標志CF 282
9.3 位操作 282
9.3.1 將一個字節分解為
兩個“半字節” 285
9.3.2 將高半字節移入
低半字節 286
9.3.3 使用查找表 286
9.3.4 通過移位和相加來
實現相乘 288
9.4 標志、測試和分支 291
9.4.1 無條件轉移 292
9.4.2 條件轉移指令 292
9.4.3 條件“缺席”時
進行跳轉 293
9.4.4 標志 294
9.4.5 通過CMP進行
比較操作 295
9.4.6 轉移指令的錯綜
復雜之處 296
9.4.7 “大于”與“以上” 296
9.4.8 使用TEST指令
查找位1 298
9.4.9 使用BT指令
查找位0 300
9.5 保護模式下內存尋址詳解 301
9.5.1 有效地址計算 303
9.5.2 位移量 303
9.5.3 基址+位移量尋址
方式 304
9.5.4 基址+索引尋址方式 304
9.5.5 索引×縮放比例+位
移量尋址方式 305
9.5.6 其他尋址方式 307
9.5.7 LEA:最機密的
數學機器 309
9.5.8 16位寄存器的負擔 311
9.6 字符表轉換 312
9.6.1 轉換表 312
9.6.2 用MOV或者XLAT
進行轉換 315
9.7 用表來代替計算 319
第10章 分治 321
10.1 盒子里面的盒子 322
10.2 調用和返回 331
10.2.1 調用中的調用 334
10.2.2 意外遞歸的危險 335
10.2.3 一個需要提防的標志
規范Bug 336
10.2.4 過程及其所需的
數據 337
10.2.5 保存主調程序的
寄存器 338
10.2.6 局部數據 341
10.2.7 更多的表格技巧 342
10.2.8 在過程定義中加入
常量數據 344
10.3 局部標號和跳轉的長度 345
10.3.1 “強行”訪問局部
標號 348
10.3.2 短轉移、近轉移和
遠轉移 349
10.4 生成外部過程庫 350
10.4.1 全局聲明和外部
聲明 351
10.4.2 全局過程和外部
過程的機制 353
10.4.3 連接庫文件到
程序中 361
10.4.4 太多過程和太多庫的
危險 362
10.5 自定義過程的藝術 362
10.5.1 可維護性和
可重用性 363
10.5.2 確定哪些代碼應該
成為一個過程 364
10.5.3 使用注釋標頭 365
10.6 Linux控制臺下的簡單光標
控制 366
10.7 創建和使用宏 374
10.7.1 宏定義機制 375
10.7.2 定義帶參數的宏 380
10.7.3 宏調用機制 382
10.7.4 宏內部的局部標號 383
10.7.5 像包含文件一樣的
宏庫文件 384
10.7.6 宏?vs.?過程:優點和
缺點 385
第11章 字符串奏鳴曲 387
11.1 匯編語言字符串的概念 387
11.1.1 徹底顛覆你的
“字符串感覺” 388
11.1.2 源字符串和目標
字符串 388
11.1.3 虛擬文本顯示屏 389
11.2 REP STOSB,軟件機槍 397
11.2.1 機槍掃射虛擬
顯示器 397
11.2.2 執行STOSB 指令 398
11.2.3 STOSB 和方向
標志(DF) 399
11.2.4 在顯示緩沖區中
定義行 400
11.2.5 將緩沖區發送到
Linux控制臺 401
11.3 半自動武器:不帶REP的
STOSB 401
11.3.1 是誰遞減了ECX 402
11.3.2 LOOP指令 402
11.3.3 在屏幕上顯示一個
標尺 403
11.3.4 MUL并非 IMUL 404
11.3.5 添加ASCII數字 406
11.3.6 調整AAA 408
11.3.7 Ruler過程的教訓 409
11.3.8 STOS指令的16位
版本和32位版本 409
11.4 MOVSB:快速塊拷貝 409
11.4.1 DF和重疊塊移動 411
11.4.2 使用Insight單步調試
REP字符串指令 413
11.5 將數據存儲到不連續的
字符串中 414
11.5.1 顯示一個ASCII表 414
11.5.2 嵌套指令循環 416
11.5.3 當ECX變為0時
進行跳轉 416
11.5.4 關閉內層循環 417
11.5.5 關閉外層循環 418
11.5.6 Showchar小結 419
11.6 命令行參數和堆棧檢查 419
11.6.1 兩塊虛擬內存 420
11.6.2 Linux堆棧剖析 422
11.6.3 為什么堆棧的地址
是不可預測的 424
11.6.4 使用Insight設置
命令行參數 424
11.6.5 通過Insight的內存
視圖查看堆棧 425
11.7 使用SCASB進行字符串
搜索 427
11.7.1 REPNE v.s. REPE 431
11.7.2 從堆棧中彈出,
還是對堆棧尋址 432
11.7.3 額外的學分 434
第12章 C語言 435
12.1 什么是GNU 436
12.1.1 “瑞士軍刀”
編譯器 437
12.1.2 以GNU的方式生成
代碼 437
12.1.3 如何在匯編工作中
使用gcc 439
12.1.4 為什么不用gas 440
12.2 連接到標準的C函數庫 441
12.2.1 C調用公約 442
12.2.2 建立一個框架 443
12.2.3 保存和恢復寄存器 443
12.2.4 建立堆棧幀 444
12.2.5 銷毀堆棧幀 446
12.2.6 通過puts()輸出
字符 447
12.3 使用printf()格式化文本輸出 448
12.4 使用fgets()和scanf()進行
數據輸入 452
12.5 駕馭時間 459
12.5.1 C庫的時間機制 459
12.5.2 從系統時鐘中取出
time_t值 461
12.5.3 將time_t 值轉換為
一個格式化字符串 461
12.5.4 生成單獨的本地
時間值 462
12.5.5 通過使用MOVSD復制
glibc的tm結構 463
12.6 理解 AT&T 指令助記符 467
12.6.1 AT&T助記符公約 46712.6.2 查看gcc創建的gas
源文件 468
12.6.3 AT&T 內存引用
語法 471
12.7 產生隨機數 472
12.7.1 利用srand()為隨機
生成器“播種” 473
12.7.2 產生偽隨機數 474
12.7.3 有些位比其他位更具
隨機性 479
12.7.4 調用寄存器中的
地址 481
12.8 C如何看待命令行參數 482
12.9 簡單文件輸入/輸出 484
12.9.1 通過sscanf()將字符串
轉換為數字 485
12.9.2 創建和打開文件 486
12.9.3 使用fgets()從文件中
讀取文本 488
12.9.4 使用fprintf()寫文本到
文件中 490
12.9.5 關于收集過程到庫中的
注解 492
結論:不是結束,而是剛剛開始 501
附錄A 部分x86指令集 505
附錄B 字符集圖 565