汇编中没有变量。 (*)
variable db 'A'
做几件事。它定义了汇编时间符号variable
,就像内存中的书签,包含地址*here*在编译的时候。这与在空行上做标签是一样的,例如:
variable:
The db 'A'
指令是“定义字节”,并且您为其定义要定义的单字节值,因此它将在结果机器代码中生成带有值的单字节0x41
or 65
以十进制表示。这就是 ASCII 编码中大字母 A 的值。
Then:
mov ecx , [variable]
是否从地址处的内存单元加载 4 个字节variable
,表示低8位ecx
将包含该值65
,并且高24位将包含一些垃圾,这些垃圾恰好驻留在后面的3个字节中'A'
..(你会用db 'ABCD'
,那么ecx
将等于价值0x44434241
('D' 'C' 'B' 'A'
字母,由于小端编码而以位“反转”dword
x86 上的值)。
But the sys_write
期望ecx
保存存储内容字节的内存地址,因此您需要:
mov ecx, variable
这将在 NASM 中将数据的地址加载到ecx
.
(在 MASM/TASM 中,这将组装为mov ecx,[variable]
要获取地址,您必须使用mov ecx, OFFSET variable
,如果您碰巧找到一些 MASM/TASM 示例,请注意语法差异)。
*)有关“无变量”的更多信息。请记住,在装配过程中,您处于机器级别。在机器级别上有计算机内存,可以按字节寻址(在x86平台上!有一些平台,内存可以按不同大小寻址,它们并不常见,但在微控制器世界中您可能会找到一些)。因此,通过使用某些内存地址,您可以访问物理内存芯片中的某些特定字节(对内存芯片中的特定物理位置进行寻址取决于您的平台,现代操作系统通常会为用户应用程序提供虚拟寻址空间,转换为CPU 动态、透明地处理物理地址,而不会影响用户代码的转换)。
所有高级逻辑概念(例如“变量”、“数组”、“字符串”等)都只是内存中的一堆字节值,所有逻辑含义都是由正在执行的指令赋予内存数据的。当您在没有指令上下文的情况下查看这些数据时,它们只是内存中的一些字节值,仅此而已。
因此,如果您的代码不精确,并且您通过指令获取来访问单字节“变量”dword
,就像你在你的mov ecx,[variable]
例如,从机器的角度来看,这没有什么问题,它会很乐意将 4 个字节的内存读取到ecx
注册,NASM 也懒得报告您,您可能越界访问超出原始内存的内存variable
定义。如果您用“变量”等术语和其他高级编程语言概念来思考,这是一种愚蠢的行为。但汇编不是为了这样的工作,实际上对机器的完全控制是汇编的主要目的,如果你想获取4个字节,你可以,这完全取决于程序员。它只需要极高的精度,关注细节,了解内存结构布局,并使用正确的指令和所需的内存操作数大小,例如movzx ecx,byte [variable]
从内存中仅加载单个字节,并将该值零扩展为目标中的完整 32b 值ecx
登记。