龙空技术网

从.NET9到Rust

opendotnet 151

前言:

此时小伙伴们对“net decimal”大致比较注重,大家都想要知道一些“net decimal”的相关资讯。那么小编在网摘上汇集了一些关于“net decimal””的相关文章,希望你们能喜欢,姐妹们一起来了解一下吧!




前言

前一篇:从.NET9看Golang,里面了解了下Go可执行文件,Main入口并没有经过Glibc,而是有Go自己的库调用的。本篇继续扩展,看下Rust。先说下结论,实际上经过个人测试,除了Go,Rust/.NET/C/C++都是经过Glibc来调用Main的。

问题

首先解决下上一篇从.NET9看Golang的一个问题,也即是Go的main调用地方实际上是/usr/lib/go-1.18/src/runtime/proc.go:259堆栈处,实际249处,代码如下:

func main() { 146 g := getg() 147  148 // Racectx of m0->g0 is used only as the parent of the main goroutine. 149 // It must not be used for anything else. 150 g.m.g0.racectx = 0 151  152 // Max stack size is 1 GB on 64-bit, 250 MB on 32-bit. 153 // Using decimal instead of binary GB and MB because 154 // they look nicer in the stack overflow failure message. 155 if goarch.PtrSize == 8 { 156 maxstacksize = 1000000000 157 } else { 158 maxstacksize = 250000000 159 } //中间省略 249 fn := main_main // make an indirect call, as the linker doesn't know the address o f the main package when laying down the runtime 250 fn() 251 if raceenabled { 252 racefini() 253 }

}

可以看到Go实际是自举自己调用了main,然后通过这个main调用了用户写的那个main.

 249 fn := main_main // make an indirect call, as the linker doesn't know the address o f the main package when laying down the runtime 250 fn()

而在这之前实际上它还调用了一个syscall进行一些用户main调用之前的操作。

 306 MOVL size+24(FP), R10 307 MOVL $SYS_rt_sigprocmask, AX 308 SYSCALL-> 309 CMPQ AX, $0xfffffffffffff001 310 JLS 2(PC) 311 MOVL $0xf1, 0xf1 // crash 312 RET
那么用户态下的linux第一个启动Go的是谁呢?
1568 // The top-most function running on a goroutine1569 // returns to goexit+PCQuantum.1570 TEXT runtime·goexit(SB),NOSPLIT|TOPFRAME,$0-01571 BYTE $0x90 // NOP1572 CALL runtime·goexit1(SB) // does not return1573 // traceback from goexit1 must hit code range of goexit1574 BYTE $0x90 // NOP

在goroutine上运行的最顶级函数,返回goexit+PCQuantum。实际上Linux用户态的main就是有它(runtime·goexit(SB))调用的,后者则调用go的用户态main,运行整个go程序。Rust
#curl --proto '=https' --tlsv1.2 -sSf  | sh 安装#cargo new rust-hello#cd rust-hello#cargo build#cd target/debug#./hello-rust

注意如果单个.rs文件Compile,是不被lldb识别的没有sysmbol,所以这里需要通过cargo创建项目。也可以rust-lldb,但需要脚本支撑,这里不做讨论。

#lldb hello-rust(lldb)b main(lldb)r(lldb)bt* thread #1, name = 'hello-rust', stop reason = breakpoint 1.2 * frame #0: 0x000055555555b7e0 hello-rust`main frame #1: 0x00007ffff7c29d90 libc.so.6`__libc_start_call_main(main=(hello-rust`main), argc=1, argv=0x00007fffffffdec8) at libc_start_call_main.h:58:16 frame #2: 0x00007ffff7c29e40 libc.so.6`__libc_start_main_impl(main=(hello-rust`main), argc=1, argv=0x00007fffffffdec8, init=0x00007ffff7ffd040, fini=<unavailable>, rtld_fini=<unavailable>, stack_end=0x00007fffffffdeb8) at libc-start.c:392:3 frame #3: 0x000055555555b635 hello-rust`_start + 37

看到了亲切的libc-start.c。下面是Rust调用ASM,注意引入use core::arch::asm; cargo build的时候会有两个警告。mut是变量,结果为8。

use core::arch::asm;

fn main() { let mut x: u32 = 5; unsafe { asm!( "add {0}, {1}", inout(reg) x, in(reg) 3 ); } println!("Result: {}", x);}

.NET9调用Rust lib,如下命令

#cargo new hello-rust --lib 创建一个lib项目#cd hello-rust#vim src/lib.rs#[no_mangle]pub extern "C" fn add(a: i32, b: i32) -> i32 { a + b}

把Cargo.toml添加一个Lib项

[lib]crate-type = ["cdylib"] # 或 "dylib" 根据需要选择

然后Cargo build --relese,生成的.so在hello-rust根目录的target/release下面名称规范:lib+项目名称.so,那么本例是:librust_hello.so。新建一个NET9项目,把librust_hello.so复制到bin/Debug/net9.0/,Program.cs如下:

using System;using System.Runtime.InteropServices;class Program{ [DllImport("libhello_rust.so", CallingConvention = CallingConvention.Cdecl)] public static extern int add(int a, int b); static void Main() { int result = add(10, 20); Console.WriteLine($"Result: {result}"); // 输出: Result: 30 }}

标签: #net decimal