【问题标题】:Assembly char* linked程序集 char* 链接
【发布时间】:2018-04-06 12:01:21
【问题描述】:

我正在用 C 和 Assembly x86-64 位编写代码,我使用 NASM 和 gcc 在 Ubuntu 16.04 上编译。

我在程序集中有一个名为 _sum 的标签。 我调用 _sum 并发送一个仅包含数字的 char*(例如:“87”),它由寄存器“rdi”接收。 当我执行以下操作时:

mov rbx, [rdi]
inc rdi
mov rcx, [rdi]

我注意到寄存器 rbx 包含链接在一起的所有数字的十六进制值(在前面的示例中:rbx 有 0x3738,rcx 有 0x37)。 我怎样才能使每次 [rdi] 只包含当前数字的值(0x38)而不是所有链接的数字?

【问题讨论】:

  • 如果您检查较小的寄存器BLCL,它们将分别包含一个字节。
  • 你的 char 类型是 8 位宽的,所以使用 8 位宽的指令来处理它。 mov bl,[rdi]movzx ebx, byte [rdi],取决于您想要以什么结尾(8 位值或 64 位值)。

标签: c assembly x86-64


【解决方案1】:

如果您使用 32 位或 64 位移动来注册,您肯定会得到从指向字节开始的 4 或 8 个字节的值,而不仅仅是请求的字节。最简单的变体是使用零填充扩展指令,例如:

movzx ebx, byte [rdi]

请注意,用某个值填充 ebx 会自动清除 rbx 的高 4 字节,因此,这与将 movzx 调用到 rbx 相同。但是,符号扩展需要明确的 r** 参数。

还有其他选择,例如:

xor ebx, ebx
mov bl, [edi]

或:

mov bl, [edi]
and ebx, 0ffh

但它们在任何现代处理器上的效率都较低。

【讨论】:

  • movzx ebx, [rdi] 不会使用 NASM 编译,因为该指令需要明确指定源操作数大小,例如 movzx ebx, byte [rdi]。否则,汇编程序只能猜测您确实希望使用哪个 movzx 变体(读取 8 位或 16 位)。
  • @Ped7g 谢谢,添加了限定符 - 我通常使用 AT&T 语法,不记得这些细节。
  • @Netch :可能是因为在 AT&T 语法 if 中,您在指令后加上 lbq 等,也可以从中推断出大小。
  • @MichaelPetch 是的,AT&T 使用指令后缀;而且,它不支持所有这些“字节指针”的东西。
  • @Ped7g 我主要处理 GCC/等。汇编器输出,因此,在我的情况下,切换到英特尔太麻烦了。我对 AT&T 很满意,除非在某些情况下反向参数顺序会导致混乱,例如 shld。其他问题对于 AT&T 和英特尔来说都很奇怪。我宁愿看到“sxt eax,ax”而不是记住所有这些糟糕的cwd/cwde/cdq/etc,和cltq/cltd...
猜你喜欢
  • 1970-01-01
  • 2015-07-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-17
相关资源
最近更新 更多