首页 > 编程语言 >0181-汇编调用 Rust

0181-汇编调用 Rust

时间:2024-07-15 09:23:31浏览次数:8  
标签:info 汇编 0181 MiB component mov nightly 64 Rust

环境

  • Time 2022-11-12
  • WSL-Ubuntu 22.04
  • QEMU 6.2.0
  • NASM 2.15.05
  • Rust 1.67.0-nightly

前言

说明

参考:https://os.phil-opp.com/set-up-rust/

目标

从汇编代码中调用 Rust 代码。该篇基于之前编写的进入 64 位模式的汇编代码。

切换到 nightly 版本

切换命令:rustup override set nightly

root@jiangbo12490:~/git/game# rustup override set nightly
info: syncing channel updates for 'nightly-x86_64-unknown-linux-gnu'
750.8 KiB / 750.8 KiB (100 %) 447.4 KiB/s in  1s ETA:  0s
info: latest update on 2022-11-12, rust version 1.67.0-nightly (42325c525 2022-11-11)
info: downloading component 'cargo'
  6.5 MiB /   6.5 MiB (100 %)   4.6 MiB/s in  2s ETA:  0s
info: downloading component 'clippy'
info: downloading component 'rust-docs'
 19.2 MiB /  19.2 MiB (100 %)   5.6 MiB/s in  3s ETA:  0s
info: downloading component 'rust-std'
 29.8 MiB /  29.8 MiB (100 %)   5.5 MiB/s in  5s ETA:  0s
info: downloading component 'rustc'
 68.0 MiB /  68.0 MiB (100 %)   6.1 MiB/s in 12s ETA:  0s
info: downloading component 'rustfmt'
info: installing component 'cargo'
info: installing component 'clippy'
info: installing component 'rust-docs'
 19.2 MiB /  19.2 MiB (100 %)  12.7 MiB/s in  1s ETA:  0s
info: installing component 'rust-std'
 29.8 MiB /  29.8 MiB (100 %)  19.3 MiB/s in  1s ETA:  0s
info: installing component 'rustc'
 68.0 MiB /  68.0 MiB (100 %)  22.0 MiB/s in  3s ETA:  0s
info: installing component 'rustfmt'
info: override toolchain for '/root/git/game' set to 'nightly-x86_64-unknown-linux-gnu'

  nightly-x86_64-unknown-linux-gnu installed - rustc 1.67.0-nightly (42325c525 2022-11-11)

Cargo.toml

[package]
name = "myos"
version = "0.1.0"
edition = "2021"

[dependencies]

[lib]
crate-type = ["staticlib"]

[profile.dev]
panic = "abort"

[profile.release]
panic = "abort"

lib.rs 代码

#![feature(lang_items)]
#![no_std]

use core::panic::PanicInfo;

#[no_mangle]
pub extern "C" fn rust_main() {
    let a = 4444;
    let name = "jiangbo";
}

#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
    loop {}
}

myos.json

{
    "llvm-target": "i686-unknown-none",
    "data-layout": "e-m:e-p:32:32-f64:32:64-f80:32-n8:16:32-S128",
    "linker-flavor": "gcc",
    "target-endian": "little",
    "target-pointer-width": "32",
    "target-c-int-width": "32",
    "arch": "x86",
    "os": "none",
    "disable-redzone": true,
    "features": "-mmx,-sse,+soft-float",
    "executables": false
}

安装 xargo

安装命令:cargo install xargo

编译命令

RUST_TARGET_PATH=$(pwd) xargo build --target=myos

自动编译脚本

#! /usr/bin/bash

RUST_TARGET_PATH=$(pwd) xargo build --target myos
nasm -f elf32 -g boot.asm
nasm -f elf32 -g long_mode.asm
ld -T linker.ld -m elf_i386 boot.o long_mode.o -o \
    kernel.elf target/myos/debug/libmyos.a
qemu-system-x86_64 -kernel kernel.elf -display curses -s -S

效果

调试Rust代码

总结

在 64 位模式下,使用汇编指令调用了 Rust 编写的函数。

附录

long_mode.asm

global long_mode_start

section .text
bits 64
long_mode_start:

    ; 清空所有的段寄存器,因为当前为平坦模式,不需要段选择器
    mov ax, 0
    mov ss, ax
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax

    ; 打印 `OKAY` 到屏幕
    mov rax, 0x2f592f412f4b2f4f
    mov qword [0xb8000], rax
    hlt

boot.asm

section .multiboot_header
header_start:
    dd 0x1BADB002  ; 魔法数字,固定值
    dd 0
    dd -0x1BADB002 ; 定义的这三个数字相加需要等于0
header_end:

global start
extern long_mode_start
section .text
bits 32
start:

    ; 栈是否高地址往低地址增长
    mov esp, stack_top

    call check_cpuid
    call check_long_mode

    call set_up_page_tables
    call enable_paging

    lgdt [gdt64.pointer]

    ; 远跳指令,清空流水线,执行 64 位指令
    jmp gdt64.code:long_mode_start
    ; print `OK` to screen
    mov dword [0xb8000], 0x2f4b2f4f
    hlt

check_cpuid:
    ; 检查 CPUID 是否支持可以通过翻转 ID 位,即第 21 位。
    ; 如果在 FLAGS 标志寄存器中,我们能够翻转它,CPUID 就是可用的。

    ; 通过栈拷贝 FLAGS 寄存器的值到 EAX 寄存器
    pushfd
    pop eax

    ; 将 EAX 的值拷贝到 ECX,后面要用
    mov ecx, eax

    ; 翻转第 21 位
    xor eax, 1 << 21

    ; 把 EAX 的值拷贝回 FLAGS 寄存器
    push eax
    popfd

    ; 拷贝 FLAGS 寄存器的值回 EAX 寄存器,检查是否翻转成功,成功翻转则支持 CPUID
    pushfd
    pop eax

    ; 通过 ECX 还原 EFLAGS 中的值
    push ecx
    popfd

    ; 比较,如果两个一样,则翻转不成功,不支持CPUID;如果翻转成功,则支持CPUID
    cmp eax, ecx
    je .no_cpuid
    ret
.no_cpuid:
    mov al, "1"
    jmp error

check_long_mode:

    ; 检查是否有扩展的处理器信息可用
    mov eax, 0x80000000    ; CPUID 的隐式参数
    cpuid                  ; 获取最高支持的参数
    cmp eax, 0x80000001    ; 如果支持长模式,至少是 0x80000001
    jb .no_long_mode       ; 如果小于,则不支持长模式

    ; 使用扩展信息验证是否支持长模式
    mov eax, 0x80000001    ; 扩展处理器参数信息
    cpuid                  ; 将各种特征标记位返回到 ECX 和 EDX
    test edx, 1 << 29      ; 第 29 位是 long mode 长模式标记位,检查是否支持
    jz .no_long_mode       ; 如果为 0,表示不支持长模式
    ret
.no_long_mode:
    mov al, "2"
    jmp error

set_up_page_tables:

    ; 将 P4 的第一个地址设置成 P3 的起始地址
    mov eax, p3_table
    or eax, 0b11 ; 二进制数,表示当前页存在,并且可写
    mov [p4_table], eax

    ; 将 P3 的第一个地址设置成 P2 的起始地址
    mov eax, p2_table
    or eax, 0b11 ; 二进制数,表示当前页存在,并且可写
    mov [p3_table], eax

    ; 将 P2 设置成 2M 的巨型页
    mov ecx, 0         ; 循环的计数器
.map_p2_table:
    ; 使用 EAX 初始化 P2 的每一项,并且映射到物理地址最低的 1G 空间
    mov eax, 0x200000  ; 2MiB
    mul ecx            ; 每一项对应的物理地址 EAX * counter
    or eax, 0b10000011 ; 存在,可写,巨型页
    mov [p2_table + ecx * 8], eax ; 将地址记录到 P2 的每一项

    inc ecx            ; 计数器加 1
    cmp ecx, 512       ; 是否存满,最大 512 项
    jne .map_p2_table  ; 不相等继续下次循环

    ret

enable_paging:
    ; 将 CR3 寄存器指向 P4 的起始地址
    mov eax, p4_table
    mov cr3, eax

    ; 在 CR4 中启用物理地址扩展(Physical Address Extension),第五位
    mov eax, cr4
    or eax, 1 << 5
    mov cr4, eax

    ; 将 EFER MSR(model specific register)寄存器中的第八位设置成长模式
    mov ecx, 0xC0000080
    rdmsr
    or eax, 1 << 8
    wrmsr

    ; 将 CR0 的最高位分页开启位设置成 1
    mov eax, cr0
    or eax, 1 << 31
    mov cr0, eax

    ret

; 打印 `ERR: ` 和一个错误代码并停住。
; 错误代码在 al 寄存器中
error:
    mov dword [0xb8000], 0x4f524f45
    mov dword [0xb8004], 0x4f3a4f52
    mov dword [0xb8008], 0x4f204f20
    mov byte  [0xb800a], al
    hlt

section .rodata
gdt64:
    dq 0 ; 和之前一样,第一段为 0
.code: equ $ - gdt64 ; 需要跳转到代码段
    ; 43 表示代码段,44 同样为 1,47 表示可用,53 表示 64 位
    dq (1<<43) | (1<<44) | (1<<47) | (1<<53) ; 代码段

.pointer:
    dw $ - gdt64 - 1
    dq gdt64

section .bss
align 4096
p4_table:
    resb 4096
p3_table:
    resb 4096
p2_table:
    resb 4096
stack_bottom:
    resb 64
stack_top:

lib.rs

#![feature(lang_items)]
#![no_std]

use core::panic::PanicInfo;

#[no_mangle]
pub extern "C" fn rust_main() {
    let a = 4444;
    let name = "jiangbo";
}

#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
    loop {}
}

标签:info,汇编,0181,MiB,component,mov,nightly,64,Rust
From: https://www.cnblogs.com/jiangbo4444/p/18302424

相关文章

  • 提升漏洞挖掘效率:详解RustScan端口快速扫描工具
    在漏洞挖掘过程中,梳理目标站点的资产面是至关重要的一步。这一过程通常需要进行全量端口扫描,以发现目标站点上所有可能的开放端口。然而,传统的端口扫描工具往往需要大量时间来完成这一任务,特别是在面对大量端口时。这不仅延长了整个漏洞挖掘的时间,还可能导致关键漏洞的发现......
  • 0173-GDB 调试汇编程序
    环境Time2022-11-12WSL-Ubuntu22.04QEMU6.2.0NASM2.15.05前言说明参考:https://os.phil-opp.com/multiboot-kernel/参考:https://ncona.com/2019/12/debugging-assembly-with-gdb/目标编写一个简单的汇编程序,使用GDB进行调试。汇编程序section.textglobal......
  • leetcode简单题21 N.104 二叉树的最大深度 rust描述
     //[3,9,20,null,null,15,7]3//[1,null,2]2usestd::rc::Rc;usestd::cell::RefCell;//Definitionforabinarytreenode.#[derive(Debug,PartialEq,Eq)]pubstructTreeNode{pubval:i32,publeft:Option<Rc<RefCell<TreeNode>>......
  • Windows系统安装RustDesk Server的详细步骤和客户端设置
    Windows系统安装RustDeskServer的详细步骤在Windows系统上安装RustDeskServer涉及几个关键步骤,包括安装必要的依赖、下载RustDeskServer程序、配置并启动服务。以下是详细的步骤:1.安装Node.js和PM2RustDeskServer的某些版本可能需要Node.js环境来运行,而PM2是一个常用的Nod......
  • rust跨平台
    目前常见的跨平台方案C++很多公司的跨平台移动基础库基本都有C++的影子,如微信,腾讯会议,还有早期的Dropbox,知名的开源库如微信的Mars等。好处是一套代码多端适配,但是需要大公司对C++有强大的工具链支持,还需要花重金聘请C++研发人员,随着团队人员变动,产品维护成本也不可忽......
  • Rust中为外部类型实现外部trait
    由于孤儿规则(orphanrule)的限制,在Rust中无法直接为外部类型实现外部trait。但是我们可以通过构造一个外部类型的wrapper来间接实现这个目的。一个比较常见的使用情形是,外部类型并没有实现Displaytrait,而我们想为其实现。这里,我们以标准库中的String为例进行介绍。externcr......
  • Rust中 String、str、&str、char 的区别
    先上结论String是动态分配在堆上的可变长度字符串类型。str是字符串切片类型,通常以&str的形式出现,用于引用字符串字面量或String的一部分。&str是字符串字面量的类型,以双引号创建,通常用于传递字符串数据的引用。char是单个Unicode字符类型,以单引号创建,用于表示单个......
  • 如何在 Rust 中安全地处理 Openresty中的字符串?
    HelloWorldRust以简洁高效安全而闻名,那么我们怎么集成到C的项目中呢。尤其是字符串数据结构,该如何正确地交互。借此机会整理一下工作中遇到的难题,希望可以帮助大家走出坑。我们先回顾一下C中字符串的结构。在C语言中,字符是一个连续的内存地址空间以\0结尾。C语言的......
  • 内存管理-15-Arm64汇编
    1.Arm64汇编lsr指令LSR是ARM架构的位移动指令,用于逻辑右移操作。它将第一个操作数的位向右移动指定位数,并根据需要将符号位(在有符号数操作中)扩展到空出来的位。语法:LSR{条件}{S}移位量,寄存器条件是可选的,指定为如EQ、NE等,用来指明只有在特定条件下才能执行指令。S是可......
  • 详解 | 什么是GeoTrust
    GeoTrust是一家全球知名的数字证书颁发机构(CertificateAuthority,简称CA),专注于提供SSL/TLS证书和其他相关的网络安全产品。1、历史背景:GeoTrust成立于2001年,最初作为一个独立的公司运营。2006年,GeoTrust被VeriSign收购。后来,在2010年,VeriSign的SSL业务又被Symantec收购。而现......