`push label` 推送 [label],而不是标签的地址(Rust asm!)
`push label` pushs [label], not the address of label (Rust asm!)
我正在写 OS。我使用 asm!
宏来更改代码段。 (2020/06/08 详情改为asm!
here and in Rust RFC 2873)
pub unsafe fn set_code_segment(offset_of_cs: u16) {
asm!("push {0:r} // 64-bit version of the register
lea rax, 1f // or more efficiently, [rip + 1f]
push rax
retfq
1:", in(reg) offset_of_cs);
}
这行得通。但是,如果我使用push 1f
,标签1:
的地址将不会被推送。相反,它将是一个内存源操作数,从 [1:]
加载
所以下面的代码
pub unsafe fn set_code_segment(offset_of_cs: u16) {
asm!("push {0:r}
push 1f // loads from 1f, how to push the address instead?
retfq
1:", in(reg) offset_of_cs);
}
将不起作用。反汇编(ndisasm
)代码是这样的:
11103 │ 0000B9EC 57 push rdi
11104 │ 0000B9ED FF3425F6B90080 push qword [0xffffffff8000b9f6]
11105 │ 0000B9F4 48CB retfq
用 nasm 语法编写的所需代码是这样的:
[bits 64]
extern set_code_segment
set_code_segment:
push rdi
push change_code_segment ; absolute address as a 32-bit immediate
retfq
change_code_segment:
ret
链接到内核(和extern "C" { pub fn set_code_segment(offset_of_cs: u16) -> () }
),代码可以工作。 change_code_segment
地址推送成功
所以我的问题是:为什么asm!
的push 1f
推送地址1:
的内容,而不是1:
的地址?
rust asm!
宏建立在 llvm
.
之上
并且在llvm中有a specific bug解释只由0
和1
数字组成的标签,例如0
、11
或101010
,作为二进制值。这就是这里发生的事情,这个二进制值被读取为内存中的地址。
此外,rust asm!
文档已更新,现在包括 labels section。
我正在写 OS。我使用 asm!
宏来更改代码段。 (2020/06/08 详情改为asm!
here and in Rust RFC 2873)
pub unsafe fn set_code_segment(offset_of_cs: u16) {
asm!("push {0:r} // 64-bit version of the register
lea rax, 1f // or more efficiently, [rip + 1f]
push rax
retfq
1:", in(reg) offset_of_cs);
}
这行得通。但是,如果我使用push 1f
,标签1:
的地址将不会被推送。相反,它将是一个内存源操作数,从 [1:]
所以下面的代码
pub unsafe fn set_code_segment(offset_of_cs: u16) {
asm!("push {0:r}
push 1f // loads from 1f, how to push the address instead?
retfq
1:", in(reg) offset_of_cs);
}
将不起作用。反汇编(ndisasm
)代码是这样的:
11103 │ 0000B9EC 57 push rdi
11104 │ 0000B9ED FF3425F6B90080 push qword [0xffffffff8000b9f6]
11105 │ 0000B9F4 48CB retfq
用 nasm 语法编写的所需代码是这样的:
[bits 64]
extern set_code_segment
set_code_segment:
push rdi
push change_code_segment ; absolute address as a 32-bit immediate
retfq
change_code_segment:
ret
链接到内核(和extern "C" { pub fn set_code_segment(offset_of_cs: u16) -> () }
),代码可以工作。 change_code_segment
地址推送成功
所以我的问题是:为什么asm!
的push 1f
推送地址1:
的内容,而不是1:
的地址?
rust asm!
宏建立在 llvm
.
并且在llvm中有a specific bug解释只由0
和1
数字组成的标签,例如0
、11
或101010
,作为二进制值。这就是这里发生的事情,这个二进制值被读取为内存中的地址。
此外,rust asm!
文档已更新,现在包括 labels section。