无法在 32 位代码中递增寄存器
Cannot increment register in 32 bit code
我遇到了一个相当愚蠢的问题,但我无法在任何地方找到解决方案。
我正在尝试编写一个程序,它从内存中逐个(32 位)添加(带进位)两个数字,并将部分和写入堆栈。不幸的是,不知道为什么,for 循环的计数器在 inc %ecx
之后没有递增。 (我已经在 gdb 中测试过,并且 %ecx
甚至在 inc
指令之后就保持在 0
。
我为 Intel 架构编写,但使用 AT&T 语法(我在这里别无选择)。
.code32
SYSEXIT = 1
EXIT_SUCCESS = 0
.align 32
.data
nr1:
.long 0xF0000111, 0x000B0000
nr2:
.long 0x10000333, 0x000A000F
size:
.long 0x00000002
.text
.global _start
_start:
mov [=10=], %ecx #initialization of counter
movl size(,%ecx,4), %edi #moving size (amount of 32-bit pieces) to %edi
addition:
movl nr1(,%ecx,4), %eax #moving one piece
movl nr2(,%ecx,4), %ebx #(from address of nr1 + (value of %ecx * 4 bytes)
adcl %ebx, %eax #add with carry
push %eax #push the result
inc %ecx #increment counter
cmp %edi, %ecx #compare %edi (==2) with counter (%ecx)
je overflow # if %edi == %ecx
jmp addition # else back to addition loop
overflow: #in case when last sum had an overflow (CF==1)
mov [=10=], %eax
adcl [=10=], %eax
push %eax
end:
mov $SYSEXIT, %eax
mov $EXIT_SUCCESS, %ebx
int [=10=]x80
如果您还可以解释为什么会发生这种情况以及将来如何避免该问题,我将不胜感激(如您所见,我仍在学习)。另外,如果您看到其他错误,请告诉我。提前致谢。
您似乎是在 64 位系统上汇编您的代码。因此,汇编程序默认为 64 位二进制文件。此类二进制文件中的所有代码都将作为 64 位代码执行。指令
.code32
使汇编程序发出 32 位代码,但不改变处理器解释指令的方式;它会将您的代码解释为 64 位代码。要使汇编器生成 32 位目标文件(处理器会将其解释为 32 位代码),您需要在命令行上传递一个特殊开关:
as --32 code.s
为什么 inc
被跳过了?在 x86 处理器上,32 位模式与 64 位模式非常相似,因此大多数指令做同样的事情。大多数情况下,引入了一组新的前缀来区分 32 位和 64 位指令。由于没有可用于这些新前缀的操作码,操作码 40
到 4f
(意思是 inc r32
和 dec r32
)被重新利用。 inc
和 dec
指令仍然以不同的双字节编码提供。因此,处理器“跳过”了您的 inc
而是更改了下一条指令。
除非您正在做非常奇怪的事情(例如编写引导加载程序),否则您永远不需要 .code32
指令。忘记它的存在。请注意,您不应使用 int [=21=]x80
在 64 位代码中执行系统调用,因为这些系统调用仅接受 32 位指针。在64位代码中,系统调用使用syscall
,但注意系统调用号和调用约定是不同的。
我遇到了一个相当愚蠢的问题,但我无法在任何地方找到解决方案。
我正在尝试编写一个程序,它从内存中逐个(32 位)添加(带进位)两个数字,并将部分和写入堆栈。不幸的是,不知道为什么,for 循环的计数器在 inc %ecx
之后没有递增。 (我已经在 gdb 中测试过,并且 %ecx
甚至在 inc
指令之后就保持在 0
。
我为 Intel 架构编写,但使用 AT&T 语法(我在这里别无选择)。
.code32
SYSEXIT = 1
EXIT_SUCCESS = 0
.align 32
.data
nr1:
.long 0xF0000111, 0x000B0000
nr2:
.long 0x10000333, 0x000A000F
size:
.long 0x00000002
.text
.global _start
_start:
mov [=10=], %ecx #initialization of counter
movl size(,%ecx,4), %edi #moving size (amount of 32-bit pieces) to %edi
addition:
movl nr1(,%ecx,4), %eax #moving one piece
movl nr2(,%ecx,4), %ebx #(from address of nr1 + (value of %ecx * 4 bytes)
adcl %ebx, %eax #add with carry
push %eax #push the result
inc %ecx #increment counter
cmp %edi, %ecx #compare %edi (==2) with counter (%ecx)
je overflow # if %edi == %ecx
jmp addition # else back to addition loop
overflow: #in case when last sum had an overflow (CF==1)
mov [=10=], %eax
adcl [=10=], %eax
push %eax
end:
mov $SYSEXIT, %eax
mov $EXIT_SUCCESS, %ebx
int [=10=]x80
如果您还可以解释为什么会发生这种情况以及将来如何避免该问题,我将不胜感激(如您所见,我仍在学习)。另外,如果您看到其他错误,请告诉我。提前致谢。
您似乎是在 64 位系统上汇编您的代码。因此,汇编程序默认为 64 位二进制文件。此类二进制文件中的所有代码都将作为 64 位代码执行。指令
.code32
使汇编程序发出 32 位代码,但不改变处理器解释指令的方式;它会将您的代码解释为 64 位代码。要使汇编器生成 32 位目标文件(处理器会将其解释为 32 位代码),您需要在命令行上传递一个特殊开关:
as --32 code.s
为什么 inc
被跳过了?在 x86 处理器上,32 位模式与 64 位模式非常相似,因此大多数指令做同样的事情。大多数情况下,引入了一组新的前缀来区分 32 位和 64 位指令。由于没有可用于这些新前缀的操作码,操作码 40
到 4f
(意思是 inc r32
和 dec r32
)被重新利用。 inc
和 dec
指令仍然以不同的双字节编码提供。因此,处理器“跳过”了您的 inc
而是更改了下一条指令。
除非您正在做非常奇怪的事情(例如编写引导加载程序),否则您永远不需要 .code32
指令。忘记它的存在。请注意,您不应使用 int [=21=]x80
在 64 位代码中执行系统调用,因为这些系统调用仅接受 32 位指针。在64位代码中,系统调用使用syscall
,但注意系统调用号和调用约定是不同的。