rCore-Tutorial-Book-v3 icon indicating copy to clipboard operation
rCore-Tutorial-Book-v3 copied to clipboard

rCore-Tutorial-Book-v3/chapter2/2application

Open utterances-bot opened this issue 4 years ago • 45 comments

实现应用程序 — rCore-Tutorial-Book-v3 0.1 文档

https://rcore-os.github.io/rCore-Tutorial-Book-v3/chapter2/2application.html

utterances-bot avatar Mar 10 '21 12:03 utterances-bot

将程序的起始物理地址调整为 0x80040000

现在代码中的地址为 0x80400000

$ qemu-riscv64 ./00hello_world
  Hello, world!
# 正确显示了字符串

现在 00hello_world.rs 中内容为

fn main() -> i32 {
    println!("Hello, world!");
    unsafe {
        llvm_asm!("sret");
    }
    0
}

已含有执行S模式特权指令的部分,执行会报错。(同时不需要特意 clone chyyuu/os_kernel_lab

duskmoon314 avatar Mar 10 '21 12:03 duskmoon314

在本章最后运行 qemu-riscv64 02power 进行用户程序测试的时候,如果用源码库里面ch2分支的代码。我运行的时候出现了奇怪的错误段错误,print 10以上的数就会出现。后来发现原因是ch2分支代码默认是用的自己的内存布局,并且把起始地址改成了0x80040000,但qemu-riscv64 是半模拟的,意味着它提供了完整的底层操作系统,所以在qemu-riscv64上测试我们的应用程序应该把 我们自己的内存布局删除掉, 就是在.cargo/config文件中注释掉内存布局相关代码

[build]
target = "riscv64gc-unknown-none-elf"

#[target.riscv64gc-unknown-none-elf]
#rustflags = [
#    "-Clink-args=-Tsrc/linker.ld",
#]

然后程序中注释掉 clean_bss相关代码,就可以运行了

不知道我理解的对不对?,还有没有其他可以兼容qemu-riscv64和qemu-system-riscv64而不改代码的方式?

顺便说一句,我没有用Makefile文件,我是直接 cargo build, 然后用的是debug里面的文件,不知道和这有没有关系?

dunmengjun avatar Jul 17 '21 03:07 dunmengjun

还有在rust 1.55中 asm! 宏现在可以用了,而且llvm_asm! 宏是已经被标记删除的状态了,不知道下面哪个版本就会直接删除了。所以之后的版本还是推荐用asm!宏

下面是asm!宏的sbi call的代码

fn sbi_call(id:usize, args: [usize; 3]) -> usize {
    let mut ret = 0;
    unsafe {
       asm!("ecall",
           inlateout("x10") args[0] => ret,
           in("x11") args[1],
           in("x12") args[2],
           in("x17") id,
           options(nostack)
       )
    }
    ret
}

system call的代码也可以改个名字直接替换,需要解释的点是

  1. asm!宏默认汇编指令是会修改内存的,所以不需要标注类似 memory 这样的clobber
  2. options(nostack) 类似 标注volatile

这样改了之后,我测试是通过的

如果我的解释有误的地方请告诉我

dunmengjun avatar Jul 17 '21 04:07 dunmengjun

let mut ret 不需要初始化

dunmengjun avatar Jul 17 '21 04:07 dunmengjun

@dunmengjun

  1. ch2上应用程序的内存布局完全不影响它在完整OS qemu-riscv64上的正常运行,因为它应该是支持页表的,所以应用程序和OS的地址不会有冲突,这一点和ch2是不同的。事实上只要syscall接口能对上就应该没问题(从ch3开始就做不到这一点了)我测试了一下,无论是cargo build还是make build出来的可执行文件qemu-riscv64都是能正常运行退出的,将参数P改成10以上也不影响。可能是Qemu版本问题?我用的是5.0.0
  2. 近期会参考你的代码将llvm_asm!换成asm!,多谢贡献!

wyfcyx avatar Jul 17 '21 04:07 wyfcyx

@wyfcyx 我这边是只要用了自己的内存布局,就是不注释那段linker的rustflag代码,cargo build, 然后运行

qemu-riscv64 02power

就会报

3^Segmentation fault

的错误 你可以看到前面3^这些字符串都打出来了,然后就是u32的数字没打出来,我测试了一下,超过10就会出现段错误😂

我的环境是 windows10 wsl2 ubuntu18.04, qemu-riscv64 5.0.0, rustc 1.55.0-nightly (2f391da2e 2021-07-14), cargo 1.55.0-nightly (3ebb5f15a 2021-07-02)

就在写这一段的时候,我又测试了一下,我这次直接clone你们代码库的代码,然后cargo build, 运行,然后是ok的😂

到这里总算知道了问题在哪儿了,你们代码库里面的rust版本是1.51, 而我全程用的是1.55, 这就是区别,你如果用rust1.55来测试你们库中的代码,应该也能重现。

不知道rust工具链从1.51 到1.55又更改了什么导致了这个问题,我会继续去看看的,如果你又什么更新,我们及时沟通

dunmengjun avatar Jul 17 '21 05:07 dunmengjun

我用rust-readobj 命令去看两个rust版本生成的02power文件发现 1.51

...
  SectionHeaderOffset: 0xBA48
  Flags [ (0x1)
    EF_RISCV_RVC (0x1)
  ]
...

1.55

...
  SectionHeaderOffset: 0xA988
  Flags [ (0x5)
    EF_RISCV_FLOAT_ABI_DOUBLE (0x4)
    EF_RISCV_RVC (0x1)
  ]
...

其他的两个版本一模一样,感觉这个EF_RISCV_FLOAT_ABI_DOUBLE flag会是原因

dunmengjun avatar Jul 17 '21 05:07 dunmengjun

@wyfcyx cargo build --release 1.55生成的文件是可以运行的😂, 而且rust-readobj也是

SectionHeaderOffset: 0x5C48
  Flags [ (0x5)
    EF_RISCV_FLOAT_ABI_DOUBLE (0x4)
    EF_RISCV_RVC (0x1)
  ]

我是不知道是啥原因了,求帮助啊

dunmengjun avatar Jul 17 '21 06:07 dunmengjun

@dunmengjun qemu-riscv64的行为着实比较玄学,目前我也不清楚了(手动捂脸

wyfcyx avatar Jul 17 '21 08:07 wyfcyx

@wyfcyx 我最后测试到的原因是 代码优化等级,如果在 1.55版本的.cargo/config文件中加入

[profile.dev]
opt-level = 1 # 就是opt-level > 0, 默认dev profile的 opt-level = 0 就是不优化

那么直接运行cargo build出来的elf文件是可以运行的,不会出现段错误,只不过gdb debug的时候会丢失一些信息,导致你在clion里面debug下一步的时候有时候会直接下两步下三步(其实原因就是代码经过了编译器优化)(强迫症抓狂) 1.51版本则没有这个问题

我猜测 rust 1.51版本到1.55版本的迭代中,代码编译优化这方面肯定改了什么东西导致了这个问题,但是我对rust内部的编译细节也是两眼一抹黑😂,我会去rust的github仓库里提issue,看看能不能碰到大神给解决一下,目前我就用opt-level = 1继续往下学习了(强迫症只能强行忍耐了)

dunmengjun avatar Jul 17 '21 09:07 dunmengjun

好家伙,我直接好家伙,rust github仓库那里5k+的 open issue. 😀

dunmengjun avatar Jul 17 '21 09:07 dunmengjun

@wyfcyx qemu 升级到5.2.0 问题解决了。(不能升级到最新的6.0.0, rustsbi 会报错,就是qemu-riscv64能正确工作,但qemu-system-riscv64不行)

目前来看,应该是qemu5.0.0有bug, 在5.2.0修复了。但是呢,rust 1.55也肯定改变了一些东西才触发了qemu5.0.0的bug,所以这波啊,这波是他们俩配合搞我😂

dunmengjun avatar Jul 17 '21 17:07 dunmengjun

第 1 行,我们使用 Rust 的宏将其函数符号 main 标志为弱链接

#[linkage = "weak"] 是attribute不是宏吧?

Mrfogg avatar Oct 05 '21 07:10 Mrfogg

想问下为什么 os/src/linker-qemu.ld 需要 . = ALIGN(4K); 而 user/src/linker.ld 不需要

reakuragho avatar Nov 28 '21 06:11 reakuragho

想问下为什么 os/src/linker-qemu.ld 需要 . = ALIGN(4K); 而 user/src/linker.ld 不需要

同问

ggssh avatar Nov 29 '21 02:11 ggssh

@leave8426 @ggssh 事实上前三章无论是内核还是应用这里的 4K 对齐都是不必要的。在第四章之后,基于页式内存管理和地址空间,我们才希望不要将权限不同的段映射到相同的页面中,因此在权限不同的两个段之间加上 4K 对齐来避免这件事情。

wyfcyx avatar Dec 29 '21 18:12 wyfcyx

// user/src/syscall.rs
const SYSCALL_WRITE: usize = 64;
const SYSCALL_EXIT: usize = 93;

/// syscall ID:64
fn sys_write(fd: usize, buf: *const u8, len: usize) -> isize;

/// syscall ID:93
fn sys_exit(xstate: usize) -> !;

这里 syscall ID 是一种约定,我有点好奇 64 和 93 这些数字是依照现有标准、实现来约定的吗?我在 Linux 手册中没有找到对应的系统调用。

Yang-Xijie avatar Feb 04 '22 11:02 Yang-Xijie

@Yang-Xijie 是按照这个网站的RISC-V64一列来约定的,应该与RISC-V架构下的Linux相同。

wyfcyx avatar Feb 05 '22 09:02 wyfcyx

error[E0061]: this function takes 2 arguments but 0 arguments were supplied
  --> src/lib.rs:43:10
   |
43 |     exit(main());
   |          ^^^^-- supplied 0 arguments
   |          |
   |          expected 2 arguments
   |

这个怎么解决啊大佬

wakk3107 avatar Feb 07 '22 05:02 wakk3107

前面那个exit函数问题解决了,是因为我main函数没修改成上面写的那样,然后现在cargo build出现了新的问题,求大佬赐教

error: linking with `rust-lld` failed: exit status: 1
  |
  = note: "rust-lld" "-flavor" "gnu" "/home/oslab/rust_demo/user/target/riscv64gc-unknown-none-elf/release/deps/run_pipe_test-cd9ed4c35e5e1ffd.run_pipe_test.698be4ce-cgu.0.rcgu.o" "/home/oslab/rust_demo/user/target/riscv64gc-unknown-none-elf/release/deps/run_pipe_test-cd9ed4c35e5e1ffd.run_pipe_test.698be4ce-cgu.1.rcgu.o" "/home/oslab/rust_demo/user/target/riscv64gc-unknown-none-elf/release/deps/run_pipe_test-cd9ed4c35e5e1ffd.fapzvyorumfo2o3.rcgu.o" "--as-needed" "-L" "/home/oslab/rust_demo/user/target/riscv64gc-unknown-none-elf/release/deps" "-L" "/home/oslab/rust_demo/user/target/release/deps" "-L" "/home/oslab/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/riscv64gc-unknown-none-elf/lib" "--start-group" "-Bstatic" "/home/oslab/rust_demo/user/target/riscv64gc-unknown-none-elf/release/deps/libuser_lib-e7e36345d281a60d.rlib" "/home/oslab/rust_demo/user/target/riscv64gc-unknown-none-elf/release/deps/libbuddy_system_allocator-7b8999f0e6ef4305.rlib" "/home/oslab/rust_demo/user/target/riscv64gc-unknown-none-elf/release/deps/libspin-cef89ffe0617938b.rlib" "/home/oslab/rust_demo/user/target/riscv64gc-unknown-none-elf/release/deps/libbitflags-e88189588f2de552.rlib" "/home/oslab/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/riscv64gc-unknown-none-elf/lib/liballoc-680acaf3577ebc7d.rlib" "/home/oslab/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/riscv64gc-unknown-none-elf/lib/librustc_std_workspace_core-2b7a7d6425e304f4.rlib" "/home/oslab/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/riscv64gc-unknown-none-elf/lib/libcore-4ac5b90611459253.rlib" "--end-group" "/home/oslab/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/riscv64gc-unknown-none-elf/lib/libcompiler_builtins-6dc56396ec70195b.rlib" "-Bdynamic" "-znoexecstack" "-L" "/home/oslab/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/riscv64gc-unknown-none-elf/lib" "-o" "/home/oslab/rust_demo/user/target/riscv64gc-unknown-none-elf/release/deps/run_pipe_test-cd9ed4c35e5e1ffd" "--gc-sections" "-O1" "-Tsrc/linker.ld"
  = note: rust-lld: error: undefined symbol: ebss
          >>> referenced by user_lib.dd02b582-cgu.1
          >>>               user_lib-e7e36345d281a60d.user_lib.dd02b582-cgu.1.rcgu.o:(_start) in archive /home/oslab/rust_demo/user/target/riscv64gc-unknown-none-elf/release/deps/libuser_lib-e7e36345d281a60d.rlib
          
          rust-lld: error: undefined symbol: sbss
          >>> referenced by user_lib.dd02b582-cgu.1
          >>>               user_lib-e7e36345d281a60d.user_lib.dd02b582-cgu.1.rcgu.o:(_start) in archive /home/oslab/rust_demo/user/target/riscv64gc-unknown-none-elf/release/deps/libuser_lib-e7e36345d281a60d.rlib

wakk3107 avatar Feb 07 '22 05:02 wakk3107

@wakk3107 这是链接错误,原因是在linker.ld中找不到sbssebss符号。

wyfcyx avatar Feb 07 '22 09:02 wyfcyx

解决了,设置和第一章一样的链接脚本 ,再将程序的起始物理地址调整为 0x80400000

便可build成功了

| | 陈钰霖 | | @.*** | On 2/7/2022 17:33,Yifan @.***> wrote:

@wakk3107 这是链接错误,原因是在linker.ld中找不到sbss和ebss符号。

— Reply to this email directly, view it on GitHub, or unsubscribe. Triage notifications on the go with GitHub Mobile for iOS or Android. You are receiving this because you were mentioned.Message ID: @.***>

wakk3107 avatar Feb 07 '22 10:02 wakk3107

求救 , 执行qemu-riscv64 ./hello_world后 结果为 段错误 (核心已转储) 我的linker.ld文件内容为

ENTRY(_start)
BASE_ADDRESS = 0x80400000;

SECTIONS
{
    . = BASE_ADDRESS;
    skernel = .;

    stext = .;
    .text : {
        *(.text.entry)
        *(.text .text.*)
    }

    . = ALIGN(4K);
    etext = .;
    srodata = .;
    .rodata : {
        *(.rodata .rodata.*)
        *(.srodata .srodata.*)
    }

    . = ALIGN(4K);
    erodata = .;
    sdata = .;
    .data : {
        *(.data .data.*)
        *(.sdata .sdata.*)
    }

    . = ALIGN(4K);
    edata = .;
    .bss : {
        *(.bss.stack)
        sbss = .;
        *(.bss .bss.*)
        *(.sbss .sbss.*)
    }

    . = ALIGN(4K);
    ebss = .;
    ekernel = .;

    /DISCARD/ : {
        *(.eh_frame)
    }
}```

wakk3107 avatar Feb 07 '22 13:02 wakk3107

对qemu-riscv64执行程序出现segment fault问题的猜测:qemu-riscv64执行程序的入口点是main。可以对使用linker.ld和不使用linker.ld生成的程序进行反汇编比较,看符号表中是否有main。

zcg0696 avatar Feb 26 '22 10:02 zcg0696

您好,在内存布局中小节中有这样一句话:“将程序的起始物理地址调整为 0x80400000 ,三个应用程序都会被加载到这个物理地址上运行”。但我在更改起始物理地址之后发现程序仍可以正常运行,例如:BASE_ADDRESS = 0x80410000。我寻找过很多回答,可能是加载地址和链接地址的区别,user的linker.ld是链接文件,其中的 BASE_ADDRESS 只是链接基地址,告诉程序在编译时从哪个地址开始,如果代码是与位置无关的,那么这个值怎样变都不会对程序运行产生影响。而真正决定应用程序加载位置的应该是 batch.rs 中的 APP_BASE_ADDRESS ,这个值的改变会直接影响应用程序加载位置。

但随意修改 BASE_ADDRESS 的话,会导致 start_bss 和 end_bss 的值发生变化,从而在 clear_bss() 函数执行时对错误的区域进行初始化。在当前的程序中,如果除去 clear_bss() 函数,那么这个值是可以任意更改的。请问我这样理解是对的吗?

jklincn avatar Mar 06 '22 11:03 jklincn

@jklinCN 应该没有什么问题。

wyfcyx avatar Mar 06 '22 21:03 wyfcyx

rustc 1.61.0-nightly (eb82facb1 2022-04-01) qemu-riscv64 version 5.0.0 02power.rs可以正常运行

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)
Test power OK!

qi-xmu avatar Apr 06 '22 14:04 qi-xmu

rustc 1.62.0-nightly (1f7fb6413 2022-04-10) qemu-riscv64 version 7.0.0 02power.rs 也可以正常运行

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)
Test power OK!

JasonkayZK avatar Jul 22 '22 07:07 JasonkayZK

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) Test power OK!

可以正常运行 cargo 1.64.0-nightly (4fd148c47 2022-08-03)

Tom-debug110 avatar Jan 21 '23 07:01 Tom-debug110

笔记:此处pub extern "C"的作用:

#[no_mangle]
#[link_section = ".text.entry"]
pub extern "C" fn _start() -> ! {
    clear_bss();
    exit(main());
    panic!("unreachable after sys_exit!");
}

ref: Rust程序设计语言,从其它语言调用Rust函数 可以使用 extern 来创建一个允许其他语言调用 Rust 函数的接口,这里创建一个C的ABI,此用法无需unsafe,因为使用Rust定义的函数安全性由Rust负责

xukp20 avatar Feb 11 '23 03:02 xukp20