`push label`push[label],而不是标签的地址(Rust asm!)
我正在写一个操作系统。我使用`push label`push[label],而不是标签的地址(Rust asm!),rust,x86-64,inline-assembly,Rust,X86 64,Inline Assembly,我正在写一个操作系统。我使用asm宏以更改代码段。(关于2020/06/08对asm!和中的更改的详细信息) pub不安全的fn集合码段(偏移量:u16){ asm!(“推送{0:r}//64位版本的寄存器 lea-rax,1f//或更有效,[rip+1f] 推拉 retfq 1:“,在(reg)偏移量中,”; } 这很有效。但是,如果我使用push 1f,标签1:的地址将不会被推送。相反,它将是一个内存源操作数,从[1://code> 所以下面的代码 pub不安全的fn集合码段(偏移量:u1
asm代码>宏以更改代码段。(关于2020/06/08对asm!
和中的更改的详细信息)
pub不安全的fn集合码段(偏移量:u16){
asm!(“推送{0:r}//64位版本的寄存器
lea-rax,1f//或更有效,[rip+1f]
推拉
retfq
1:“,在(reg)偏移量中,”;
}
这很有效。但是,如果我使用push 1f
,标签1:
的地址将不会被推送。相反,它将是一个内存源操作数,从[1://code>
所以下面的代码
pub不安全的fn集合码段(偏移量:u16){
asm!(“推送{0:r}
push 1f//从1f加载,如何改为推送地址?
retfq
1:“,在(reg)偏移量中,”;
}
这是行不通的。反汇编(通过NDISAM
)代码如下:
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_段(偏移量_of_cs:u16)->()}
)链接,代码可以工作。将成功推送change\u code\u段的地址
所以我的问题是:为什么asm的推1f
代码>推送地址1:
的内容,而不是1:
?的地址。asm代码>宏是基于llvm
构建的
在llvm中,有人将仅由0
和1
数字组成的标签(如0
、11
或101010
)解释为二进制值。这就是这里发生的事情,这个二进制值被读取为内存中的地址
还有,锈asm代码>文档已经更新,现在包含了一个。AFAIK,Rust的内联汇编从GCC中获得了一些灵感。因此,您可能需要使用$
前缀来指定您指的是立即操作数:push$1f
@Michael谢谢您的评论,但是push$1f
并没有改变这种情况。。。反汇编的代码是相同的。@PeterCordesr
of{0:r}
将寄存器的大小指定为64位。令我惊讶的是,使用16位寄存器会导致一般保护故障。我找到的文档明确表示,它应该使用GAS/LLVM样式的。英特尔语法noprefix
,因此我认为这是一个推送偏移1f
不起作用的错误。“我不确定报告此事的最佳地点。@PeterCordes感谢您提供了许多有用的意见。”。我发送了。关于github问题的评论建议使用2:
可能是一种解决方法。但是我测试了(在一个独立的.s
中,带有叮当声),并且。因此,我想使用.Lfoobar:
并希望asm不会在同一个文件中扩展两次,或者在asm模板字符串中寻找与GCC内联asm的%=
自动编号功能等效的生锈内联asm。