Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/advance/unsafe/inline-asm.md
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ fn mul(a: u64, b: u64) -> u128 {

## Clobbered 寄存器

在很多情况下,无需作为输出的状态都会被内联汇编修改,这个状态被称之为 "clobbered"。
在很多情况下,无需作为输出的寄存器的状态都会被内联汇编修改,这个状态被称之为 "clobbered"。

我们需要告诉编译器相关的情况,因为编译器需要在内联汇编语句块的附近存储和恢复这种状态。

Expand Down Expand Up @@ -241,7 +241,7 @@ fn main() {

即使 `eax` 从没有被读取,我们依然需要告知编译器这个寄存器被修改过,这样编译器就可以在执行汇编之前存储寄存器中的值。这个需要通过将输出声明为 `_` 而不是一个具体的变量名,代表着该输出值被丢弃。

这段代码也会绕过一个限制: `ebx` 是一个 LLVM 保留寄存器,意味着 LLVM 会假设它拥有寄存器的全部控制权,并在汇编代码块结束时将寄存器的状态恢复到最开始的状态。由于这个限制,该寄存器无法被用于输入或者输出,除非编译器使用该寄存器的满足一个通用寄存器的需求(例如 `in(reg)` )。 但这样使用后, `reg` 操作数就在使用保留寄存器时变得危险起来,原因是我们可能会无意识的破坏输入或者输出,毕竟它们共享同一个寄存器。
这段代码也会绕过一个限制: `ebx` 是一个 LLVM 保留寄存器,意味着 LLVM 会假设它自己拥有该寄存器的全部控制权,并在汇编代码块结束时将寄存器的状态恢复到最开始的状态。由于这个限制,该寄存器无法被用于输入或者输出,除非编译器在分配通用寄存器时恰好选择了它(例如 `in(reg)` )。 但这样使用后, `reg` 操作数就在使用保留寄存器时变得危险起来,原因是我们可能会无意识的破坏输入或者输出,毕竟它们共享同一个寄存器。

为了解决这个问题,我们使用 `rdi` 来存储指向输出数组的指针,通过 `push` 的方式存储 `ebx`:在汇编代码块的内部读取 `ebx` 的值,然后写入到输出数组。后面再可以通过 `pop` 的方式来回复 `ebx` 到初始的状态。

Expand Down