【问题标题】:Assembly: store a string in register汇编:在寄存器中存储一个字符串
【发布时间】:2022-01-02 20:18:11
【问题描述】:

假设我们在 x86_64 架构上工作,假设我们有以下字符串“123456”。在 ASCII 字符中,它变为31 32 33 34 35 36 00

现在,我应该使用哪些汇编指令以 %rdi 存储该字符串的地址(指向该字符串)的方式将该字符串的整个(即使是碎片化的)内容移动到某处?

因为我不能简单地将字符串的十六进制表示移动到寄存器中,就像使用无符号值一样,我该怎么做?

【问题讨论】:

  • 字符串从何而来?如果它是文字,您可能只需加载它的地址。
  • 我不明白你问题的最后一部分。您绝对可以将此字符串移动到寄存器中,就像使用整数一样。它将适合 64 位寄存器。
  • 您需要解决的实际问题是什么?您需要“移动整个内容”的原因是什么?现在感觉很像XY problem
  • 不太清楚你想要什么,请edit并显示值,rdi应该包含字符串"123456"。问题标题与问题并不真正匹配。您是在谈论您想要在寄存器中的字符串的 address 还是您想要在寄存器中的字符串的 content
  • 字符串的“十六进制表示”是什么意思?你的意思是在 asm 源中,它被组装成二进制,比如mov eax, 0x123456?就像编译器用 mov-immediate godbolt.org/z/dKnTz8b9G 初始化小字符串一样? (或者你的意思是你想要代表无符号数字的 ASCII 字符的字节,就像你可以在运行时从 How to convert a binary integer number to a hex string? 获得)

标签: c string assembly x86-64 stack-memory


【解决方案1】:

有几种方法可以做到这一点。 如果您想先将整个字符串移动到另一个偏移量,则必须使用循环。

mov rbx, 0
loop:
 mov al, [string+rbx]
 mov [copyoffset+rbx], al
 inc rbx
 cmp al, 0x0
 jne loop
... Insert other code here

然后您可以使用下面描述的 Lea 指令将其移动到 rdi 中。

如果你只想加载字符串的地址而不关心移动它,你可以使用 lea

lea rdi, [stringoffset]

编辑:将 rax 更改为 al,因此我们一次只能移动一个字节

【讨论】:

  • 第一部分没有将任何东西移到寄存器中,它只是将字符串复制到copyoffset中
  • 您在第二个代码块中使用(RIP-relative?)LEA,但在您的第一个代码块中,您假设地址适合 32 位绝对符号扩展的 disp32作为寻址模式的一部分。 (因此您可以将它与另一个寄存器一起使用。)如果是这种情况,您应该使用mov edi, OFFSET stringoffset 将地址放入RDI。 (除非这是针对高半内核的,因此它适合 32 位符号扩展但不适合 32 位零扩展)。见How to load address of function or label into register
  • 另外,正如@Jabberwocky 所说,还不清楚展示一个幼稚的未优化 strcpy 循环的意义何在。问题的示例是关于可以使用一对重叠的 dword 加载/存储复制的短字符串,就像 glibc memcpy 那样。如果你是手工编写 asm,通常你关心性能,所以你会使用 SSE2 movdqu / pcmpeqb / pmovmskb 来检查字符串的结尾,并进行一些对齐处理......参见 glibc 的 strcpy或其他优化 strcpy 的示例。
  • 当然这很容易优化。以我理解问题的方式,这只是一个简单方法的示例。如果他包含 libc,他可以直接调用 strcpy。为此使用堆栈或堆也比使用二进制文件的某些 rw 部分要好得多。但从提问的方式来看,他似乎是新人,只需要一个他能理解的简单例子。
  • 你也应该改变cmp rax, 0x0
猜你喜欢
  • 1970-01-01
  • 2014-04-06
  • 1970-01-01
  • 2021-03-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多