- 浏览: 141164 次
文章分类
最新评论
Intel 中常用术语“字(word)”表示 16 位数据类型,因此 32 位数称为“双字(double words)”,64 位数称为“四字(quad words)”。下表中给出了 C 语言基本数据类型对应的 x86-64 表示。
如图所示,大多数 GCC 生成的汇编代码指令都有一个字符的后缀(本文中都是使用 ATT 而非 Intel 汇编代码格式),表明操作数的大小。例如,数据传送指令有四个变种:movb(传送字节)、movw(传送字)、movl(传送双字)和 movq(传送四字)。后缀“l”用来表示双字,因为 32 位数被看成是“长字(long word)”。注意,虽然汇编代码中的 4 字节整数和 8 字节双精度浮点数都使用了该后缀来表示,但这不会产生歧义,因为浮点数使用的是一组完全不同的指令和寄存器。
一个 X86-64 的 CPU 包含一组 16 个存储 64 位值的通用目的寄存器,用来存储整数数据和指针。下图中显示了这 16 个寄存器。它们的名字都以“%r”开头,后面则跟以随指令集历史演化而来的不同命名规则的名字。最初的 8086 中有 8 个 16 位的寄存器,对应图中的 %ax 到 %bp。每个寄存器都有特殊的用途。扩展到 IA32 架构时,这些寄存器也扩展成 32 位,标号从 %eax 到 %ebp。扩展到 x86-64 后,原来的 8 个寄存器也随之扩展成 64 位,标号从 %rax 到 %rbp。除此之外,还增加了 8 个新的寄存器,它们的标号是按照新的命名规则制定的:从 %r8 到 %r15。
指令可以对这 16 个寄存器的低位字节中存放的不同大小的数据进行操作:字节级操作可以访问最低的字节,16 位操作可以访问最低的 2 个字节,32 位操作可以访问最低的 4 个字节,而 64 位操作可以访问整个寄存器。
当相关指令以寄存器作为目标时,对于生成小于 8 字节结果的指令,对寄存器中剩下的字节的处理有两条规则:生成 1 字节和 2 字节数字的指令会保持剩下的字节不变;生成 4 字节数字的指令会把高位 4 个字节置为 0,这是作为从 IA32 到 x86-64 的扩展的一部分而采用的。
多数指令都有一个或多个操作数(operand),用于指示一个操作中要使用的源数据值,以及放置结果的目的位置。源数据值可以是常数,或是从寄存器或内存中读出,结果可以存放在寄存器或内存中。因此,各种不同的操作数的可能性被分为三种类型。第一种是立即数(immediate),用来表示常数值。在 ATT 格式的汇编代码中,立即数的书写方式是“$”后面跟一个用标准 C 表示法表示的整数,如 $-577 或 $0x1F。不同的指令允许的立即数值范围不同,汇编器会自动选择最紧凑的方式进行数值编码。第二种是寄存器(register),它表示某个寄存器的内容。第三类是内存引用,它会根据计算出来的地址(通常称为有效地址)访问某个内存位置。x86-64 支持多种不同的寻址模式,允许不同形式的内存引用,如下表所示。
图中,使用符号 ra 来表示任意寄存器 a,用引用 R[ra] 来表示它的值,这是将寄存器集合看成一个数组 R,用寄存器标识符作为索引。对于内存引用,因为可以将内存看成一个很大的字节数组,所以用符号 Mb[Addr] 表示对存储在内存中从地址 Addr 开始的 b 个字节值的引用(为了简便,通常省略下标 b)。表中底部用语法 Imm(rb, ri, s) 表示的是最常用的形式,它有四个组成部分:一个立即数偏移 Imm,一个基址寄存器 rb,一个变址寄存器 ri 和一个比例因子 s。注意,这里 s 必须是 1、2、4 或者 8,基址和变址寄存器都必须是 64 位寄存器。有效地址被计算为:Imm + R[rb] + R[ri]*s。引用数组元素时,会用到这种通用形式,其他形式都是这种的特殊情况。在引用数组和结构元素时,比较复杂的寻址模式是很有用的。
下面是一个数据交换函数的 C 语言代码。
其对应的汇编代码主体部分如下。
从这段汇编代码中可以看出,C 语言中所谓的“指针”其实就是地址。间接引用指针就是将该指针放在一个寄存器中,然后在内存引用中使用这个寄存器。其次,像 x 这样的局部变量通常是保存在寄存器而不是内存中,因为访问寄存器要比访问内存快得多。
参考书籍:《深入理解计算机系统》第三版第三章——程序的机器级表示。
如图所示,大多数 GCC 生成的汇编代码指令都有一个字符的后缀(本文中都是使用 ATT 而非 Intel 汇编代码格式),表明操作数的大小。例如,数据传送指令有四个变种:movb(传送字节)、movw(传送字)、movl(传送双字)和 movq(传送四字)。后缀“l”用来表示双字,因为 32 位数被看成是“长字(long word)”。注意,虽然汇编代码中的 4 字节整数和 8 字节双精度浮点数都使用了该后缀来表示,但这不会产生歧义,因为浮点数使用的是一组完全不同的指令和寄存器。
一个 X86-64 的 CPU 包含一组 16 个存储 64 位值的通用目的寄存器,用来存储整数数据和指针。下图中显示了这 16 个寄存器。它们的名字都以“%r”开头,后面则跟以随指令集历史演化而来的不同命名规则的名字。最初的 8086 中有 8 个 16 位的寄存器,对应图中的 %ax 到 %bp。每个寄存器都有特殊的用途。扩展到 IA32 架构时,这些寄存器也扩展成 32 位,标号从 %eax 到 %ebp。扩展到 x86-64 后,原来的 8 个寄存器也随之扩展成 64 位,标号从 %rax 到 %rbp。除此之外,还增加了 8 个新的寄存器,它们的标号是按照新的命名规则制定的:从 %r8 到 %r15。
指令可以对这 16 个寄存器的低位字节中存放的不同大小的数据进行操作:字节级操作可以访问最低的字节,16 位操作可以访问最低的 2 个字节,32 位操作可以访问最低的 4 个字节,而 64 位操作可以访问整个寄存器。
当相关指令以寄存器作为目标时,对于生成小于 8 字节结果的指令,对寄存器中剩下的字节的处理有两条规则:生成 1 字节和 2 字节数字的指令会保持剩下的字节不变;生成 4 字节数字的指令会把高位 4 个字节置为 0,这是作为从 IA32 到 x86-64 的扩展的一部分而采用的。
多数指令都有一个或多个操作数(operand),用于指示一个操作中要使用的源数据值,以及放置结果的目的位置。源数据值可以是常数,或是从寄存器或内存中读出,结果可以存放在寄存器或内存中。因此,各种不同的操作数的可能性被分为三种类型。第一种是立即数(immediate),用来表示常数值。在 ATT 格式的汇编代码中,立即数的书写方式是“$”后面跟一个用标准 C 表示法表示的整数,如 $-577 或 $0x1F。不同的指令允许的立即数值范围不同,汇编器会自动选择最紧凑的方式进行数值编码。第二种是寄存器(register),它表示某个寄存器的内容。第三类是内存引用,它会根据计算出来的地址(通常称为有效地址)访问某个内存位置。x86-64 支持多种不同的寻址模式,允许不同形式的内存引用,如下表所示。
图中,使用符号 ra 来表示任意寄存器 a,用引用 R[ra] 来表示它的值,这是将寄存器集合看成一个数组 R,用寄存器标识符作为索引。对于内存引用,因为可以将内存看成一个很大的字节数组,所以用符号 Mb[Addr] 表示对存储在内存中从地址 Addr 开始的 b 个字节值的引用(为了简便,通常省略下标 b)。表中底部用语法 Imm(rb, ri, s) 表示的是最常用的形式,它有四个组成部分:一个立即数偏移 Imm,一个基址寄存器 rb,一个变址寄存器 ri 和一个比例因子 s。注意,这里 s 必须是 1、2、4 或者 8,基址和变址寄存器都必须是 64 位寄存器。有效地址被计算为:Imm + R[rb] + R[ri]*s。引用数组元素时,会用到这种通用形式,其他形式都是这种的特殊情况。在引用数组和结构元素时,比较复杂的寻址模式是很有用的。
下面是一个数据交换函数的 C 语言代码。
long exchange(long *xp, long y){ long x = *xp; *xp = y; return x; }
其对应的汇编代码主体部分如下。
; long exchange(long *xp, long y) ; xp in %rdi, y in %rsi exchange: movq (%rdi), %rax ; Get x at xp. Set as return value. movq %rsi, (%rdi) ; Store y at xp. ret ; Return.
从这段汇编代码中可以看出,C 语言中所谓的“指针”其实就是地址。间接引用指针就是将该指针放在一个寄存器中,然后在内存引用中使用这个寄存器。其次,像 x 这样的局部变量通常是保存在寄存器而不是内存中,因为访问寄存器要比访问内存快得多。
参考书籍:《深入理解计算机系统》第三版第三章——程序的机器级表示。
发表评论
-
浮点运算指令
2019-05-22 23:13 1568上一节介绍了浮点数与各种数值类型之间的相互转换 ... -
浮点数类型转换指令
2019-05-15 22:37 1691在浮点寄存 ... -
浮点寄存器概述
2019-05-14 22:31 2568本文介绍的浮点寄存器是基于 AVX2(Adva ... -
汇编指令之跳转指令
2019-04-15 00:21 4769正常执行的情况下,指令会按照顺序一条条地执行, ... -
汇编指令之条件码
2019-04-08 21:05 2336在系统底层,除了整数寄存器,CPU 还维护着一 ... -
汇编指令之算术和逻辑操作指令
2019-03-28 22:16 1347下表是 x86-64 ... -
汇编指令之数据传送指令
2019-03-25 21:28 1276在x86-64 中的 ... -
hello 程序执行背后的故事
2018-12-26 21:48 607源文件 hello. ... -
linux启动服务概述
2017-04-08 02:43 396传统的linux中定义了七个运行级,分别如下: ... -
unix限制
2017-04-04 16:08 572UNIX系统实现定义了很多幻数和常量,其中有很 ... -
linux引导加载程序--GRUB
2017-04-04 04:22 623linux世界里有两种 ... -
存储器映射
2016-06-13 00:12 551注:本文摘自《深入理解计算机操作系统》第九章--虚拟存 ... -
虚拟存储器对存储器管理的作用
2016-06-10 16:00 693注:本文中的大部分内容均是摘录自《深入理解计算机系统》一书,权 ... -
信号处理问题
2016-06-03 08:31 560注:本文摘自《深入理解计算机系统》第8章 --- 异常控制流。 ... -
僵尸进程
2016-05-23 23:57 359在解释僵尸进程的概念之前,我们得先了解这样的一个事实: 一个进 ... -
程序优化之存储器别名使用
2016-05-20 08:55 794说明:本文示例摘自《深入理解计算机系统》第五章----优化程序 ... -
条件变量基本概念与原理(转载)
2016-05-20 08:54 1568对于条件变量,我一直感到很困惑,搞不清其与互斥锁到底有啥区别, ... -
CPU与磁盘的交互过程
2016-05-19 09:05 1829对于计算机系统底层技术,想必很多人都和我一样不太了解,最近在学 ... -
存储器层次结构中基本的缓存原理
2016-05-19 09:00 663对于操作系统,我们知道,越靠近CPU的存储器,其存储速度就会越 ... -
异常处理
2016-05-19 00:29 422我知道很多人都知道异常处理,但可能对其底层并不太了解,现在我们 ...
相关推荐
而汇编操作数则是这些指令所操作的数据,可以是寄存器、内存地址或者立即数。 64位的x86-64架构,也称为AMD64或EM64T,是在原有的32位x86基础上扩展的,引入了新的寄存器和寻址模式,允许更大的地址空间和更高效的...
书中可能包含以下章节内容:介绍汇编语言的基本概念、x86-64指令集、Ubuntu环境下的开发工具(如GCC、GDB)、内存模型、程序结构、输入/输出操作、中断处理、异常和错误处理,以及如何将汇编代码与高级语言混合编程...
总结起来,x86-64下的函数调用和栈帧原理涉及了寄存器的管理、堆栈操作和控制流的转移,这些都是为了确保函数调用的正确性和效率。这些概念对于理解底层计算机系统的工作原理以及编写高效的汇编代码至关重要。
3. 汇编指令的格式和种类,如操作码、操作数的表示 4. 通过一系列例子详细解释如何阅读和理解汇编代码 5. 重点介绍了函数调用中栈帧的使用 6. 使用很多配图辅助说明 总的来说,这是一篇写得非常好的有关x86_64汇编...
《x86-64 Intel汇编器实用程序例程和程序》是一个深入探讨汇编语言编程的资源集合,特别关注于Intel架构的x86-64指令集。汇编语言是计算机科学中的基本编程语言,它直接对应于机器码,对底层硬件操作有直接控制力,...
本文将介绍在x86-64系统中使用gdb的常用指令,包括程序的启动与停止、设置断点、执行控制、查看代码、查看数据以及操作内存等。 首先,要启动gdb调试器,通常输入"gdb"命令即可。如果需要调试的程序文件已知,可以...
内存/寄存器操作数字节(ModR/M)和索引寻址描述字节(SIB)用于确定操作数的位置和操作类型。ModR/M字节由Mod、Reg/Opcode和R/M三部分组成。Mod字段指示寻址模式,R/M字段用于选择特定的寄存器或者指定内存寻址的...
X86汇编指令集是计算机体系结构中不可或缺的一部分,特别是在32位和64位的x86架构处理器中。这篇文档详细列举了汇编指令,并为每条指令提供了注释说明。以下知识点涵盖了文档中提及的关键指令及其功能。 一、数据...
**汇编语言与x86汇编指令集详解** 汇编语言是一种低级编程语言,它是计算机硬件系统可以直接理解和执行的指令集的符号化表示。在个人计算机领域,x86架构是主流,对应的汇编语言就是x86汇编语言。这种语言直接对应...
【ICS笔记1】这篇笔记主要涉及的是x86-64架构下...综上所述,这篇笔记提供了关于x86-64汇编语言和C语言在数据处理、指令格式、寄存器使用、类型转换以及栈操作的基础知识,这对于理解和编写x86-64平台的程序至关重要。
在本编程作业中,你将学习如何在编译器中实现代码生成,特别是针对简化语言(SimpliC)的x86-64汇编代码生成。x86-64是64位x86架构的别名,也称为AMD64或EM64T。为了完成这项任务,你需要一个Linux环境,可以通过SSH...
《x86,x64汇编代码注入器的C/C++实现详解》 在计算机编程领域,代码注入是一种技术,它允许程序将代码插入到另一个正在运行的进程上下文中执行。这种技术通常用于调试、系统监控、性能优化,但也可能被滥用进行恶意...
寄存器用于存储操作数、中间结果和地址,是汇编语言编程中非常重要的资源。以下是一些关键寄存器的功能说明: - rdi(寄存器):用来存储函数的第一个参数。 - rsi:用来存储函数的第二个参数。 - rdx:用来存储...
- **修饰寄存器列表**:可以使用不同的修饰符来进一步限定寄存器的使用方式,例如`=r`表示操作数将被分配到寄存器中,并且是输出操作数。 - **操作数约束**:定义了操作数可以出现在指令中的哪些位置。例如,`"r"`...
以下是关于x86寄存器的详细解释: 一、通用寄存器 通用寄存器是处理器中最常用的一类寄存器,它们在32位x86体系中扩展了16位8086的寄存器,提供了8位、16位和32位的操作。主要分为数据寄存器、变址寄存器和地址指针...
1. **x86与x64架构**:x86是指英特尔的32位微处理器系列,包括80386、Pentium等。而x64(也称为AMD64或EM64T)是x86架构的64位扩展,最初由AMD推出,后来被Intel广泛采用。x64架构不仅支持传统的32位应用程序,还能...
4. 操作码与操作数:操作码表示要执行的操作,操作数则是操作的对象。 5. 转移指令:如JMP、CALL等,用于改变程序的执行流程。 6. 子程序和堆栈:通过调用子程序和使用堆栈,可以实现复杂的逻辑控制和数据管理。 7. ...
2. **传送-填充指令**:MOVSX和MOVZX,用于将位数较短的源操作数扩展到位数较长的目的操作数,MOVSX根据源操作数符号位填充,而MOVZX用0填充。 3. **交换指令XCHG**:交换两个寄存器或寄存器与内存位置的内容。 4....
在计算机编程,特别是汇编语言中,我们经常需要对数据进行操作,包括拆分和重组。这个场景描述了一个具体的操作,即将AX寄存器中的16位数值分成四部分,每部分4位,然后分别存储到AL、BL、CL和DL这四个8位寄存器中。...