`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解释只由01数字组成的标签,例如011101010,作为二进制值。这就是这里发生的事情,这个二进制值被读取为内存中的地址。

此外,rust asm! 文档已更新,现在包括 labels section