我有一个功能,Rust&#LLVM的优化失败并导致恐慌(在发布版本中),而未经优化的代码(调试版本)工作正常。如果我比较生成的汇编代码,我甚至无法理解优化器试图完成的内容。 (原因可能是这个函数使用内联汇编程序。)
有没有办法告诉Rust在优化过程中单独保留某些功能,还是必须关闭所有优化?
以下是具体功能:
$ python app.py
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
127.0.0.1 - - [24/May/2017 20:38:21] "GET / HTTP/1.1" 200 -
Raw: {'json': {'type': 13, 'name': 'foo', 'isReadonly': True, 'id': 1}, 'filename': 'hello.py'}
Filename: hello.py
Dataset: {'type': 13, 'name': 'foo', 'isReadonly': True, 'id': 1}
127.0.0.1 - - [24/May/2017 20:38:22] "POST /hello HTTP/1.1" 200 -
答案 0 :(得分:6)
据我所知,除了整个箱子之外,Rust没有任何设施来指定优化级别。 您唯一的解决方法是在单个包中编译此函数,编译它,然后将其作为预编译依赖项包含在内。 (正常的锈蚀依赖性是在依赖者的优化级别编译的)
但是:为此单一功能指定不同的优化级别无法解决您的问题!当然,它今天可能会起作用,但每次编译器(或优化标志)发生变化时都会再次中断。
TL; DR :裸体功能非常不安全(我尊重,你是一个比我更勇敢的人!)。
使用它们的唯一可靠方法是只编写一个asm!()
块作为整个函数体,而不是其他任何块。
混合asm!
,正常的Rust和函数调用就像你正在做的那样是有效的Undefined Behavior(在可怕的C / Nasal-Demon意义上)没有多少优化调整会改变这个。
裸体功能仍然不稳定,直到Rust作者"正确#34;。 正如您所发现的,这有许多微妙的问题。跟踪稳定问题here
在naked-fn RFC," Motivation"下,我们发现:
因为编译器依赖于函数序言和结尾来维护局部变量绑定的存储,所以除了在裸函数内部编写内联汇编外,通常是不安全的。 LLVM语言参考将此功能描述为具有特定于系统的后果",程序员必须注意这些后果。
(强调我的)
在RFC中略低一点,在unresolved questions下,我们了解到这不仅仅是Rust的一个问题。其他语言也遇到此功能的问题:
..大多数支持类似功能的编译器要求或强烈建议作者在裸函数内部仅编写内联汇编,以确保不会生成假定特定堆栈布局的代码。
原因是所有编译器都对如何调用函数做了很多假设(关键字:"调用者保存的寄存器"," Callee保存的寄存器","呼叫约定","红区")。裸函数不遵守这些假设,因此编译器生成的任何代码都高度可能是错误的。 "解决方案"是不让编译器生成任何东西,即在汇编中手动编写整个函数。
因此,你正在混合正常的方式'代码(let mut nr: u32 = 0;
),函数调用(swi_service_routine(nr);
)和裸函数中的原始汇编程序是未指定的行为。 (是的,这样的东西存在于Rust中,但只存在于Unstable中)。
Naked函数导致了足够的问题,他们在Rust bugtracker中应该得到their own label。
在其中一个A-naked问题中,我们找到this comment,由知识渊博的用户Tari(其中包括llvm-sys
的作者。他解释说:
裸函数中非asm代码的实际正确性取决于优化器和代码生成器,通常我们无法保证它将做什么。
还谈到要求unsafe
裸体功能,因为它们打破了许多Rust的正常假设。事实上他们并非在所有情况下都要求is an open bug
因此,正确的解决方案来解决您的优化问题"是停止依赖优化。相反,只写一个asm!()
块。
对于Cpu::save_context()
/ Cpu::restore_context_and_return()
对:我可以理解代码重用的愿望。要获取它,请将它们更改为插入相关asm!(...)
的宏。 asm!(...); asm!(...); asm!(...);
的串联应等同于asm!()
。
答案 1 :(得分:-3)
如果您正在使用货物,您可以告诉它不要优化任何东西,或按级别