- VisualStudio2022
- pprof-Hướng dẫn sử dụng nó trong bản mạng trực tiếp
- Triển khai C# các loại hộp chọn nhiều màu lựa chọn thả xuống, cây lựa chọn nhiều màu lựa chọn thả xuống và các nút tối đa
- [Ghi chú học tập] Cơ sở dữ liệu cấu trúc: cat tree
Bài luận này được viết bởi một người rất mới. Nếu bạn có bất kỳ câu hỏi nào, xin vui lòng hỏi họ kịp thời.
Bạn có thể liên hệ: 1160712160@qq.com.
GitHhub: https://github.com/WindDevil (Hiện tại không có gì.
Trên thực tế, sau khi hiểu cơ chế cấp đặc quyền, nếu muốn thiết kế một ứng dụng, bạn cần đảm bảo rằng nó đáp ứng các yêu cầu của chế độ U và không truy cập các chức năng ở chế độ S. Sau đó, những điểm chính khi triển khai nó là.
Trong quá trình thực hiện cụ thể, việc thiết kế cũng phải được thực hiện theo các điểm chính được đưa ra trong phương pháp thiết kế.
linker.ld
File, thiết lập người dùng khó khănrom
địa chỉ ởgọi lại
giao diệnỨng dụng được biên dịch riêng để tạo tệp ELF và cắt nó thành tệp .bin. Để gọi nó, bạn chỉ cần liên kết nó với kernel trước rồi kernel sẽ tải nó vào bộ nhớ vào thời điểm thích hợp. để thực hiện nó trong phần giới thiệu của phần này
xin chào thế giới
: In một dòng lên màn hình Xin chào thế giới từ chương trình chế độ người dùng!
cửa hàng_lỗi
: Truy cập vào một địa chỉ vật lý bất hợp pháp để kiểm tra xem hệ thống xử lý hàng loạt có bị ảnh hưởng bởi lỗi này hay không.quyền lực
: Liên tục chuyển đổi cấp độ đặc quyền giữa các thao tác tính toán và thao tác in chuỗiĐảm bảo rằng vị trí hiện tại là không gian làm việc.
cd -/không gian làm việc
Sử dụng hàng hóa để tạo dự án và tạo thư mục người dùng trong thư mục dự án để lưu trữ mã và giao diện chế độ người dùng.
hàng hóa mới ./user
Đã có user/src trong tệp dự án để lưu thư viện người dùng. Tiếp theo, tạo user/src/bin để lưu ứng dụng.
người dùng mkdir/src/bin
Tạo tệp liên kết linker.ld trong user/src.
liên kết liên kết.ld
Vì địa chỉ mục nhập của lớp người dùng ứng dụng là 0x80400000 nên linker.ld được cung cấp trong Chương 1 cần được sửa đổi và BASE_ADDRESS được đặt thành 0x80400000.
OUTPUT_ARCH(riscv) ENTRY(_start) BASE_ADDRESS = 0x80400000; SECTIONS { . = BASE_ADDRESS; skernel = .; stext = .; (4K); etext = .; .rodata : { *(.rodata .rodata.*) *(.srodata .srodata.*) } = ALIGN(4K); erodata = .; sdata = .; ) *(.sdata .sdata.*) } = ALIGN(4K); edata = .bss : { *(.bss.stack) sbss = .; *(.bss .bss.*) *(.sbss .sbss.*) } . = ALIGN(4K); ebss = .; *(.eh_frame) } }
Bố cục bộ nhớ được thể hiện bằng tệp liên kết này như trong hình. Hãy chú ý đến vị trí của địa chỉ thấp và địa chỉ cao trong hình.
.rodata
Và .data
Hai phần. Cái trước lưu trữ dữ liệu toàn cầu chỉ đọc, thường là một số hằng số hoặc chuỗi không đổi, v.v. trong khi cái sau lưu trữ dữ liệu toàn cầu có thể sửa đổi..bss
Lưu dữ liệu chung chưa được khởi tạo trong chương trình, dữ liệu này thường được khởi tạo bằng 0 bởi trình tải của chương trình, nghĩa là xóa vùng này theo từng byte;Nhớ lại hướng dẫn mà chúng tôi đã sử dụng để flash tệp nhị phân vào QEMU, chúng tôi thực sự đã đặt kernel đã biên dịch ở 0x80200000, đây là phần .text.
qemu-system-riscv64 \ -machine virt \ -nographic \ -bios ../bootloader/rustsbi-qemu.bin \ -device Loader,file=target/riscv64gc-unknown-none-elf/release/os.bin,addr= 0x80200000
Đặt .text.entry trong đó _start nằm ở đầu toàn bộ chương trình. Nghĩa là, hệ thống hàng loạt đã nhập điểm vào của thư viện người dùng miễn là nó nhảy tới 0x80400000 sau khi tải và sẽ chuyển đến ứng dụng sau khi khởi tạo Logic chính...
Ở đây lưu ý rằng ENTRY(_start) là lối vào chương trình cài đặt. Nhìn lại nội dung của entry.asm trong Chương 1, .section .text.entry được đặt ở đây và Global_asm!(include_str!("entry. asm" )), trích dẫn mã này
# os/src/entry.asm .section .text.entry .globl _start _start: la sp, boot_stack_top gọi Rust_main .section .bss.stack .globl boot_stack_low_bound boot_stack_low_bound: .space 4096 * 16 .globl boot_stack_top boot_stack_top:
Cung cấp địa chỉ bắt đầu và kết thúc của phần .bss của tệp thực thi được tạo cuối cùng để hỗ trợ việc sử dụng hàm clear_bss.
Quan sát ~/App/rCore-Tutorial-v3/user/src/linker.ld
OUTPUT_ARCH(riscv) ENTRY(_start) BASE_ADDRESS = 0x80400000; SECTIONS { . = BASE_ADDRESS; .text : { *(.text.entry) *(.text .text.*) } .rodata : { *(.rodata .rodata. *) *(.srodata .srodata.*) } .data : { *(.data .data.*) *(.sdata .sdata.*) } .bss : { start_bss = .; *(.bss .bss.*) *(.sbss .sbss.*) end_bss = .; /DISCARD/ : { *(.eh_frame) *(.debug*) } }
Bạn có thể thấy rằng so với file link.ld mà chúng ta xây dựng theo file thì có ít mô tả về xxx(label) = .; và offset của = ALIGN(4K); hơn.
xxx(label) = .; được sử dụng để xác định ký hiệu xxx và đặt vị trí con trỏ hiện tại cho anh ta.
. = ALIGN(4K) được sử dụng để kiểm tra xem vị trí liên kết hiện tại có được căn chỉnh theo ranh giới 4K hay không. Nếu vị trí liên kết hiện tại không phải là bội số của ranh giới 4K, trình liên kết sẽ lấp đầy đủ byte cho đến ranh giới 4K tiếp theo.
Do đó, chúng ta có thể biết rằng trong linker.ld gốc, một số nhãn cần được đặt để chúng ta có thể lấy các con trỏ này thông qua extern C để biết kích thước của từng phần sau khi biên dịch. Và mỗi khi một phần được đặt, nó cần. được kiểm tra để phù hợp với ranh giới 4K ..
OUTPUT_ARCH(riscv)
: Xác định rằng kiến trúc đầu ra mục tiêu là RISC-V.NHẬP(_bắt đầu)
: Chỉ định điểm vào của chương trình là_bắt đầu
chức năng. Đây là nơi thực hiện chương trình bắt đầu.BASE_ADDRESS = 0x80200000;
: Đặt địa chỉ cơ sở của chương trình thành 0x80200000, đây là địa chỉ bắt đầu của chương trình được tải vào bộ nhớ.PHẦN
: Bắt đầu xác định bố cục của phân đoạn bộ nhớ.. = CƠ SỞ_ĐỊA CHỈ;
: Đặt địa chỉ hiện tại làm địa chỉ cơ sở.da = .;
: Ghi lại địa chỉ bắt đầu của phân đoạn kernel.văn bản = .;
: Ghi địa chỉ bắt đầu của đoạn văn bản (đoạn mã)..chữ
: Xác định một đoạn văn bản, chứa mã thực thi.*(.text.entry)
Và*(.text .text.*)
có nghĩa là tất cả.chữ
Và.chữ.*
Nội dung phần được liên kết ở đây.. = CĂN HỘ(4K);
: Căn chỉnh địa chỉ hiện tại theo ranh giới 4K (4096 byte).etext = .;
: Ghi địa chỉ cuối của đoạn văn bản.srodata = .;
: Ghi lại địa chỉ bắt đầu của phân đoạn dữ liệu chỉ đọc..rodata
: Xác định phân đoạn dữ liệu chỉ đọc, bao gồm các hằng số và dữ liệu chỉ đọc.*(.rodata .rodata.*)
Và*(.srodata .srodata.*)
có nghĩa là tất cả.rodata
Và.srodata
Nội dung phần được liên kết ở đây.erodata = .;
: Ghi lại địa chỉ cuối của phân đoạn dữ liệu chỉ đọc.sdata = .;
: Ghi lại địa chỉ bắt đầu của đoạn dữ liệu khởi tạo..data
: Xác định phân đoạn dữ liệu khởi tạo, bao gồm các biến toàn cục được khởi tạo.*(.data .data.*)
Và*(.sdata .sdata.*)
có nghĩa là tất cả.data
Và.sdata
Nội dung phần được liên kết ở đây.edata = .;
: Ghi lại địa chỉ cuối của đoạn dữ liệu khởi tạo..bss
: Xác định phân đoạn dữ liệu chưa được khởi tạo (phân đoạn BSS), bao gồm các biến toàn cục chưa được khởi tạo.*(.bss.stack)
Và*(.bss .bss.*)
cũng như*(.sbss .sbss.*)
có nghĩa là tất cả.bss
,.sbss
Và.bss.stack
Nội dung phần được liên kết ở đây.sss = .;
Ghi lại địa chỉ bắt đầu của phân đoạn BSS.ebss = .;
: Ghi lại địa chỉ cuối của đoạn dữ liệu chưa được khởi tạo.hạt nhân = .;
: Ghi lại địa chỉ cuối của toàn bộ phân đoạn kernel./BỎ BỎ/
: Xác định phần loại bỏ để loại trừ các phần không cần thiết, ở đây quy định là không bao gồm.eh_frame
phần này, thông thường phần này chứa thông tin khung xử lý ngoại lệ.Tạo mô-đun lib.rs
chạm vào lib.rs
Giống như main.rs của os, khi tạo mục nhập hàm, hãy sử dụng #[no_mangle] để đảm bảo tên hàm không được tối ưu hóa và sử dụng macro mới #[link_section = ".text.entry"] để tạo _start mã này. mã hợp ngữ đã biên dịch được đặt trong một tệp có tên .text.entry Trong đoạn mã, thuận tiện cho chúng ta điều chỉnh vị trí của nó trong quá trình liên kết tiếp theo để nó có thể đóng vai trò là lối vào thư viện người dùng. Ở đây cần lưu ý rằng chúng ta vẫn chỉ có thể sử dụng thư viện lõi nên chúng ta phải sử dụng. #![no_std] macro
#![no_std] #[no_mangle] #[link_section = ".text.entry"] pub extern "C" fn _start() -> ! { clear_bss(); sys_exit!"); }
Tương ứng với Chương 1, bạn cũng cần xóa phần .bss và sử dụng macro hoảng loạn!
#![feature(panic_info_message)] fn clear_bss() { extern "C" { fn start_bss(); fn end_bss(); } (start_bss as usize..end_bss as usize).for_each(|addr| không an toàn { (addr as *mut u8).write_volatile(0); } }
Và dùng giao diện exit để gọi hàm main. Giao diện exit ở đây chỉ có thể thực hiện được thông qua ecall sau này đối với hàm main nếu có ký hiệu main trong thư mục bin thì chương trình có thể liên kết bình thường, nhưng khi đó chúng ta không thể liên kết được. tìm chính, chúng tôi cũng cần phải có một Đảm bảo, điều này liên quan đến các liên kết yếu. Nếu không tìm thấy chính, hãy liên kết đến chính.
#![feature(linkage)] #[linkage = "weak"] #[no_mangle] fn main() -> i32 { hoảng loạn!("Không thể tìm thấy main!" }
Tạo mô-đun syscall. Tệp này được tạo trong tệp người dùng/src.
touchsyscall.rs
Chúng tôi sử dụng mã hợp ngữ nhúng của Rust để gọi ecall nhằm bắt đầu các cuộc gọi hệ thống ở chế độ người dùng.
Khi một tiến trình thực thi lệnh ecall, bộ xử lý sẽ kích hoạt một ngoại lệ, khiến điều khiển chuyển sang trình xử lý ngoại lệ kernel đặt trước. Tại thời điểm này, kernel có thể kiểm tra ngữ cảnh đã kích hoạt ecall và cung cấp các dịch vụ phù hợp dựa trên các tham số được truyền vào, chẳng hạn như mở tệp, tạo tiến trình, phân bổ bộ nhớ, v.v.
Bản thân lệnh ecall không mang bất kỳ tham số nào, nhưng nó có thể truy cập các giá trị trong các thanh ghi chung và chuyển chúng vào kernel dưới dạng tham số. Thông thường, các thanh ghi sau được sử dụng để truyền tham số:
x10
(a0): tham số đầu tiênx11
(a1): tham số thứ haix12
(a2): Tham số thứ bax13
(a3): Tham số thứ tưx14
(a4): Tham số thứ nămx15
(a5): Tham số thứ sáux16
(a6): Tham số thứ bảyx17
(a7): Tham số thứ tám, cũng đóng vai trò là số cuộc gọi hệ thốngSau đó, bạn có thể tạo giao diện trong tệp syscall.rs
// user/src/syscall.rs use core::arch::asm; fn syscall(id: usize, args: [usize; 3]) -> isize { let mut ret: isize không an toàn { asm!( " ecall ", inlateout("x10") args[0] => ret, in("x11") args[1], in("x12") args[2], in("x17") id } ret }
Format macro asm!
gọi lại
hướng dẫn, nhưng nó có thể hỗ trợ chèn nhiều hướng dẫn cùng một lúc.trong ("x11") tranh luận [1]
Có nghĩa là các thông số sẽ được nhập lập luận[1]
kill with gọi lại
ghi đầu vào x11
Instant setting a1
, trình biên dịch sẽ tự động chèn các lệnh liên quan và chắc chắn rằng gọi lại
đăng ký trước khi thực hiện lệnh này a1
Giá trị của lập luận[1]
như nhau.lập luận[2]
Và NHẬN DẠNG
Liên kết với các thanh ghi tương ứng a2
Và a7
ở giữa.a0
Thanh ghi, đóng vai trò vừa đầu vào vừa là đầu ra, vì vậy chúng ta sẽ TRONG
Change thành công vào sau
và trong phần biến ở dòng cuối cùng, hãy sử dụng {in_var} => {out_var}
format, ở đâu {in_var}
Và {out_var}
Giao diện cho các biến đầu vào và đầu ra biến trong bối cảnh tương ứng.Trong chương trình này, hai lệnh gọi hệ thống sau đây được thống nhất giữa chương trình ứng dụng và hệ thống xử lý hàng loạt theo API cấu hình:
/// Chức năng: Ghi dữ liệu vào bộ nhớ đệm vào tệp /// Tham số: `fd` đại diện cho tệp mô tả của file. được ghi; /// `buf` đại diện cho địa chỉ bắt đầu của bộ đệm trong bộ nhớ /// `len` đại diện cho chiều dài; /// ID tòa nhà: 64 fn sys_write(fd: usize, buf: *const u8, len: usize) -> isize; /// Chức năng: Thoát khỏi ứng dụng và thông báo cho hệ thống xử lý hàng hóa về giá trị trả về /// Tham số: `exit_code` biểu tượng /// ID tòa nhà: 93 fn sys_exit(exit_code: useize) -> !;
Tương tự như vậy, chúng tôi có thể sử dụng syscall để phát triển API này
// user/src/syscall.rs const SYSCALL_WRITE: usize = 64; const SYSCALL_EXIT: usize = 93; pub fn sys_write(fd: usize, buffer: &[u8]) -> isize { syscall(SYSCALL_WRITE, [fd, buffer .as_ptr() as usize, buffer.len()]) } pub fn sys_exit(xstate: i32) -> isize { syscall(SYSCALL_EXIT, [xstate as usize, 0, 0]) }
Lưu ý rằng sys_write sử dụng lát lát &[u8] để mô tả bộ đệm, đó là một con trỏ béo (Con trỏ béo), chứa cả địa chỉ chỉ bắt đầu bộ đệm và độ dài của bộ đệm. ứng dụng và sử dụng chúng để tạo ra một tham số gọi hệ thống thực tế một cách độc lập.
Để gói gọn hơn nữa hai lệnh gọi hệ thống trên trong thư viện người dùng user_lib, để gần với giao diện lệnh gọi hệ thống thực tế trên Linux và các nền tảng khác, hãy sửa đổi tệp lib.rs và nhập vào
sử dụng syscall mod; ) }
bảng điều khiển
hiện thực hóaChúng tôi đã thay đổi Stdout::write_str trong mô-đun con bảng điều khiển thành triển khai dựa trên ghi và đặt tham số fd đến thành 1, đại diện cho đầu ra tiêu chuẩn, nghĩa là xuất ra màn hình. Chúng ta không cần phải xem xét các tình huống lựa chọn fd khác vào lúc này. Bằng cách này, macro println! của ứng dụng sẽ khả dụng thông qua lệnh gọi hệ thống.
Tạo tệp console.rs. Nội dung phù hợp với mô-đun trong Chương 1. Chỉ sửa đổi việc triển khai tính năng Ghi của Stdout.
// user/src/console.rs const STDOUT: usize = 1; impl Viết cho Stdout { fn write_str(&mut self, s: &str) -> fmt::Result { write(STDOUT, s.as_bytes()); (()) } }
Nội dung tập tin cuối cùng là
sử dụng super::write; sử dụng core::fmt::{self, Write}; const STDOUT: usize = 1; impl Viết cho Stdout { fn write_str(&mut self, s: &str) -> fmt::Result { write(STDOUT, s.as_bytes()); Ok(()) } } pub fn print(args: fmt::Arguments) { Stdout.write_fmt(args).unwrap(); } #[macro_export] macro_rules! print { ($fmt: chữ $(, $($arg: tt)+)?) => { $crate ::console::print(format_args!($fmt $(, $($arg)+)?)); #[macro_export] macro_rules! println { ($fmt: chữ $(, $($arg: tt)+)?) => { $crate::console::print(format_args!(concat!($fmt, "\ n") $(, $($arg)+)?)); } }
Bạn có thể truy cập ~/App/rCore-Tutorial-v3, sử dụng git check ch2, chuyển sang mã trong Chương 2 để xem mã nguồn của ba ứng dụng. Và bạn có thể sao chép chúng vào thư mục user/src/bin của chúng tôi. dự án.
cd ~/App/rCore-Tutorial-v3 git kiểm tra ch2 cd user/src/bin cp 00hello_world.rs ~/workspace/user/src/bin cp 01store_fault.rs ~/workspace/user/src/bin cp 02power.rs ~ /không gian làm việc/người dùng/src/bin
#![no_std] #![no_main] #[macro_use] thùng bên ngoài user_lib; #[no_mangle] fn main() -> i32 { println!("Xin chào thế giới!");
#![no_std] #![no_main] #[macro_use] extern thùng user_lib; #[no_mangle] fn main() -> i32 { println!("Trong quá trình kiểm tra store_fault, chúng tôi sẽ chèn một thao tác lưu trữ không hợp lệ...") ; println!("Kernel nên tắt ứng dụng này!"); core::ptr::null_mut::().write_volatile(0);
#![no_std] #![no_main] #[macro_use] thùng bên ngoài user_lib; const SIZE: usize = 10; const P: u32 = 3; const STEP: usize = 100000; const MOD: u32 = 10007; fn main() -> i32 { let mut pow = [0u32; SIZE]; đặt chỉ số thay đổi: usize = 0; pow[index] = 1; for i in 1..=STEP { let end = pow[index]; cuối cùng * P % MOD; nếu i % 10000 == 0 { println!("{}^{}={}(MOD {})", P, i, pow[index], MOD); } } println!("Kiểm tra nguồn ổn!");
Mượn trực tiếp tập lệnh trong ~/App/rCore-Tutorial-v3/user và tạo Makefile trong thư mục người dùng
MỤC TIÊU := riscv64gc-unknown-none-elf MODE := phát hành APP_DIR := src/bin TARGET_DIR := target/$(TARGET)/$(MODE) APPS := $(wildcard $(APP_DIR)/*.rs) ELFS := $(patsubst $(APP_DIR)/%.rs, $(TARGET_DIR)/%, $(APPS)) BINS := $(patsubst $(APP_DIR)/%.rs, $(TARGET_DIR)/%.bin, $(APPS)) OBJDUMP := Rust-objdump --arch-name=riscv64 OBJCOPY := Rust-objcopy --binary-architecture=riscv64 elf: @cargo build --release nhị phân: elf @$(foreach elf, $(ELFS), $(OBJCOPY) $(elf) --strip-all -O nhị phân $(patsubst $(TARGET_DIR)/%, $(TARGET_DIR)/%.bin, $(elf));) build: nhị phân
phân tích cú pháp
MỤC TIÊU
:Đặt làm kiến trúc đích riscv64gc-unknown-none-elf
, đây là sự hỗ trợ của Rust dành cho kiến trúc RISC-V.CÁCH THỨC
:Đặt thành giải phóng
, nghĩa là xây dựng bằng chế độ phát hành của Rust, chế độ này thường tạo ra các tệp nhị phân được tối ưu hóa.APP_DIR
: Thư mục mã nguồn, đây là src/bin
, thường lưu trữ các tệp nguồn chương trình thực thi Rust.TARGET_DIR
: Xây dựng thư mục đầu ra, được xây dựng ở đây theo kiến trúc đích và chế độ xây dựng.ỨNG DỤNG
:sử dụng ký tự đại diện
danh sách chức năng APP_DIR
Tất cả trong thư mục .rs
Tệp, tức là tệp nguồn Rust.ELFS
:vượt qua patsubst
chuyển đổi chức năng ỨNG DỤNG
List, chuyển đổi từng tệp nguồn sang đường dẫn tệp đích tương ứng ở định dạng ELF.thùng
: Sử dụng tương tự patsubst
chức năng, ý chí ỨNG DỤNG
Danh sách được chuyển đổi thành .bin
Định dạng đường dẫn tệp nhị phân.ĐỐI TƯỢNG
:sử dụng gỉ-objdump
công cụ, chỉ định lược đồ là riscv64
, được sử dụng để xem cấu trúc bên trong của tệp mục tiêu.ĐỐI TƯỢNG
:sử dụng vật thể rỉ sét
Tool, cũng chỉ định kiến trúc như riscv64
, được sử dụng để chuyển đổi từ định dạng ELF sang các định dạng khác (chẳng hạn như nhị phân).yêu tinh
: Mục tiêu này gọi xây dựng hàng hóa --phát hành
lệnh, sử dụng Cargo (trình quản lý gói và công cụ xây dựng của Rust) để xây dựng dự án và tạo tệp thực thi ở định dạng ELF.nhị phân
: Mục tiêu này phụ thuộc vào yêu tinh
mục tiêu, sau đó đi qua ELFS
liệt kê, sử dụng ĐỐI TƯỢNG
Chuyển đổi từng tệp ELF thành tệp nhị phân có biểu tượng.xây dựng
: Mục tiêu này phụ thuộc vào nhị phân
Mục tiêu, có nghĩa là mục tiêu cuối cùng của quá trình xây dựng là tạo ra tệp nhị phân.Nhập thư mục người dùng và thực thi lệnh xây dựng tự động của ứng dụng make build.
Báo cáo lỗi
error[E0583]: không tìm thấy tệp cho mô-đun `lang_items` --> src/lib.rs:7:1 | mod lang_items; để tạo module `lang_items`, tạo file "src/lang_items.rs" hoặc "src/lang_items/mod.rs" = lưu ý: nếu có `mod lang_items` ở nơi khác trong thùng, hãy nhập nó bằng `sử dụng thùng::...` thay vì lỗi: thanh ghi không hợp lệ `x10`: thanh ghi không xác định --> src/syscall.rs:11:13 inlateout("x10 | ") args[0] => ret, | ^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^^ lỗi: đăng ký không hợp lệ `x11`: đăng ký không xác định --> src/syscall.rs:12:13 | in("x11") args[1], | ^^^^^^^^^^ lỗi: thanh ghi không hợp lệ `x12`: thanh ghi không xác định --> src/syscall.rs:13:13 | in("x12") args[2], | ^^ ^^^ ^^ ^^ ^^ ^^ ^^ ^^ lỗi: đăng ký không hợp lệ `x17`: đăng ký không xác định --> src/syscall.rs:14:13 | in("x17") id | ^^ ^^ ^^ ^^ ^^ ^^ Để biết thêm thông tin về lỗi này, hãy thử `rustc --explain E0583`. tạo: *** [Makefile:13: elf] Lỗi 101
Bạn có thể thấy mô-đun lang_items không tồn tại và tất cả các thanh ghi được đánh dấu là thanh ghi không hợp lệ.
Chúng tôi cũng kiểm tra việc triển khai trong ~/App/rCore-Tutorial-v3/user/src
#[panic_handler] fn Panic_info: &core::panic::PanicInfo) -> ! { let err = Panic_info.message().unwrap(); if let Some(location) = Panic_info.location() { println!( "Hoảng loạn tại {}:{}, {}", location.file(), location.line(), err } else { println!("Hoảng loạn: {}", err); } vòng lặp {} }
Bạn có thể thấy rằng giống như Chương 1, một hàm được chú thích bằng #[panic_handler] đã được triển khai, nhưng lệnh tắt do sbi cung cấp và macro error! do log cung cấp không được sử dụng. sử dụng macro hoảng loạn! Để triển khai một hàm có tên là hoảng loạn, chỉ cần triển khai hàm với chú thích này.
Sao chép tập tin này và sử dụng nó
cp lang_items.rs ~/workspace/user/src/
Biên dịch lại
cd ~/workspace/người dùng tạo bản dựng
Nhận thấy lỗi vẫn được báo cáo
lỗi: đăng ký không hợp lệ `x10`: đăng ký không xác định --> src/syscall.rs:11:13 | inlateout("x10") args[0] => ret, | ^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^ lỗi: thanh ghi không hợp lệ `x11`: thanh ghi không xác định --> src/syscall.rs:12:13 | 12 | in("x11") args[1], | ^^ ^^^ ^^ ^^ ^^ ^^ ^^ lỗi: đăng ký không hợp lệ `x12`: không xác định đăng ký --> src/syscall.rs:13:13 | 13 | in("x12") args[2], | ^^ ^^^ ^^ ^^ ^^ ^^ ^^ ^^ lỗi: đăng ký không hợp lệ `x17`: đăng ký không xác định --> src/syscall.rs:14:13 | in("x17") id | ^^ ^^ ^^ ^^ ^^ ^^ lỗi: không thể biên dịch `user` (lib) do 4 lỗi trước đó tạo ra: *** [Makefile:13: elf] Lỗi 101
Có thể có vấn đề với các tệp phụ thuộc. Chúng tôi nhận thấy rằng Rust-sbi dường như không phụ thuộc vào nó. Chúng tôi đã kiểm tra ~/App/rCore-Tutorial-v3/user/Cargo.toml và nhận thấy rằng đó không phải là vấn đề. sbi không có phần phụ thuộc, nhưng có phần phụ thuộc risc-v.
[phụ thuộc] riscv = { git = "https://github.com/rcore-os/riscv", tính năng = ["inline-asm"] }
Tại thời điểm này, hãy chạy lại bản dựng dưới quyền người dùng và vẫn gặp lỗi.
lỗi: đăng ký không hợp lệ `x10`: đăng ký không xác định --> src/syscall.rs:11:13 | inlateout("x10") args[0] => ret, | ^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^ lỗi: thanh ghi không hợp lệ `x11`: thanh ghi không xác định --> src/syscall.rs:12:13 | 12 | in("x11") args[1], | ^^ ^^^ ^^ ^^ ^^ ^^ ^^ lỗi: đăng ký không hợp lệ `x12`: không xác định đăng ký --> src/syscall.rs:13:13 | 13 | in("x12") args[2], | ^^ ^^^ ^^ ^^ ^^ ^^ ^^ ^^ lỗi: đăng ký không hợp lệ `x17`: đăng ký không xác định --> src/syscall.rs:14:13 | in("x17") id | ^^ ^^ ^^ ^^ ^^ ^^ lỗi: không thể biên dịch `user` (lib) do 4 lỗi trước đó tạo ra: *** [Makefile:13: elf] Lỗi 101
Lúc này, xét nội dung của file Makefile và sử dụng hàng hóa để xây dựng, có vấn đề gì với cài đặt hàng hóa không? So sánh ~/App/rCore-Tutorial-v3/user, bạn có thể thấy thư mục .cargo tồn tại trong đó. nó. Trước đây chúng tôi cũng sử dụng thư mục này.
Trong môi trường lập trình Rust, .cargo/config.toml và Cargo.toml đều là các tệp cấu hình, nhưng mỗi tệp chịu trách nhiệm thực hiện các tác vụ khác nhau.
.cargo/config.toml Tệp này được sử dụng để định cấu hình hoạt động của chuỗi công cụ Rust (bao gồm cả Cargo). Nó cho phép người dùng đặt một số tùy chọn chung, chẳng hạn như kiến trúc mục tiêu biên dịch, hành vi mặc định của trình biên dịch (chẳng hạn như có bật thông tin gỡ lỗi, mức tối ưu hóa, v.v.), đường dẫn đến kho riêng, biến môi trường thời gian biên dịch, và nhiều tùy chọn cấu hình nâng cao khác, chẳng hạn như nguồn hình ảnh, lựa chọn chuỗi công cụ, v.v.
Tệp .cargo/config.toml thường nằm trong thư mục .cargo trong thư mục chính của người dùng, nhưng cũng có thể tạo một tệp có cùng tên trong thư mục gốc của dự án để ghi đè cấu hình mặc định sao cho cấu hình sẽ có hiệu lực cho một dự án cụ thể.
Tệp Cargo.toml là tệp kê khai dự án. Nó chứa siêu dữ liệu quan trọng về dự án Rust, bao gồm tên dự án, phiên bản, tác giả, giấy phép và các siêu thông tin khác của dự án và các yêu cầu về phiên bản của chúng; các thành viên của một dự án, tức là các dự án khác thuộc cùng một không gian làm việc; biên dịch các tính năng dành riêng cho cấu hình có thể bật hoặc tắt chức năng bổ sung của các tệp nhị phân, thư viện hoặc mô-đun thử nghiệm đích;
Tóm lại, Cargo.toml mô tả cấu trúc và yêu cầu của dự án, trong khi .cargo/config.toml kiểm soát cách Cargo xử lý các chi tiết khác nhau trong quá trình xây dựng dự án. Mọi dự án Rust đều có tệp Cargo.toml, trong khi .cargo/config.toml là tùy chọn và có thể được đặt trên toàn cầu hoặc ghi đè cục bộ trong thư mục dự án.
Sau đó, chúng tôi xem nội dung của tệp này và thấy rằng trình biên dịch và tệp liên kết đã được chỉ định
[build] target = "riscv64gc-unknown-none-elf" [target.riscv64gc-unknown-none-elf] Rustflags = [ "-Clink-args=-Tsrc/linker.ld", "-Cforce-frame-pointers= Đúng" ]
Chúng tôi tạo /user/.cargo/config.toml trong /user
chạm vào /user/.cargo/config.toml
Copy nội dung trên vào rồi chạy lại make build
error[E0463]: không thể tìm thấy thùng cho `user_lib` --> src/bin/01store_fault.rs:5:1 | 5 | thùng bên ngoài user_lib; ^^ ^^ ^^ ^^ không thể tìm thấy thùng lỗi[E0463]: không thể tìm thấy thùng cho `user_lib` --> src/bin/00hello_world.rs:5:1 | 5 | user_lib thùng bên ngoài; ^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^ không thể tìm thấy lỗi thùng: không thể tìm thấy macro `println` trong phạm vi này --> src/bin/01store_fault.rs:10:5 | 10 | ^^^^ ^^ | trợ giúp: xem xét việc nhập macro này | 4 + sử dụng user::println; không thể tìm thấy macro `println` trong phạm vi này --> src/bin/01store_fault.rs:9:5 | 9 | println!("Trong phần thử nghiệm store_fault, chúng tôi sẽ chèn một thao tác lưu trữ không hợp lệ..." | ^^^^^ | user::println; | lỗi: yêu cầu chức năng `#[panic_handler]`, nhưng không tìm thấy lỗi: không thể tìm thấy macro `println` trong phạm vi này --> src/bin/00hello_world.rs:9:5 | ("Xin chào thế giới!"); | ^^^^^ | trợ giúp: hãy xem xét việc nhập macro này | 4 + sử dụng user::println; `rustc --explain E0463` lỗi: không thể biên dịch `user` (bin "01store_fault") do 4 lỗi trước đó cảnh báo: quá trình xây dựng không thành công, đang chờ các công việc khác hoàn thành... lỗi: không thể biên dịch `user` ( bin "00hello_world") do 3 lỗi trước đó tạo ra: *** [Makefile:13: elf] Lỗi 101
Lỗi vẫn được báo cáo và người ta thấy rằng gói user_lib được yêu cầu không tồn tại và println là do thiếu sự phụ thuộc này. Hãy kiểm tra tài liệu chính thức tại đây: Thư viện bên ngoài này thực sự là lib.rs trong thư mục người dùng và một số thư mục khác. mô-đun con mà nó tham chiếu. Về lý do tại sao thư viện bên ngoài này được gọi là user_lib thay vì user, tên thư mục chứa lib.rs là do chúng ta đặt tên thư viện trong user/Cargo.toml: name="user_lib". Là thư viện người dùng mà chương trình nguồn trong thư mục bin phụ thuộc vào, nó tương đương với thư viện tiêu chuẩn được cung cấp bởi các ngôn ngữ lập trình khác.
Sau đó, chúng tôi sửa đổi tên trong user/Cargo.toml, name = "user_lib", rồi tạo bản dựng, không có lỗi nào được báo cáo.
Có thể tìm thấy trong ~/workspace/user/target/riscv64gc-unknown-none-elf/release,00hello_world,01store_fault,02power..
Sử dụng qemu-riscv64, bạn có thể thực thi trực tiếp các ứng dụng bằng trình mô phỏng chế độ người dùng mà không cần hệ điều hành.
Chuyển đến thư mục ~/workspace/user/target/riscv64gc-unknown-none-elf/release và thử thực thi qemu-riscv64 ./00hello_world..
Tìm thấy một lỗi
Không tìm thấy lệnh 'qemu-riscv64', nhưng có thể được cài đặt bằng: sudo apt install qemu-user
thử cài đặt
sudo apt cài đặt qemu-người dùng
Sử dụng sau khi cài đặt thành công
qemu-riscv64 ./00hello_world - Xin chào thế giới! qemu-riscv64 ./01store_fault - Vào thử nghiệm store_fault, chúng tôi sẽ chèn một thao tác lưu trữ không hợp lệ... - Kernel sẽ tắt ứng dụng này! - Lỗi phân đoạn (core dumped) qemu-riscv64 . /02power - 3^10000=5079(MOD 10007) - 3^20000=8202(MOD 10007) - 3^30000=8824(MOD 10007) - 3^40000=5750(MOD 10007) - 3^50000=3824(MOD 10007) - 3^60000=8516(MOD 10007) - 3^70000=2510(MOD 10007) - 3^80000=9379(MOD 10007) - 3^90000=2621(MOD 10007) - 3^100000=2749(MOD 10007) - Kiểm tra nguồn OK!
Có thể thấy rằng sau khi thực thi 00hello_world, chế độ người dùng có thể thực thi bình thường. Sau khi thực thi 01store_fault, đã xảy ra lỗi do cố gắng ghi 0 vào con trỏ null.
Sau khi thực thi 02power, các phép tính ở chế độ người dùng và println! được chạy và println! thực sự gọi write và syscall. Có thể thấy rằng việc chuyển đổi lặp lại giữa chế độ người dùng và chế độ kernel cũng khả thi.
Theo mô tả trong tài liệu chính thức, có hai ứng dụng khác có thể được biên dịch và chạy: 03priv_inst và 04priv_csr, lần lượt xác minh hai tình huống "lý do tại sao các ứng dụng ở chế độ người dùng trực tiếp kích hoạt ngoại lệ từ chế độ người dùng sang chế độ kernel"
sret
Lệnh (biểu thị việc quay lại từ chế độ S sang chế độ U)trạng thái
Chờ đợiLúc này cũng sao chép mã nguồn của 2 ứng dụng này.
cp 03priv_inst.rs ~/workspace/user/src/bin/ cp 04priv_csr.rs ~/workspace/user/src/bin/
Biên dịch tạo và chạy
cd ~/workspace/user make build cd ~/workspace/user/target/riscv64gc-unknown-none-elf/release qemu-riscv64 03priv_inst - Cố gắng thực thi lệnh đặc quyền ở Chế độ U - Kernel nên tắt ứng dụng này! - Hướng dẫn bất hợp pháp ( core dumped) qemu-riscv64 04priv_csr - Cố gắng truy cập CSR đặc quyền ở Chế độ U - Kernel sẽ bị hủy ứng dụng này! - Hướng dẫn bất hợp pháp (kết xuất lõi)
Cuối cùng, bài viết này về việc triển khai các ứng dụng [rCore Study Notes 016] kết thúc tại đây. Nếu bạn muốn biết thêm về việc triển khai các ứng dụng [rCore Study Notes 016], vui lòng tìm kiếm các bài viết về CFSDN hoặc tiếp tục duyệt các bài viết liên quan. Tôi hy vọng tất cả các bạn sẽ ủng hộ tôi. blog trong tương lai! .
đóng cửa. Câu hỏi này dựa trên ý kiến. Hiện tại nó không chấp nhận câu trả lời. Bạn muốn cải thiện câu hỏi này? Cập nhật câu hỏi để việc chỉnh sửa bài đăng này có thể trả lời nó bằng các sự kiện và trích dẫn. Đã đóng 9 năm trước. Cải thiện
Giới thiệu: MiniApis là gì? Các tính năng và ưu điểm của MiniApis Yêu cầu hệ thống xây dựng môi trường kịch bản ứng dụng MiniApis Cài đặt MiniApis Định cấu hình môi trường phát triển Các khái niệm cơ bản Tổng quan về kiến trúc MiniApis
Tôi đang học javascript từ cuốn sách "Kinh thánh JavaScript" nhưng tôi gặp một số khó khăn. Tôi đang cố gắng hiểu mã này: function checkIt(evt) { evt = (evt) e?
gói com.fastone.www.javademo.stringintern; /** * * String.intern() là một phương thức gốc, * Chức năng của nó là: nếu chuỗi
Bạn muốn giới thiệu những tài nguyên nào để học AppleScript. Tôi sử dụng C/C++ truyền thống với nền Objective-C. Tôi cũng đang tìm kiếm các mẹo về cách phát triển tốt hơn và lấy tài liệu nhanh hơn từ trình chỉnh sửa tập lệnh. Lời nhắc ví dụ là "Tìm
đóng cửa. Câu hỏi này không đáp ứng các nguyên tắc của Stack Overflow. Hiện tại nó không chấp nhận câu trả lời. Bạn muốn cải thiện vấn đề này? Câu hỏi được cập nhật để làm cho câu hỏi trở thành chủ đề cho Stack Overflow. Đóng cửa 4 năm trước. Cải thiện điều này
đóng cửa. Câu hỏi này không đáp ứng các nguyên tắc của Stack Overflow. Hiện tại nó không chấp nhận câu trả lời. Bạn muốn cải thiện vấn đề này? Câu hỏi được cập nhật để làm cho câu hỏi trở thành chủ đề cho Stack Overflow. Đóng cửa 7 năm trước Cải thiện điều này
đóng cửa. Câu hỏi này không tuân thủ nguyên tắc Stack Overflow. Hiện tại nó không chấp nhận câu trả lời. Bạn muốn cải thiện vấn đề này? Đã cập nhật câu hỏi sao cho đúng chủ đề trên Stack Overflow. Đóng cửa 6 năm trước Cải thiện điều này
Tôi là Ali đến từ Sénégal. Tôi 60 tuổi rồi (có lẽ đó là vấn đề thực sự của tôi - cười!!!). Tôi đang học Flutter và Dart. Hôm nay tôi muốn sử dụng danh sách một mô hình dữ liệu nhất định (tên của nó là Mortalite, xem mã bên dưới). tôi cố gắng
đóng cửa. Câu hỏi này lạc đề. Hiện tại nó không chấp nhận câu trả lời. Bạn muốn cải thiện câu hỏi này? Đã cập nhật câu hỏi để nó phù hợp với chủ đề về Stack Overflow. Đóng cửa 9 năm trước Cải thiện hàng đợi này
Nguồn tốt nhất để học Cappuccino là gì? Tôi làm việc trong lĩnh vực phát triển web "truyền thống", nhưng tôi rất quan tâm đến khuôn khổ mới này. Xin lưu ý rằng tôi không có kiến thức về Objective-C. Câu trả lời hay nhất Như đã nêu ở trên, trang web này là một nơi tuyệt vời nhưng có một số trang khác
Tôi đang học cách sử dụng hashMap, ai đó có thể kiểm tra mã tôi đã viết này và cho tôi biết mã đó có đúng không? Ý tưởng là có một danh sách nhân viên làm việc trong công ty và tôi muốn thêm và xóa nhân viên khỏi hashMap. lớp công khai
Tôi đang cố gắng sử dụng jQuery với CoffeScript. Tôi đã làm theo hướng dẫn trong blog hướng dẫn sử dụng $-> hoặc jQuery -> thay vì .ready(). Tôi đã thử mã nhưng dường như tôi không thể hiểu mình đang mắc lỗi gì
Vẫn đang học và vẫn còn rất nhiều câu hỏi, vì vậy đây là một số câu hỏi. Tôi đang thực hiện chuyển đổi javascript -> PHP và muốn đảm bảo thực tiễn là chính xác. là $dailyparams->$calories = $calories một;
Tôi hiện đang học SQL để tạo báo cáo RFM đơn giản từ cơ sở dữ liệu Magento của chúng tôi, hiện tại tôi có thể thực hiện việc này bằng cách xuất hai truy vấn và dán chúng vào mẫu Excel, tôi muốn loại bỏ mẫu Excel. tôi nghĩ
Tôi biết tôi có thể sẽ nhận được sự chỉ trích vì câu hỏi này, nhưng vì chưa có ai hỏi nên tôi quay sang bạn. Đây có phải là chuyển đổi javascript> php chính xác không - Trước khi gặp rắc rối, tôi muốn biết liệu đây có phải là cách chính xác để giải quyết vấn đề này hay không. JavaS
Ngoài Ruby-Doc, nguồn tốt nhất để lấy một số ví dụ và hướng dẫn, đặc biệt là về Tk/Tile trong Ruby là gì? Tôi thấy mình bình thường hơn http://www.tutorialspoint.com/ruby/r
Tôi chỉ nhận được cảnh báo lần đầu tiên. Điều này có bình thường không? >>> cv=LassoCV(cv=10).fit(x,y) C:\Python27\lib\site-packages\scikit_learn-0.14.1-py
Như hiện tại, câu hỏi này không phù hợp với dạng Hỏi & Trả lời của chúng tôi. Chúng tôi mong đợi câu trả lời. sẽ được hỗ trợ bởi các sự kiện, trích dẫn hoặc chuyên môn, nhưng câu hỏi có thể gây ra tranh luận, tranh luận, bỏ bỏ phiếu hoặc thảo luận mở rộng. truy cập
Vì hiện tại, câu hỏi này không phù hợp với hình thức Hỏi & Đáp của chúng tôi.
Tôi là một lập trình viên xuất sắc, rất xuất sắc!