源码rust安装教程的rust,怎么设置RUST

> 博客详情
下载安装 Rust
http://www.rust-lang.org/index.html
下载安装 Racer
/phildawes/racer/
/phildawes/racer/archive/master.zip
1. 将 Rust 的 Bin 加入系统变量 Path 中
2. 运行 RustPath\bin\cargo build --release
安装 SublimeText
安装 Sublime 的 Rust 相关包 Rust ,RustAutoComplete
编辑 Sublime 下的插件包管理下的 RustAutoComplete 下的 Settings - User ,写入:&
& // racer.exe绝对路径
& "racer": "D:/RustPath/racer/target/racer.exe", &
& // rust源码文件路径
& "search_paths": [ "D:/RustPath/source/rust-nightly-src/rust-nightly/src" ]
支付宝支付
微信扫码支付
打赏金额: ¥
已支付成功
打赏金额: ¥新版rust怎么保存家推荐回答:哪服务器盖房退游戏家没别抄玩候再进入服务器家抄能重新存steam旗下的rust,准新版的指令谁能发一下,设置家,传送回家,传送到玩家,自杀,关闭草地,等推荐回答:设置家set xx设5传送家home xx传送玩家tpr xx自杀kill设置家 传送 要插件 纯净行rust正版如何设置画面推荐回答:什么画面,可视角吗?rust tp抄家法怎么弄,怎么tp?推荐回答:房周围放基设home点(/sethome 数字)传送home点(/home 数字)家要设home点或者放睡袋带着c4炸死传送家拿c4再传送房设home点继续炸防万设几腐蚀rust设置家的代码推荐回答:/set home1steam平台游戏腐蚀怎么设置中文推荐回答:腐蚀支持文steam平台绝部游戏都支持文些知名游戏厂商考虑游戏支持文问题新版rust怎么设置home点推荐回答:谢谢rust怎么设重生点无效,rust 腐蚀设置回家点推荐回答:标准服能设命令模组服类命令f1设置聊界面输入要基展开全部下一篇:拉杆箱密码锁怎么设置?金山词霸相信很多人都使用过,平时遇到什么英文单词不会了都可以用金山词霸进行翻译,那么您知道金山词霸怎么设置随时翻译吗?容声冰箱温度调节怎么设置?交换机怎么设置? 交换机设置步骤第1步:单击“开始”按钮,在“程序”菜单的“附件”选项中单击“超级终端”,弹出所示界面。苹果手机密码怎么设置四位数?qq相册怎么设置密码?qq相册设置密码的方法,首先,要先登录到自己的qq帐号,登录账号以后在qq面板上面点击空间小图标,也就是星号键。苹果手机虚拟按键怎么设置?设置方法介绍一苹果手机的虚拟按键设置,一般来说是需要九个详细步骤的。手机来电显示怎么设置?安卓手机来电显示归属地设置介绍手机来电显示的设置,我们先介绍安卓手机。手机定时关机怎么设置?介绍一手机定时关机功能的设置,首先要打开手机,找到“设置”图标。其次,是点击设置图标,找到“系统”-“定时开关机”。苹果手机怎么设置屏幕旋转?介绍一苹果手机设置屏幕旋转,首先,打开苹果手机的屏幕,用手指从屏幕底部向上滑动,即可打开手机的控制中心。主题信息(必填)
主题描述(最多限制在50个字符)
申请人信息(必填)
申请信息已提交审核,请注意查收邮件,我们会尽快给您反馈。
如有疑问,请联系
CSDN &《程序员》编辑/记者,投稿&纠错等事宜请致邮
你只管努力,剩下的交给时光!
如今的编程是一场程序员和上帝的竞赛,程序员要开发出更大更好、傻瓜都会用到软件。而上帝在努力创造出更大更傻的傻瓜。目前为止,上帝是赢的。个人网站:。个人QQ群:、
个人大数据技术博客:
作者:Filippo Valsorda
翻译:雁惊寒
摘要:本文介绍了在Go中调用Rust代码这个实验。你无需知道Rust或者编译器的内部原理,只需知道链接器有什么用即可。以下是译文Go语言完美支持直接调用汇编程序。stdlib中的很多快速加密代码都是使用精心优化过的汇编语言编写的,速度是优化前的20倍以上。但是,编写汇编代码很难,检查汇编代码更难。如果我们可以用更高级的语言编写这些热门函数就好了。本文介绍了在Go中调用Rust代码这个实验。你无需知道Rust或者编译器的内部原理,只需知道链接器有什么用即可。为什么是 Rust坦率地讲:我对Rust并不熟悉,也并不觉得自己用Rust进行日常编程是被迫的。然而,我知道Rust是一个可调和可优化的语言,并且比汇编更易阅读。(事实上任何一个语言都比汇编更容易阅读!)Go一直在努力寻找自己擅长的地方,但它只接受自己速度足够快这个特点。我很喜欢它这个特点。但对于我们今天要做的工作,我们需要有一种语言,它能在手动关闭了安全检查的情况下生成完全基于栈的函数。因此,如果存在一种语言,我们能够像约束汇编一样约束它,并能像汇编一样进行优化,那它可能就是Rust。最后,Rust安全性高,更新频繁,尤其存在着一个很不错的高性能Rust加密代码生态系统。为什么不是 cgoGo具备机制,名叫cgo。 允许Go程序以最自然的方式调用C函数(但其实一点都不自然)。通过使用C的作为FFI的,我们可以在任何语言中调用其他任何语言:Rust可以编译成一个暴露C接口的库,然后cgo就可以使用它了。这很尴尬,但确实有效。我们甚至可以使用reverse-cgo把Go编译到C库中,供其他任意一个语言调用,例如。但是,cgo为了实现这个功能做了很多事情:它为C的生存生成了一个完整的栈,这使得在Go回调中存在一定的延迟……这简直可以写一篇文章了。因此,每一次cgo调用的性能成本对于我们这个例子来说实在太高了。将它们链接在一起所以我的想法是:如果我们可以让Rust代码像汇编一样受到约束,我们应该就能够想汇编一样使用它,直接调用它。也许还要用一点点胶水。我们没有必要在工作,因为Go编译器从开始就能在链接之前将代码和高级汇编转换为机器码了。这是“”机制所决定的,该机制就是使用系统链接器将代码和高级汇编组合成一个Go程序。同时,这也是cgo的工作原理:它使用C编译器编译C,使用Go编译器编译Go,然后使用clang或gcc将这两者链接在一起。我们甚至可以使用CGO_LDFLAGS将标记传递给链接器。在cgo安全特性的底层能找到一个跨语言的函数调用。如果我们可以弄清楚如何在不给编译器打补丁的情况下做到这一点就好了。首先,我们来搞清楚如何将Go程序与Rust文件链接到起来。除了使用#cgo指令之外,我找不到一种使用go build命令链接到外部blob的体面方式。但是,调用cgo。值得庆幸的是只是一个前端工具,其他什么都没做! Go提供了一套低级工具可以用来和程序,go build只是收集文件并调用这些工具。我们可以使用-x标志来跟踪编译链接过程。我通过在cgo构建中增加-x -ldflags "-v -linkmode=external '-extldflags=-v'"来构建下面这个简单的 Makefile。rustgo: rustgo.a
go tool link -o rustgo -extld clang -buildmode exe -buildid b01dca11ab1e -linkmode external -v rustgo.a
rustgo.a: hello.go hello.o
go tool compile -o rustgo.a -p main -buildid b01dca11ab1e -pack hello.go
go tool pack r rustgo.a hello.o
hello.o: hello.s
go tool asm -I "$(shell go env GOROOT)/pkg/include" -D GOOS_darwin -D GOARCH_amd64 -o hello.o hello.s
这个Makefile文件将编译出一个由Go文件(hello.go)和Go汇编文件(hello.s)组成的简单主程序包。现在,如果我们要链接一个Rust对象,我们首先要将其构建为一个静态库……libhello.a: hello.rs
rustc -g -O --crate-type staticlib hello.rs
……然后告诉外部链接器将它们链接在一起。rustgo: rustgo.a libhello.a
go tool link -o rustgo -extld clang -buildmode exe -buildid b01dca11ab1e -linkmode external -v -extldflags='-lhello -L"$(CURDIR)"' rustgo.a
go tool asm -I "/usr/local/Cellar/go/1.8.1_1/libexec/pkg/include" -D GOOS_darwin -D GOARCH_amd64 -o hello.o hello.s
go tool compile -o rustgo.a -p main -buildid b01dca11ab1e -pack hello.go
go tool pack r rustgo.a hello.o
rustc --crate-type staticlib hello.rs
note: link against the following native artifacts when linking against this static library
note: the order and any duplication can be significant on some platforms, and so may need to be preserved
note: library: System
note: library: c
note: library: m
go tool link -o rustgo -extld clang -buildmode exe -buildid b01dca11ab1e -linkmode external -v -extldflags="-lhello -L/Users/filippo/code/misc/rustgo" rustgo.a
HEADER = -H1 -T0x1001000 -D0x0 -R0x1000
searching for runtime.a in /usr/local/Cellar/go/1.8.1_1/libexec/pkg/darwin_amd64/runtime.a
searching for runtime/cgo.a in /usr/local/Cellar/go/1.8.1_1/libexec/pkg/darwin_amd64/runtime/cgo.a
0.00 deadcode
0.00 pclntab=166785 bytes, funcdata total 17079 bytes
0.01 dodata
0.01 symsize = 0
0.01 symsize = 0
0.01 reloc
0.01 dwarf
0.02 symsize = 0
0.02 reloc
0.02 codeblk
0.03 datblk
0.03 headr
0.06 host link: "clang" "-m64" "-gdwarf-2" "-Wl,-headerpad,1144" "-Wl,-no_pie" "-Wl,-pagezero_size,4000000" "-o" "rustgo" "-Qunused-arguments" "/var/folders/ry/v14gg02d0y9cb2w00gn/T/go-link-/go.o" "/var/folders/ry/v14gg02d0y9cb2w00gn/T/go-link-0000.o" "-g" "-O2" "-lpthread" "-lhello" "-L/Users/filippo/code/misc/rustgo"
0.34 cpu time
12641 symbols
5764 liveness data
跳转到Rust中好了,链接成功了,下面我们需要在Go代码中以某种方式调用Rust函数了。我们知道如何在Go中调用Go函数。在汇编中,调用函数是这样的:CALL hello(SB),其中SB是与所有的全局符号有关的虚拟寄存器。如果想要在Go中调用一个汇编函数,就要在代码中加上func hello()(无需函数体),以便让编译器知道这个函数的存在。我尝试了上述的所有的方法来调用外部(Rust)函数,但都提示找不到符号名称或函数体。但是在某一天,cgo终于以某种方式成功调用了这个外部函数!怎么做到的呢?几天之后,我偶然间发现了。
var __cgofn__cgoPREFIX_Cfunc__Cmalloc byte
var _cgoPREFIX_Cfunc__Cmalloc = unsafe.Pointer(&__cgofn__cgoPREFIX_Cfunc__Cmalloc)
这看起来很有趣! //go:linkname只是在本地范围内创建了一个符号别名(! ),我很确定byte只是用来取某个东西的地址,但是//go:cgo_import_static…… 这会导入一个外部符号!有了这个新工具和上面那个Makefile,我们就有机会调用这个Rust函数了(hello.rs)#[no_mangle]
pub extern fn hello() {
println!("Hello, Rust!");
在这个Go程序中(hello.go)package main
func trampoline()
func main() {
println("Hello, Go!")
trampoline()
在这一小段汇编的帮助下。(hello.s)TEXT ·trampoline(SB), 0, $2048
JMP hello(SB)
CALL有点太聪明了,改用一个简单的JMP……Hello, Go!
Hello, Rust!
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x0]
嗯,它在试图返回时崩溃了。也就是说,$2048的值是Rust允许的整个栈的大小。不要问我如果Rust尝试触碰一个堆会发生什么……但是,我们惊奇地发现这竟然能跑起来!调用约定现在,需要返回一些东西,并传入一些参数,我们需要关注一下Go和Rust的调用约定。 定义了参数和返回值在函数调用中的位置。Go的调用约定可以在和找到。对于Rust,我们要看一下,这是标准C的调用约定。我们还需要一个调试器。Go调用约定Go调用约定记录,但是我们需要了解一下才能继续进行后续的工作,所以,我们可以从反汇编中学到一点东西。我们来看一个非常简单的函数。
TEXT ·foo(SB), 0, $256-24
MOVQ x+0(FP), DX
MOVQ DX, ret+16(FP)
foo拥有本地帧的256个字节(0x100),参数16个字节,返回值8个字节,并返回第一个参数。func main() {
foo(0xf0f0f0f0f0f0f0f0, 0x5555)
rustgo[0x49d785]:
movabsq $-0xf0f0f0f0f0f0f10, %rax
rustgo[0x49d78f]:
%rax, (%rsp)
rustgo[0x49d793]:
movabsq $0x5555, %rax
rustgo[0x49d79d]:
%rax, 0x8(%rsp)
rustgo[0x49d7a2]:
0x49d8a0 main.foo at hello.s:14
从上面的代码可以看出,调用者做的事情很少:它将参数逆序放入栈中,也就是在自有帧的底部(rsp到16(rsp),记住,栈是向下生长的),然后执行CALL。 CALL会将返回指针压入栈中并进行跳转。注意,rsp是固定的,我们用了movq,而不是push。`.foo
[0x49d8a0]:
[0x49d8a9]:
[0x49d8b1]:
[0x49d8b5]:
0 .foo + 78
[0x49d8ee]:
0 .morestack_noctxt
[0x49d8f3]:
函数的前4个和最后2个指令是检查栈在不调用runtime.morestack的情况下是否有足够的空间。它们可能被跳过了NOSPLIT函数。rustgo[0x49d8b7]:
$0x108, %rsp
rustgo[0x49d8e6]:
$0x108, %rsp
rustgo[0x49d8ed]:
接着是rsp管理,它将减去0x108,为0x100字节的帧的和8个字节的帧指针让出空间。所以rsp指向函数帧的底部。在返回之前,rsp会返回到它原来所在的位置。rustgo[0x49d8be]:
%rbp, 0x100(%rsp)
rustgo[0x49d8c6]:
0x100(%rsp), %rbp
rustgo[0x49d8de]:
0x100(%rsp), %rbp
最后,将移到栈上(在返回指针的后面),并在rbp处更新。rustgo[0x49d8ce]:
0x110(%rsp), %rdx
rustgo[0x49d8d6]:
%rdx, 0x120(%rsp)
最后,从代码本身可以看出,返回值刚好超过了参数。虚拟寄存器Go文档说,SP和FP是虚拟寄存器,而不仅仅是rsp和rbp的别名。实际上,当从Go汇编访问SP的时候,偏移量会相对于真正的rsp来进行调整,使得SP指向帧的顶部而不是底部。这很方便,因为这意味着在更改帧大小的时候无需更改所有的偏移量,但这只是语法糖。如果要直接访问寄存器(如MOVQ SP, DX),那么直接访问rsp即可。FP虚拟寄存器也是相对于rsp的偏移量。它指向调用者帧的底部,也就是参数所在的地方。注意:Go保留rbp和帧指针的目的是用于调试,但是使用固定的rsp和omit-stack-pointer风格的rsp偏移量则用于虚拟FP。你可以从中了解更多有关帧指针的信息。C调用约定x86-64上的默认C调用约定“”是完全不同的:
参数通过寄存器传递:RDI,RSI,RDX,RCX,R8和R9。
返回值转到RAX。
一些寄存器由被调用者保存:RBP,RBX和R12-R15。
我们几乎不关心这一点,因为在Go中,所有寄存器中都由调用者保存。
栈必须是16字节对齐。
(我认为这是为什么可以用JMP,而不能用CALL的原因,栈没有字节对齐!)
帧指针也是这么工作的(通过rustc附带-g生成)。将它们粘在一起在两个约定之间建立一个简单的蹦床并不难。我们也可以看看来获取灵感,因为它的功能大致相同。请记住,我们希望Rust函数使用汇编函数的栈空间,这样可以确保栈一直存在。要做到这一点,我们必须从栈的末尾回滚rsp。package main
func trampoline(arg uint64) uint64
func main() {
println(trampoline(41))
TEXT ·trampoline(SB), 0, $2048-16
MOVQ arg+0(FP), DI
MOVQ SP, BX
ADDQ $2048, SP
ANDQ $~15, SP
CALL increment(SB)
MOVQ BX, SP
MOVQ AX, ret+8(FP)
#[no_mangle]
pub extern fn increment(a: u64) -& u64 {
return a + 1;
macOS上CALLCALL在macOS上无法工作。由于某种原因,函数调用需要被替换为_cgo_thread_start的中间调用,考虑到我们使用的东西叫做cgo_import_static,并且CALL在Go汇编中是虚拟的,所以这很正常。callq
0x40a27cd x_cgo_thread_start + 29
我们可以通过使用在标准库中找到的完整的//go:linkname语法来绕过这个“助手”,以获取指向该函数的指针,然后像这样调用函数指针。import _ "unsafe"
var increment uintptr
var _increment = &increment
MOVQ ·_inc
它快吗整个练习的重点是要能够调用Rust。因此,rustgo调用必须要才有用。评测时间!我们将比较//go:noinline函数中增加一个内联uint64变量的值,使用上文中的rustgo调用,以及一个cgo调用。Rust用-g -O进行编译,基准测试在CPU是2.9GHz Intel Core i5的macOS上运行。name
CallOverhead/Inline
1.72ns ± 3
CallOverhead/Go
4.60ns ± 2
CallOverhead/rustgo
5.11ns ± 4
CallOverhead/cgo
73.6ns ± 0
rustgo比Go函数调用慢11%,比cgo快了几乎15倍!在没有函数指针的Linux上运行时,性能更好,只有2%的开销。name
CallOverhead/Inline
1.67ns ± 2
CallOverhead/Go
4.49ns ± 3
CallOverhead/rustgo
4.58ns ± 3
CallOverhead/cgo
69.4ns ± 0
实例对于这个真实的演示,我选择了优秀的curve25519-dalek库,特别是将曲线基点乘以标量并返回其Edwards表示的任务。由于存在的影响,Cargo基准在多次执行的时候摇摆不定,但他们建议操作将占用22.9μs±17%。test curve::bench::basepoint_mult
... bench:
17,276 ns/iter (+/- 3,057)
test curve::bench::edwards_compress
... bench:
5,633 ns/iter (+/- 858)
在GO方面,我们暴露了一个简单的API。func ScalarBaseMult(dst, in *[32]byte)
在Rust方面,它与建立没有区别。老实说,我花了好长时间才弄明白Rust并完成这项工作。#![no_std]
extern crate curve25519_
use curve25519_dalek::scalar::S
use curve25519_dalek::
#[no_mangle]
pub extern fn scalar_base_mult(dst: &mut [u8; 32], k: &[u8; 32]) {
let res = &constants::ED25519_BASEPOINT_TABLE * &Scalar(*k);
dst.clone_press_edwards().as_bytes());
要构建.a,我们使用了cargo build --release与定义依赖关系的Cargo.toml,启用了帧指针,并配置curve25519-dalek以使用最高效的数学和非标准库。[package]
name = "ed25519-dalek-rustgo"
version = "0.0.0"
crate-type = ["staticlib"]
[dependencies.curve25519-dalek]
version = "^0.9"
default-features = false
features = ["nightly"]
[profile.release]
debug = true
最后,我们需要调整蹦床,来传入两个参数,不返回任何值。TEXT ·ScalarBaseMult(SB), 0, $16384-16
MOVQ dst+0(FP), DI
MOVQ in+8(FP), SI
MOVQ SP, BX
ADDQ $16384, SP
ANDQ $~15, SP
MOVQ ·_scalar_base_mult(SB), AX
MOVQ BX, SP
结果是一个透明的Go调用,性能与纯Rust基准测试非常接近,比cgo几乎快了6%!name
old time/op
new time/op
RustScalarBaseMult
23.7μs ± 1%
22.3μs ± 4%
(p=0.003 n=5+7)
作为比较,/agl/ed25519/edwards25519提供了类似的功能,纯Go库的耗时几乎是3倍。h := &edwards25519.ExtendedGroupElement{}
edwards25519.GeScalarMultBase(h, &k)
h.ToBytes(&dst)
GoScalarBaseMult
66.1μs ± 2%
包装起来现在我们知道它确实能用,太开心了!但是要使用的话,它必须是一个可导入的包,而不是被一个奇怪的构建过程强制写上package main。用来解决这个问题!这个注解告诉编译器忽略包的源,并且只能在$GOPATH/pkg中使用预先构建的.a库文件。如果我们可以设法构建一个能与Go的本地链接器一起使用的.a文件,我们可以进行重发布,并且允许用户把它当成本地包一样的进行导入,包括交叉编译!在Go侧则很简单。
package edwards25519
import _ "unsafe"
var scalar_base_mult uintptr
var _scalar_base_mult = &scalar_base_mult
func ScalarBaseMult(dst, in *[32]byte)
Makefile必须要修改一下,因为我们不再是构建一个二进制文件了,我们不能再使用go tool link。.a文件是多个.o组成的打包文件。.a文件由ar这个UNIX工具来管理,或者由Go内部工具来管理。当然,这两种格式略有不同。我们需要使用ar来管理libed25519_dalek_rustgo.a,用Go的cmd/pack来管理edwards25519.a。要绑定这两个库,我试着做了一件最简单的事情:将libed25519_dalek_rustgo.a提取到一个临时文件夹中,然后将对象打包到edwards25519.a文件中。edwards25519/edwards25519.a: edwards25519/rustgo.go edwards25519/rustgo.o target/release/libed25519_dalek_rustgo.a
go tool compile -N -l -o $@ -p main -pack edwards25519/rustgo.go
go tool pack r $@ edwards25519/rustgo.o
mkdir -p target/release/libed25519_dalek_rustgo && cd target/release/libed25519_dalek_rustgo && \
rm -f *.o && ar xv "$(CURDIR)/target/release/libed25519_dalek_rustgo.a"
go tool pack r $@ target/release/libed25519_dalek_rustgo/*.o
.PHONY: install
install: edwards25519/edwards25519.a
mkdir -p "$(shell go env GOPATH)/pkg/darwin_amd64/$(IMPORT_PATH)/"
cp edwards25519/edwards25519.a "$(shell go env GOPATH)/pkg/darwin_amd64/$(IMPORT_PATH)/"
太惊喜了,这竟然有用!把.a放在适当的位置,就可以使用这个包来制作一个简单的程序了。package main
"encoding/hex"
"/FiloSottile/ed25519-dalek-rustgo/edwards25519"
func main() {
input, _ := hex.DecodeString("bbd7e17aa737fc3bf430fcbc60aab3707")
expected, _ := hex.DecodeString("1ccf84ad91ff532c1af1fac7b62f7ebcbcf")
var dst, k [32]byte
copy(k[:], input)
edwards25519.ScalarBaseMult(&dst, &k)
if !bytes.Equal(dst[:], expected) {
fmt.Println("rustgo produces a wrong result!")
fmt.Printf("BenchmarkScalarBaseMult\t%v\n", testing.Benchmark(func(b *testing.B) {
for i := 0
edwards25519.ScalarBaseMult(&dst, &k)
然后运行go build!$ go build -ldflags '-linkmode external -extldflags -lresolv'
$ ./ed25519-dalek-rustgo
BenchmarkScalarBaseMult
19914 ns/op
太好了,这么做是有效的,我们成功欺骗了编译器。除非我们把它链接到libresolv,否则这个二进制文件不会被编译。note: link against the following native artifacts when linking against this static library
note: the order and any duplication can be significant on some platforms, and so may need to be preserved
note: library: System
note: library: resolv
note: library: c
note: library: m
现在,链接成系统库将是一个问题,因为它将永远不会发生内部链接和交叉编译……但是,等一会儿,libresolv呢? 为什么我们的no_std“应该像汇编一样”,只使用栈的Rust库要去解析DNS域名呢?no_std问题问题是这个库实际上并不是no_std。看看这里的东西!我们希望与分配器无关!$ ar t target/release/libed25519_dalek_rustgo.a
ed25519_dalek_rustgo-742a1d9f1c101d86.0.o
ed25519_dalek_rustgo-742a1d9f1c101d86.crate.allocator.o
curve25519_dalek-03e3ca0f6d904d88.0.o
subtle-cd04ba.0.o
std-72653eb.0.o
panic_unwind-d0ba9.0.o
unwind-da13b.0.o
arrayref-2be0c0ff08ae2c7d.0.o
digest-fca45.0.o
generic_array-95ca86a62dc11ddc.0.o
nodrop-7df18ca19bb4fc21.0.o
odds-3bc0ea0bdf8209aa.0.o
typenum-a61ae.0.o
rand-e0d585156faee9eb.0.o
alloc_system-cf049140.0.o
libc-e038d130d15e5dae.0.o
alloc-0e789bf.0.o
std_unicode-9735142be30abc63.0.o
compiler_builtins-8a5da980a34153c7.0.o
[... snip ...]
truncsfhf2.o
core-9077840c2cc91cbf.0.o
那么我们实际上是如何让它no_std的呢?下面我就简单介绍一下。
如果任何一个依赖不是no_std,那么你的no_std标志是无效的。 curve25519-dalek依赖之一有这个问题,cargo update解决了这个问题。
实际上,生成一个no_std静态库更像是生成一个no_std可执行程序,但生成后者更加困难,因为它必须是独立的。
有关如何生成“no_std”可执行程序的文档非常少。我主要阅读了,并最终发现了。 很有用。
对于初学者,需要定义“lang_items”函数来处理通常在stdlib中的功能,如panic_fmt。
由于你没有`compiler-rt’的Rust等效标志,所以你必须导入条件库compiler_builtins。
然后,由于“rust_begin_unwind”没有导出,所以存在一个问题,但是通过将panic_fmt标记为no_mangle来解决。
这一切都归结到lib.rs顶部的一系列的神秘线。#![no_std]
#![feature(lang_items, compiler_builtins_lib, core_intrinsics)]
use core::
#[allow(private_no_mangle_fns)] #[no_mangle]
#[lang = "panic_fmt"] fn panic_fmt() -& ! { unsafe { intrinsics::abort() } }
#[lang = "eh_personality"] extern fn eh_personality() {}
extern crate compiler_
而且,在macOS上,go build起作用(!!!)Linux在Linux上完全没用。外部链接提示缺少fmax和其他一些符号。$ ld -r -o linux.o target/release/libed25519_dalek_rustgo/*.o
$ nm -u linux.o
U _GLOBAL_OFFSET_TABLE_
幸亏一位朋友建议我使用--gc-sections来删除无用的代码,这确实有效。$ go build -ldflags '-extld clang -linkmode external -extldflags -Wl,--gc-sections'
但是,在Makefile中我们根本没有使用链接器,那么应该把--gc-sections放在哪里呢? 不要再考虑.a的问题了,我们来看下链接器的吧。我们可以使用ld -r --gc-sections -u $SYMBOL来构建一个包含给定符号及其他所有符号的.o文件。 -r使得对象可以为以后的链接重用,而-u会根据需要标记一个符号,否则所有的东西都会被垃圾收集掉。 在我们的例子中,$SYMBOL就是scalar_base_mult。为什么在macOS上不存在这个问题呢? 如果我们手动链接就会出现这个问题,但是macOS编译器在默认情况下会自动去掉无用的符号。$ ld -e _scalar_base_mult target/release/libed25519_dalek_rustgo/*.o
Undefined symbols for architecture x86_64:
"___assert_rtn", referenced from:
_compilerrt_abort_impl in int_util.o
"_copysign", referenced from:
___divdc3 in divdc3.o
___muldc3 in muldc3.o
"_copysignf", referenced from:
___divsc3 in divsc3.o
___mulsc3 in mulsc3.o
"_copysignl", referenced from:
___divxc3 in divxc3.o
___mulxc3 in mulxc3.o
"_fmax", referenced from:
___divdc3 in divdc3.o
"_fmaxf", referenced from:
___divsc3 in divsc3.o
"_fmaxl", referenced from:
___divxc3 in divxc3.o
"_logb", referenced from:
___divdc3 in divdc3.o
"_logbf", referenced from:
___divsc3 in divsc3.o
"_logbl", referenced from:
___divxc3 in divxc3.o
"_scalbn", referenced from:
___divdc3 in divdc3.o
"_scalbnf", referenced from:
___divsc3 in divsc3.o
"_scalbnl", referenced from:
___divxc3 in divxc3.o
ld: symbol(s) not found for inferred architecture x86_64
$ ld -e _scalar_base_mult -dead_strip target/release/libed25519_dalek_rustgo/*.o
这是Makefile的一部分,它能够与外部链接一起使用。edwards25519/edwards25519.a: edwards25519/rustgo.go edwards25519/rustgo.o edwards25519/libed25519_dalek_rustgo.o
go tool compile -N -l -o $@ -p main -pack edwards25519/rustgo.go
go tool pack r $@ edwards25519/rustgo.o edwards25519/libed25519_dalek_rustgo.o
edwards25519/libed25519_dalek_rustgo.o: target/$(TARGET)/release/libed25519_dalek_rustgo.a
ifeq ($(shell go env GOOS),darwin)
$(LD) -r -o $@ -arch x86_64 -u "_$(SYMBOL)" $^
$(LD) -r -o $@ --gc-sections -u "$(SYMBOL)" $^
最后一个缺失的部分是Linux上的内部链接。简而言之,即使编译似乎成功了,。重新定位没有发生,Rust函数中的CALL指令指向了无意义的地址。
我仍然不知道为什么把它留那会导致这个问题,但添加它的话又能使rustgo包同时在外部和内部链接,在Linux和macOS上都有效。重发布现在,我们可以构建一个.a了,我们可以在规范中获得说明,并为linux_amd64/darwin_amd64和包源创建一个包含多个.a的压缩包,这样就可以通过将这个压缩包解压到GOPATH目录中进行安装了。$ tar tf ed25519-dalek-rustgo_go1.8.3.tar.gz
src/github.com/FiloSottile/ed25519-dalek-rustgo/
src/github.com/FiloSottile/ed25519-dalek-rustgo/.gitignore
src/github.com/FiloSottile/ed25519-dalek-rustgo/Cargo.lock
src/github.com/FiloSottile/ed25519-dalek-rustgo/Cargo.toml
src/github.com/FiloSottile/ed25519-dalek-rustgo/edwards25519/
src/github.com/FiloSottile/ed25519-dalek-rustgo/main.go
src/github.com/FiloSottile/ed25519-dalek-rustgo/Makefile
src/github.com/FiloSottile/ed25519-dalek-rustgo/release.sh
src/github.com/FiloSottile/ed25519-dalek-rustgo/src/
src/github.com/FiloSottile/ed25519-dalek-rustgo/target.go
src/github.com/FiloSottile/ed25519-dalek-rustgo/src/lib.rs
src/github.com/FiloSottile/ed25519-dalek-rustgo/edwards25519/rustgo.go
src/github.com/FiloSottile/ed25519-dalek-rustgo/edwards25519/rustgo.s
pkg/linux_amd64/github.com/FiloSottile/ed25519-dalek-rustgo/edwards25519.a
pkg/darwin_amd64/github.com/FiloSottile/ed25519-dalek-rustgo/edwards25519.a
一旦像上述那样安装完之后,软件包就可以像本地包那样使用了。我们唯一需要担心的问题是,如果我们使用-Ctarget-cpu=native来构建Rust,那么它可能无法在老的CPU上运行。幸亏性能测试()告诉了我们Haswell之前的处理器和Haswell之后的处理器的不同,所以我们只需要构建一个普遍包和一个针对Haswell处理器的包就可以了。$ benchstat bench-none.txt bench-haswell.txt
old time/op
new time/op
ScalarBaseMult/rustgo
22.0μs ± 3%
20.2μs ± 2%
(p=0.001 n=7+6)
$ benchstat bench-haswell.txt bench-native.txt
old time/op
new time/op
ScalarBaseMult/rustgo
20.2μs ± 2%
20.1μs ± 2%
(p=0.945 n=6+7)
根据上面的分析,我遵循GOOS/GOARCH对Makefile做了修改,将其根据需要转换为Rust目标三元组,因此如果要将Rust设置为交叉编译,那么甚至可以交叉编译.a本身。结果如下:。在也有。把它变成一个真实的东西是的,这很有趣!但要主意,rustgo并不能在生产环境中使用。例如,我怀疑我应该在跳转之前保存g。为了使其成为一件真实的东西,我将从NOSPLIT汇编函数手动调用morestack开始,以确保有足够的goroutine栈空间(而不是回滚rsp)。所有这些都可以通过一些“rustgo”工具来分析、生成,以及构建,而不是在Makefile和汇编文件中中硬编码。 cgo本身就是一个代码生成工具。此外,FFI类型的Rust侧集合,比如说GoSlice,也不错。#[repr(C)]
struct GoSlice {
array: *mut u8,}

我要回帖

更多关于 steam rust安装不了 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信