新書推薦:
《
戈特曼情感大师系列6册:爱的沟通+幸福的婚姻+幸福的家庭+幸福婚姻的10大敌人+爱的博弈+当婚姻中有了孩子
》
售價:HK$
659.3
《
吐司三明治自己做最好吃:102款花样吐司+85款爆款三明治+11款轻食沙拉+5款灵魂抹酱
》
售價:HK$
43.8
《
DK马术全书(全新升级版)
》
售價:HK$
262.9
《
货币之手
》
售價:HK$
142.9
《
被困住的人(余华、李翊云等名家推崇的短篇大师,历时20多年创作,73个受困于生活的故事,洞见人性的幽微之处和人生的真相)
》
售價:HK$
240.9
《
灯花笑共此灯(全二册)
》
售價:HK$
76.8
《
系统家庭治疗的刻意练习
》
售價:HK$
83.5
《
2049:未来10000天的可能
》
售價:HK$
75.9
編輯推薦:
汇编语言是程序代码与芯片硬件的交汇点。然而,大多数初学者乃至资深工程师常因汇编语言的复杂性望而却步,转而依赖高级语言完成工作。在《Linux x64汇编语言编程》中,知名作家Jeff Duntemann全面更新了这本汇编语言指南,专注于解析Linux环境下64位长模式(long-mode)的技术实践,指导你写出效率高、空间省、速度快的汇编程序。
內容簡介:
《Linux x64汇编语言编程》介绍二进制、十六进制、计算、编程和x64架构的基础知识,分析Linux软件开发过程,讲解NASM汇编器、x64指令集、内存寻址、过程、宏及Linux的C库函数接口,披露软件设计、编码、测试和调试的实用技巧。本书示例代码丰富,文笔幽默,将深奥的知识讲得简单易懂,引导你循序渐进地学会汇编编程。
來源:香港大書城megBookStore,http://www.megbook.com.hk 《Linux x64汇编语言编程》是权威的Intel/AMD x64教程,是学习x64汇编语言的黄金标准,非常适合自学。
關於作者:
Jeff Duntemann,是一位在科幻文学与技术领域皆有建树的知名作家,发表技术文章逾百篇;现为技术出版顾问兼Copperwood Press独立出版人。Jeff迄今已撰写20本技术书籍。Jeff曾在Dr. Dobbs Journal?杂志撰写“结构化编程”专栏达四年之久,并在其他杂志上发表了数十篇技术文章。其作品以技术深度与叙事魅力的完美融合著称。
目錄 :
第1章 一切都在计划之中——真正理解计算机的工作原理 1
1.1 完美的周六计划 1
1.1.1 步骤和测试 2
1.1.2 决定总是具有二元性 3
1.1.3 计算机像我们一样思考 4
1.2 如果这是真的 4
1.3 将汇编语言编程比作方块舞 4
1.4 将汇编语言编程比作棋盘游戏 5
1.4.1 代码和数据 6
1.4.2 地址 7
1.4.3 总结 7
第2章 外星人基地——理解二进制和十六进制 9
2.1 新数学怪兽的回归 9
2.1.1 使用火星文计数 10
2.1.2 剖析火星数字 12
2.1.3 数基的本质 13
2.2 八进制:鬼精灵如何偷走8和9 13
2.3 十六进制:解决数字短缺问题 17
2.4 从十六进制到十进制以及从十进制到十六进制 20
2.4.1 从十六进制到十进制 21
2.4.2 从十进制到十六进制 22
2.5 练习!练习!练习! 23
2.6 十六进制算术 24
2.6.1 列和进位 26
2.6.2 减法和借位 27
2.6.3 跨多列借位 28
2.6.4 重点是什么? 29
2.7 二进制 29
2.7.1 二进制值 31
2.7.2 为什么是二进制 33
2.8 十六进制作为二进制的简写 33
2.9 准备计算 35
第3章 揭开面纱——了解计算机的真实面貌 36
3.1 RAX寄存器,我们几乎不了解 36
3.2 开关、晶体管和内存 38
3.2.1 如果敌方陆路来袭,则点亮一盏灯 38
3.2.2 晶体管开关 39
3.2.3 令人难以置信的比特缩小现象 41
3.2.4 随机访问 42
3.2.5 内存访问时间 44
3.2.6 字节、字、双字和四字 44
3.2.7 排成一排的精美芯片 45
3.3 CPU和装配线 48
3.3.1 与内存对话 48
3.3.2 搭乘数据总线 49
3.3.3 寄存器 50
3.3.4 装配线 51
3.4 遵循计划的盒子 51
3.4.1 获取并执行 52
3.4.2 CPU的内部结构 53
3.4.3 改变路线 55
3.5 什么与如何:架构和微架构 56
3.5.1 不断演变的架构 56
3.5.2 地下室的秘密机器 57
3.6 工厂经理 58
3.6.1 操作系统:转角办公室 59
3.6.2 BIOS:软件不“软” 59
3.6.3 多任务魔法 60
3.6.4 提升至内核 61
3.6.5 内核爆炸 62
3.6.6 计划 63
第4章 寻址、寻址、寻址——寄存器、内存寻址及了解数据的位置 64
4.1 内存模型的乐趣 64
4.1.1 16位能“买到”64KB 65
4.1.2 兆字节(MB)的本质 68
4.1.3 向后兼容和虚拟86模式 69
4.1.4 16位的视野限制 70
4.2 分段的本质 71
4.2.1 一条地平线,而不是一个具体位置 74
4.2.2 使用16位寄存器生成20位地址 74
4.3 分段寄存器 76
4.3.1 分段寄存器和x64 77
4.3.2 通用寄存器 77
4.3.3 寄存器的高位和低位 79
4.3.4 指令指针 81
4.3.5 标志寄存器 82
4.3.6 数学协处理器及其寄存器 82
4.4 四种主要的汇编编程模型 83
4.4.1 实模式平面模型 83
4.4.2 实模式分段模型 85
4.4.3 32位保护模式平面模型 87
4.4.4 64位长模式编程模型 89
第5章 汇编的正确方式——汇编语言程序的开发过程 91
5.1 编程的96种方法 91
5.2 文件及其内容 92
5.2.1 二进制文件与文本文件 92
5.2.2 使用GHex十六进制编辑器查看二进制文件内部 94
5.2.3 解释原始数据 97
5.2.4 字节顺序 98
5.3 输入文本,输出代码 102
5.3.1 汇编语言 102
5.3.2 注释 104
5.3.3 当心“只写源代码”! 105
5.3.4 目标代码、链接器和库 106
5.3.5 可重定位性 108
5.4 汇编语言的开发过程 108
5.4.1 工作目录的规则 110
5.4.2 编辑源代码文件 110
5.4.3 汇编源代码文件 111
5.4.4 汇编器错误 111
5.4.5 回到编辑器 113
5.4.6 编译器警告 113
5.5 链接目标代码文件 114
5.5.1 链接器错误 115
5.5.2 测试EXE文件 115
5.5.3 错误与缺陷 116
5.5.4 调试器和调试 117
5.6 走进汇编语言的世界 117
5.6.1 安装软件 118
5.6.2 步骤1:在编辑器中编辑程序 120
5.6.3 步骤2:使用NASM汇编程序 121
5.6.4 步骤3:使用ld链接程序 123
5.6.5 步骤4:测试可执行文件 124
5.6.6 步骤5:在调试器中观察它的运行 124
第6章 一个可使用工具的立足之地——Linux和塑造你的工作方式的工具 126
6.1 集成开发环境(IDE) 126
6.2 SASM简介 128
6.2.1 配置SASM 129
6.2.2 SASM的字体 130
6.2.3 使用编译器链接 130
6.2.4 SASM速览 132
6.2.5 SASM的编辑器 134
6.2.6 SASM对你的代码有何要求 134
6.3 Linux和终端 135
6.3.1 Linux控制台 136
6.3.2 Konsole中的字符编码 136
6.3.3 三个标准UNIX文件 138
6.3.4 I/O重定向 139
6.3.5 简单文本过滤器 141
6.3.6 使用SASM内部的标准输入和标准输出 142
6.3.7 使用转义序列进行终端控制 142
6.3.8 为什么不使用GUI应用程序 143
6.4 使用Linux Make 145
6.4.1 依赖 145
6.4.2 当文件是最新的 147
6.4.3 依赖链 148
6.4.4 调用Make 149
6.4.5 为Make创建自定义按键绑定 150
6.4.6 使用touch强制构建 151
6.5 使用SASM进行调试 152
第7章 遵循你的指令——近距离观察机器指令 154
7.1 构建自己的沙箱 154
7.2 指令及其操作数 157
7.3 源操作数和目标操作数 157
7.3.1 即时数据 158
7.3.2 寄存器数据 160
7.3.3 内存数据和有效地址 162
7.3.4 混淆数据及其地址 162
7.3.5 内存数据的大小 163
7.3.6 糟糕的旧时光 164
7.4 团结在“标志”周围 164
7.4.1 标志礼仪 167
7.4.2 在SASM中观察标志 167
7.4.3 使用INC和DEC进行加1和减1操作 167
7.4.4 标志如何改变程序的执行 169
7.4.5 如何检查SASM中的变量 170
7.5 有符号值和无符号值 172
7.5.1 二进制补码和NEG 172
7.5.2 符号扩展和MOVSX 174
7.6 隐式操作数和MUL 176
7.6.1 MUL和进位标志 177
7.6.2 使用DIV进行无符号除法 178
7.6.3 MUL和DIV速度很慢 179
7.7 阅读和使用汇编语言参考 180
7.7.1 复杂记忆的备忘录 180
7.7.2 初学者的汇编语言参考 181
7.7.3 标志 181
7.8 NEG取反(二进制补码,即乘以-1) 182
7.8.1 受影响的标志 182
7.8.2 有效形式 182
7.8.3 示例 182
7.8.4 备注 182
7.8.5 有效形式 183
7.8.6 操作数符号 183
7.8.7 示例 184
7.8.8 备注 184
7.8.9 这里没有提到的内容…… 185
第8章 我们崇高的目标——创建有效的程序 186
8.1 汇编语言程序的骨架 186
8.1.1 初始注释块 188
8.1.2 .data部分 188
8.1.3 .bss部分 189
8.1.4 .text部分 189
8.1.5 标签 190
8.1.6 初始化数据的变量 191
8.1.7 字符串变量 191
8.1.8 使用EQU和$推导字符串长度 193
8.2 通过栈后进先出 194
8.2.1 每小时500个盘子 195
8.2.2 倒置堆叠 196
8.2.3 压入指令 197
8.2.4 POP指令登场 198
8.2.5 PUSHA和POPA已停用 199
8.2.6 压入和弹出的详细信息 200
8.2.7 短期存储 201
8.3 通过SYSCALL使用Linux内核服务 202
8.3.1 通过SYSCALL指令使用x64内核服务 202
8.3.2 ABI与API的区别 203
8.3.3 ABI的寄存器参数方案 203
8.3.4 通过SYSCALL退出程序 204
8.3.5 被SYSCALL破坏的寄存器 205
8.4 设计一个不平凡的程序 205
8.4.1 定义问题 206
8.4.2 从伪代码开始 207
8.4.3 持续改进 207
8.4.4 那些不可避免的惊讶时刻 211
8.4.5 扫描缓冲区 212
8.4.6 差一错误 214
8.4.7 从伪代码到汇编代码 215
8.4.8 SASM输出窗口的陷阱 218
8.4.9 进一步学习 218
第9章 位、标志、分支和表——逐步驶入汇编编程的主航道 219
9.1 位就是位(字节也是位) 219
9.1.1 位编号 220
9.1.2 最合乎逻辑的做法 220
9.1.3 AND指令 221
9.1.4 掩码位 221
9.1.5 OR指令 223
9.1.6 XOR(异或)指令 223
9.1.7 NOT指令 224
9.1.8 分段寄存器没有逻辑 225
9.2 移位 225
9.2.1 通过什么移位 226
9.2.2 移位的工作原理 226
9.2.3 将位放入进位标志 227
9.2.4 旋转指令 227
9.2.5 通过进位标志旋转位 228
9.2.6 将已知值设置到进位标志中 228
9.3 位操作实战 229
9.3.1 将一字节拆分成两个“半字节” 232
9.3.2 将高半字节移入低半字节 232
9.3.3 使用查找表 233
9.3.4 通过移位和加法进行乘法 234
9.4 标志、测试和分支 237
9.4.1 无条件跳转 237
9.4.2 有条件跳转 238
9.4.3 在缺少条件的情况下跳转 239
9.4.4 标志 240
9.4.5 使用CMP进行比较 240
9.4.6 跳转指令的“丛林” 241
9.4.7 “大于”与“高于” 241
9.4.8 使用TEST查找1位 243
9.4.9 使用BT寻找0位 244
9.5 x64长模式内存寻址详解 244
9.5.1 有效地址计算 246
9.5.2 位移 247
9.5.3 x64位移大小问题 247
9.5.4 基址寻址 248
9.5.5 基址 位移寻址 248
9.5.6 基址 索引寻址 248
9.5.7 索引×比例 位移寻址 249
9.5.8 其他寻址方案 251
9.5.9 LEA:绝密数学机器 253
9.6 字符表转换 254
9.6.1 转换表 254
9.6.2 使用MOV或XLAT进行转换 256
9.7 用表代替计算 261
第10章 分而治之——使用过程和宏来应对程序复杂性 262
10.1 层层嵌套 263
10.2 调用和返回 272
10.2.1 调用中的调用 274
10.2.2 意外递归的危险 275
10.2.3 需要警惕的标志相关错误 276
10.2.4 过程及其所需的数据 278
10.2.5 保存调用者的寄存器 278
10.2.6 在Linux系统调用中保存寄存器 280
10.2.7 PUSHAD和POPAD已废弃 281
10.2.8 本地数据 283
10.2.9 在过程定义中放置常量数据 283
10.2.10 更多表技巧 285
10.3 本地标签和跳转的长度 287
10.3.1 强制本地标签访问 290
10.3.2 短、近和远跳转 290
10.4 构建外部过程库 291
10.4.1 当工具达到极限时 292
10.4.2 在SASM中使用包含文件 292
10.4.3 SASM包含文件的存储位置 299
10.4.4 创建包含文件库的最佳方法 300
10.4.5 独立汇编和模块 301
10.4.6 全局和外部声明 301
10.4.7 全局变量和外部变量的机制 303
10.4.8 将库链接到程序中 313
10.4.9 太多过程和库会造成危险 313
10.5 制作过程的艺术 314
10.5.1 可维护性和重用性 314
10.5.2 决定什么应该是一个过程 315
10.5.3 使用注释标题 316
10.6 Linux控制台中的简单光标控制 317
10.7 创建和使用宏 325
10.7.1 宏定义的机制 326
10.7.2 定义带参数的宏 332
10.7.3 调用宏的机制 333
10.7.4 宏内的本地标签 334
10.7.5 宏库作为包含文件 335
10.7.6 宏与过程:优点和缺点 335
第11章 字符串及其他——那些令人惊叹的字符串指令 337
11.1 汇编语言字符串的概念 338
11.1.1 彻底改变你的“字符串感” 338
11.1.2 源字符串和目标字符串 339
11.1.3 文本显示虚拟屏幕 339
11.2 REP STOSB:软件机关枪 347
11.2.1 机关枪式操作虚拟显示 348
11.2.2 执行STOSB指令 348
11.2.3 STOSB和方向标志DF 349
11.2.4 定义显示缓冲区中的行 350
11.2.5 将缓冲区发送到Linux控制台 351
11.3 半自动武器:没有REP的STOSB 351
11.3.1 谁减少了RCX? 352
11.3.2 LOOP指令 352
11.3.3 在屏幕上显示标尺 353
11.3.4 MUL不是IMUL 354
11.3.5 Ruler的教训 355
11.3.6 STOS的四种大小 355
11.3.7 再见,BCD算术 356
11.4 MOVSB:快速块复制 356
11.4.1 DF和重叠阻挡移动 357
11.4.2 单步REP字符串指令 360
11.5 将数据存储到不连续的字符串中 361
11.5.1 显示一个ASCII表 361
11.5.2 嵌套指令循环 366
11.5.3 当RCX变为0时跳转 367
11.5.4 关闭内循环 367
11.5.5 关闭外循环 368
11.5.6 回顾showchar 369
11.6 命令行参数、字符串搜索和Linux栈 369
11.6.1 显示SASM的命令行参数 370
11.6.2 使用SCASB进行字符串搜索 373
11.6.3 REPNE与REPE 374
11.6.4 无法将命令行参数传递给SASM中的程序 375
11.7 栈及其结构和使用方法 375
11.7.1 直接访问栈 377
11.7.2 程序序言和结语 380
11.7.3 栈上的寻址数据 381
11.7.4 不要弹出 382
第12章 转向C——调用C语言编写的外部函数 383
12.1 GNU 384
12.1.1 瑞士军刀编译器 385
12.1.2 以GNU方式构建代码 385
12.1.3 SASM使用GCC 387
12.1.4 如何在汇编工作中使用gcc 387
12.1.5 为什么不使用gas 388
12.2 链接标准C库 389
12.2.1 C调用约定 390
12.2.2 调用者、被调用者和破坏者 390
12.2.3 设置栈帧 392
12.2.4 在结语中销毁栈帧 393
12.2.5 栈对齐 393
12.2.6 通过puts()输出字符 395
12.3 使用printf()格式化文本输出 397
12.3.1 将参数传递给printf() 398
12.3.2 printf()需要在RAX中加上前置0 399
12.3.3 你需要使用-no-pie选项 400
12.4 使用fgets()和scanf()输入数据 400
12.5 成为Linux时间领主 406
12.5.1 C库的时间机器 406
12.5.2 从系统时钟获取time_t值 407
12.5.3 将time_t值转换为格式化字符串 408
12.5.4 生成单独的本地时间值 409
12.5.5 使用MOVSD复制glibc的tm结构 409
12.6 理解AT&T指令助记符 413
12.6.1 AT&T助记符约定 413
12.6.2 AT&T内存引用语法 415
12.7 生成随机数 416
12.7.1 使用srand()为生成器设定种子 416
12.7.2 生成伪随机数 417
12.7.3 相比之下有些比特更随机 423
12.7.4 调用寄存器中的地址 425
12.7.5 使用puts()将一个裸换行符发送到控制台 426
12.7.6 如何向libc函数传递六个以上的参数 426
12.8 C语言如何处理命令行参数 427
12.9 简单文件 I/O 430
12.9.1 使用sscanf()将字符串转换为数字 431
12.9.2 创建和打开文件 432
12.9.3 使用fgets()从文件读取文本 434
12.9.4 使用fprintf()将文本写入文件 436
12.9.5 将过程收集到库中的注意事项 437
12.10 永远学习,永远不要停下来 444
12.10.1 何去何从 445
12.10.2 走出原点 446
(以下内容可扫描封底二维码下载)
附录A Insight调试器的回归 447
附录B 部分x64指令参考 454
附录C 字符集图表 509
內容試閱 :
“你为什么要那样做?”
那是1985年,我在纽约市乘坐包车去参加一个新闻发布会,同行的还有一群焦躁不安的媒体狂人。我当时刚刚开始我的科技记者生涯(担任PC Tech Journal的技术编辑),我的第一本书还要几个月后才会问世。碰巧,我坐在一位著名的编程作家/专家旁边,我对他印象深刻,因为他一直在对我唠叨一些事情。他确实很烦人,但我现在才明白为什么他那么令人讨厌:他的生活和工作与我完全没有交集。
在我们的聊天中,我无意中透露了我是一个Turbo Pascal狂热爱好者,而我真正想做的是学习如何编写利用全新Microsoft Windows用户界面的Turbo Pascal程序。他皱了皱鼻子,苦笑了一下,然后问出了那个著名的问题:
“你为什么要那样做?”
那时我还从未听过这个问题(尽管后来我听到了很多次),这让我很惊讶。“为什么?因为,嗯,因为……我想知道它是如何工作的。”我这样想着,于是答道,
“呵呵,那就是C语言的用途。”
进一步的讨论并没有让我在Pascal的方向上有所进展。但经过一番探索,我明白了不能用Turbo Pascal编写Windows应用程序。这是不可能的。或者……那位编程作家/专家不知道怎么做。也许两者皆有。我从未了解过1985年的真实情况。Delphi在1995年彻底解答了这个问题。但我确实了解了那个著名问题的含义。
请注意,如果有人问你:“你为什么要那样做?”它的真正意思是:你问我如何做一件事情,这件事要么不可能用我偏爱的工具实现,要么完全超出了我的经验范围,但我不想通过承认这一点而失去面子。
这些年来我一次又一次听到这样的话:
问:如何设置C字符串,以便不必扫描即可读取其长度?
答:你为什么要那样做?
问:如何编写可从Turbo Pascal调用的汇编语言子程序?
答:你为什么要那样做?
问:如何用汇编语言编写Windows应用程序?
答:你为什么要那样做?
……
你明白这个意思了。对于这个著名的问题,答案永远都是一样的。如果那些狡猾的人问你这个问题,你就尽快反击:“因为我想知道它是如何运作的。”
这是一个完全足够的回答。每次我都用这个答案,除了很多年前的一个例外,那时我提出我想写一本书,教人们如何将汇编语言编程作为他们的第一次编程体验。
问:天哪,你为什么要那样做?
答:因为这是培养理解编程世界其他部分如何运作所需技能的最佳方式。
成为一名程序员,首先要做到的一点是理解事物的工作原理。此外,学习成为一名程序员几乎完全是一个了解事物如何运作的过程。这可以在不同层次上完成,具体取决于你使用的工具。
如果你使用的是Visual Basic编程,你需要理解某些事物的工作原理,但这些事物基本上都局限于Visual Basic本身。Visual Basic在程序员与计算机之间设置了一道屏障,隐藏了大量的底层机制。Delphi、Lazarus、Java、Python及许多其他高级编程环境也是如此。如果你使用的是C编译器,你会离机器更近,你会看到更多的底层机制——因此,你必须理解这些机制的工作原理才能使用它们。然而,即使是资深的C程序员,也有许多东西仍然隐藏在他们的视野之外。
一方面,如果你在使用汇编语言编程,你会尽可能地接近机器。汇编语言不隐藏任何东西,也不会保留任何能力。当然,另一方面,你和机器之间没有任何神奇的层可以消除任何无知并且可以“处理”一切。如果你不理解某些东西的工作原理,你就会陷入困境——除非你足够了解,能够自己弄明白。
这是一个关键点:我编写本书的目标并非仅是讲授汇编语言本身。如果说本书有一个首要目标的话,那就是让你对机器底层产生一定的好奇心,同时提供一些基本的背景知识,帮助你开始探索机器的最底层,以及给予你信心去尽力尝试。这是困难的地方,但只要你集中注意力、耐心等待并投入必要的时间(可能会相当长),你完全可以掌握它。
实际上,我真正教给你的,是如何去学习。
你需要什么
要按照我所讲授的方式进行编程,你需要一台运行64位Linux发行版的英特尔计算机。我在编写这本书时使用的是Linux Mint Cinnamon V20.3 Una。Una是这个Linux Mint版本的代码名称,是“Linux Mint 20.3”的简写。我推荐使用Mint;它给我带来的麻烦比我用过的任何其他发行版都少,而且自从Linux首次出现以来,我就断断续续地使用它。我认为你选择哪个图形化shell并不重要。我喜欢Cinnamon,你可以使用自己喜欢或熟悉的任何界面。
你需要在用户级别上对Linux有一定的熟练掌握能力。我无法在本书中教你如何安装、配置和运行Linux。如果你还不熟悉Linux,请找一本教程,学习并掌握它。网上有很多这样的教程。
你需要一款名为SASM的免费软件,这是一种简单的汇编编程交互式开发环境。它基本上包括一个编辑器、一个构建系统,以及一个标准Linux调试器gdb的前端。你还需要一个免费的汇编器,名为NASM。
你不需要提前知道如何下载、安装和配置这些工具,因为在适当的时机,我会详细介绍所有必要的工具安装和配置方式。
请注意,其他不基于Linux内核的UNIX实现可能在底层的工作方式上有所不同。例如,BSD UNIX在进行系统调用时使用了不同的约定,而其他UNIX版本(如Solaris)则超出了我的经验范围。
请记住,本书是关于x64架构的。在x64的范围内,我也会讲解x86架构的元素。32位x86和64位x64之间的差距比16位x86和32位x86之间的差距要小得多。如果你已经扎实掌握了32位x86的基础知识,你将很快掌握本书的大部分内容。如果你能做到这一点,那很好——只是请记住,本书是为了那些刚刚开始在英特尔CPU上编程的人准备的。
还要记住,这本书的版面受出版商的限制:纸张、油墨和装订都不免费。这意味着我必须在这些限制内缩小我讲授和解释的内容范围。我希望有足够的篇幅来介绍AVX数学子系统,而实际上没有。但是,我相信,一旦你读完这本书,就能搞清楚其中的大部分内容。
总体规划
本书从最基础的知识开始讲解。也许你在这个阶段,已经完全掌握了这些。我尊重这一点。我仍然认为,从第1章开始,一直到最后一章按顺序阅读不会有什么坏处。复习是有用的,你可能会意识到你对某些内容的了解没有你想象的那么深刻(这种情况经常发生在我身上)。
如果时间紧迫,可以按照下面的建议进行学习:
●如果你已经了解计算机编程的基本思想,请跳过第1章。
●如果你已经了解十进制以外的其他数字进制(尤其是十六进制和二进制)背后的思想,请跳过第2章。
●如果你已经掌握了计算机的内部结构(内存、CPU架构等),请跳过第3章。
●如果你已经了解x64内存寻址,请跳过第4章。
●不。停下来。即使你已经了解x64内存寻址,也请阅读第4章。
最后一项需要特别强调一下,原因是:汇编语言编程涉及内存寻址。如果你不理解内存寻址,那么你在汇编语言中学到的其他任何知识都不会对你有帮助。所以,无论你已经知道或认为自己知道什么,都不要跳过第4章。从那里开始,一直到最后。内存寻址在书的其余部分会经常出现,它实际上是汇编语言编程的核心。
加载每个示例程序,汇编每个程序,并运行它们。努力理解每个程序中的每一行。不要盲目相信任何东西。此外,别仅仅停留于此。随着你对事物的理解加深,可修改示例程序。尝试不同的方法,尝试一些我没有提到的做法,要大胆,可以尽情尝试。最糟糕的情况只是Linux抛出一个分段错误,这可能损坏你的程序,但不会损害Linux。唯一的注意事项是,当你尝试某些做法时,尽量理解为什么它没有像你理解的其他有效事物那样井井有条地工作。即使程序运行正常,也要在SASM调试器中逐步调试。
这就是我最终追求的目标:展示如何理解机器的每一个细节是如何运作的,以及它的所有组件是如何协同工作的。这并不意味着我会亲自解释它的每一个细节——因为没有人能活得足够久去做到这一点,而且计算机技术已经不再简单了。如果你已经养成耐心研究和实验的习惯,你可以自己弄明白。归根结底,这就是学习的唯一途径:靠自己。从朋友、网络或像这样的书籍中得到的指导只是引导和润滑剂。你必须决定谁才是主宰,是你还是机器,并使之成为现实。
关于大写惯例的说明
汇编语言在编程语言中有一个独特之处,即没有统一的大小写区分标准。在C语言中,所有标识符都区分大小写,而我见过一些汇编器完全不区分大小写。本书介绍的汇编器NASM,仅对程序员定义的标识符区分大小写,指令助记符和寄存器名称是不区分大小写的。
汇编语言文献中有一个习惯,那就是在章节描述中将CPU指令助记符用大写字母表示,而源代码文件和文本中的代码段用小写字母表示。本书也会遵循这一习惯。在正文中,会使用MOV、CALL和CMP;而在示例代码中,则使用mov、call和cmp。代码片段和代码清单将以等宽的Courier风格字体呈现。当提到寄存器时,会使用大写字母(但不使用Courier字体),而在代码片段和清单中则使用小写字母。
在正文中,助记符需要突出显示(用大写字母)。在一大堆普通的大小写字母混合的单词中,很容易忘记它们。
要阅读和学习本书以外的现有文档和源代码,你需要能够轻松地阅读大写、小写以及混合大小写的汇编语言。熟悉不同的表达方式非常重要。
记住你为什么在这里
不管你选择从书的哪一部分开始,现在是时候开始了。只要记住,假如遇到困难,无论是面对微妙的问题还是面对机器故障,你要始终把这个目标放在心中:要努力搞清楚它是如何运作的。
让我们一起出发吧。
源代码下载
可扫描封底二维码,下载源代码。