【问题标题】:How to put a value from a variable to a register?如何将变量中的值放入寄存器?
【发布时间】:2019-07-10 20:19:48
【问题描述】:

我想将字符串的结束字符与句点进行比较。

我计算了字符串的长度并将其保存在名为strlen 的变量中。所以,我做了cmp [string + strlen], '.',但它没有用,然后,我尝试将strlen 移动到一个寄存器,但它也不起作用。程序崩溃。我使用的是 x86 32 位 Windows 10 架构

MOV BL, [strlen-1]      ;the length of the string minus 1 so i would end up 
                         in the last character of the string
cmp [string + BL], '.'
JE func1

【问题讨论】:

  • 您不能在寻址模式中使用bl。请在问题中输入您的实际代码..
  • 是的,我也尝试过使用 eax,但效果不佳
  • 使用寄存器,而不是静态的[strlen]。这就是寄存器的用途。尤其是不要在循环内增加内存位置;这是一个主要瓶颈(比如 6 个周期而不是 1 个。)您已经在递增一个指针,所以如果您想获得长度,只需在末尾做一个指针减法,给定一个指向开始和结束的指针。
  • 您的编辑使问题和答案毫无意义。这不会组装(因为您复制的答案的第一个版本有错误,现在已修复),答案是回答您问题的旧版本。我把它回滚了,但实际上 `[string + BL]` 也不会汇编,所以这不是你的代码的 minimal reproducible example 汇编 + 运行但也崩溃了。

标签: variables assembly x86 nasm


【解决方案1】:
MOV BL, [strlen-1]

这实际上并没有做你认为它正在做的事情。它没有将strlen - 1 的值存储在bl 中。相反,它将值存储在bl 中的地址 strlen - 1

如果你懂C,那就是两者的区别:

byte* strlen = ...;
BL = *strlen - 1;

和:

byte* strlen = ...;
BL = *(strlen - 1);

在汇编符号中,您可以将方括号 ([...]) 视为“要取消引用的地址”,其中“地址”可以与“内存位置”互换——就像 C 中的指针一样。

如果要从strlen的实际中减去1,则需要先将值加载到寄存器中,然后再减去1。

在 C 中:

byte* strlen = ...;
bl  = *strlen;
bl -= 1;

在组装中:

movzx ebx, BYTE PTR [strlen]
sub   ebx, 1                     ; (or dec ebx)

BL 寄存器现在将包含字符串的长度,减 1。所以,你可以这样做:

mov  al, BYTE PTR [startOfString + ebx]      ; al = startOfString[bl]

将字符串中的最后一个字符(从地址startOfString开始)加载到变量al中。

然后,跟进:

cmp  al, '.'

设置标志。或者,就像您最初拥有的那样,您可以使用 CISC 样式的指令,将加载与比较结合起来:

cmp  BYTE PTR [startOfString + ebx], '.'

【讨论】:

  • 不能在寻址模式下使用bl,所以需要在寻址模式下使用movzx ebx, BYTE PTR [strlen],然后在寻址模式下使用ebx
  • 在汇编中,您可以使用第二种寻址模式(而不是第一种)执行-1。您不需要decsubmov al, [startOfString - 1 + ebx]。寻址模式已经包含一个disp32 绝对地址,因此这样做的成本为零,并且让链接器使用与符号的偏移量填充 disp32。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-09-12
  • 2013-04-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多