CPU寄存器是位于CPU核心内部的一块计算机内存。一块计算机内存意味着一定数量的位(0/1),在64b x86 CPU的情况下,通用寄存器是64位“宽”,名称为rax, rcx, rdx, rbx, ..
。
ecx
是rcx
(上部32b部分不能通过特殊名称访问,只能通过使用rcx
的说明)下部32b部分。而下部16b部分可通过cx
访问,该部分由两个8b部分ch
(上部)和cl
(下部)组成。
因此,作为使用的是ecx
,可以设置32位为0或1。哪个可以解释为无符号数从0到2 32 -1(在六0 .. 0xFFFFFFFF
),或者作为符号数从-2 to +2 -1(0x80000000 .. 0x7FFFFFFF
)。或者你可以用你希望的任何方式解释这些位的含义,并为其编写代码。
在您的代码中,您可以利用三种常见方法来解释某些CPU寄存器中位的值。
; EBX as memory address:
mov ebx,OFFSET presetWord ; some address into memory (32b unsigned number)
; ECX as numeric value ("unsigned long" in C++)
mov ecx,SIZEOF presetWord - 1 ; 15
; AL as ASCII character (extended 8 bit)
mov al,[ebx] ; also shows how memory is referenced by address
; AL == 83 == 'S' => value of memory at address "presetWord"
在您的例子做cmp [ecx],eax
手段地址15,这是幸运的,你非法引用的内存,所以它崩溃。如果您偶然为您的流程使用了一些合法地址(但不是您真正想使用的地址),它会默默地继续进行并继续出现意想不到的结果。
您可能确实想要做cmp [esi+ecx],eax
,这意味着引用地址presetWord+15
(字符串的最后一个字符)的内存,但是这仅适用于第一次迭代。然后你做inc esi
,它将指向presetWord+1
地址(第二个字符)。
而且您可能只想比较字符,所以您应该将eax
更改为al
以一次只提取一个字节,因为该字符串是以ASCII编码(每字符8位)进行编码的。 eax
可以用于UTF-32编码。
要检查回文您可能需要使用第一个字符的地址装载一个寄存器(“R1”),一个寄存器最后一个字符的地址(“R2”)(!),然后执行这个循环:
- 如果(R2 < = R1) - >与真(比所有重要的字符)出口(检查为无符号数的地址)
- 这里解决R1 < R2 - >现在比较字符
- 如果(字节[r1]!=字节[r2])退出假
个
- ++ R1,--r2 - >调整地址指向第二/倒数第二个字符
- 环路开始
这将产生presetWord“假”,为'S' != 's'
,所以你可能要为if (byte [r1]...
部分引入不区分大小写,但我会先让它工作没有。
在调试时,您应该能够识别寄存器中某些数字的“类”。如果将大小加载到注册表中,它将很可能是一些小数字,如0000000F
(15)。地址很可能会有一些像8040506E
这样的大数字。当作为单个字符应该导致类似20
ASCII字符 - 7F
中常见的情况,但如果这样做mov al,...
,调试器仍显示整体eax
,所以上三个字节将保持它的前值,例如读取空格字符成eax
组作为12345678
将的eax
值更改为12345620
(空间' ' == 0x20
在ASCII)。
您还可以使用内存视图来查看特定地址的内容在内存中。如果你想例如改变cmp
到cmp [esi+ecx],eax
,并检查内存认为地址,你会看到它会在第二次迭代中再次在最后一个字符,而不是第二个最后一个字符点。
这是所有可见和可能检查调试器,有时有点繁琐,然后再次往往比在SO上询问或只考虑源代码更容易,特别是如果你被困在更长的时间。
终于......为什么要登录?因为电脑内存是独立的芯片。它可能看起来无辜的,但像mov al,[presetWord]
指令实际上可能拖延数百个CPU周期,而CPU芯片将等待内存芯片读取内存的内容并把它通过总线线连接到CPU芯片。而al
和ecx
直接位于CPU内部,可在CPU需要时在同一周期内访问。因此,如果您在计算中经常使用它们,您可能希望将值存储到寄存器中,以避免内存变慢(尽管一旦内存内容被L0/1/2/3高速缓存缓存,“数百“的周期变成合理的量,有时甚至在CPU芯片上直接存储高速缓存级的情况下为0个周期)。但是你希望以可预测的模式访问内存(所以缓存可以预读),并且数量合理(缓存通常以16-32B的大小在他们的级别上高达4-8k)。如果您访问16条不同的8k内存页面的指令,则可能会用尽可用的缓存行,然后至少有一个访问将全部停止,等待真正的内存读取。
您使用'ecx'作为指针,而是使用长度加载它。另外,您一次只能操作4个字节而不是1.使用'mov al,[esi]; cmp [presetWord + ecx],al'来代替。 – Jester
您将'ECX'设置为*字符数*,然后将其用作指向内存的指针。它不会指向任何合理的东西,当然它会崩溃。你需要设置'ECX'来抵消+长度,而不仅仅是长度。 –
@Jester所以使用它,我仍然必须做'mov ecx,OFFSET presetWord + SIZEOF presetWord - 1'? –