Quellcode durchsuchen

完善libc,构建了OS-specific工具链,编译了基于gcc-11.3.0的DragonOS userland compiler,移植了mpfr,gmp,mpc库 (#134)

* 修改include路径

* 添加了创建libsysapi.a和/bin/sysroot/usr/include/+lib/的代码

* 修补.gitignore

* 删除多余项

* 优化脚本可读性

* 新增crt0 crti crtn

* 编译binutils所需的东西

* fflush()和fprintf()的简单实现

* 应用程序启动前,调用初始化libc的函数

* 自动创建sysroot

* 添加了stderr的初始化

* 修改了stderr的初始化

* 内核添加对stdio的简略处理

* 格式化代码

* 修正打开stdio文件描述符的问题

* bugfix: 修复fprintf忘记释放buf的问题

* 修复shell错误地把入口设置为main而不是_start的问题

* 新增__cxa_atexit  (gcc要求libc提供这个)

* 增加putchar puts

* 更新写入磁盘镜像的脚本,默认无参数时,使用legacy方式安装

* 更新编译脚本

* stdio增加eof的定义

* 新增extern cplusplus

* mpfr gmp mpc 构建脚本

* 更新libsysapi.a为libc.a

* 加上ferror fopen fclose

* 更新移植的软件的构建脚本

* 更改build_gcc_toolchain.sh中的-save参数名为-save-cache

Co-authored-by: longjin <longjin@RinGoTek.cn>
guanjinquan vor 2 Jahren
Ursprung
Commit
2224c93ea9
49 geänderte Dateien mit 746 neuen und 70 gelöschten Zeilen
  1. 1 0
      .gitignore
  2. 1 5
      Makefile
  3. 4 2
      kernel/src/process/fork.c
  4. 23 4
      kernel/src/process/process.c
  5. 3 1
      kernel/src/process/process.h
  6. 31 5
      kernel/src/syscall/syscall.c
  7. 14 7
      tools/build_gcc_toolchain.sh
  8. 4 1
      tools/write_disk_image.sh
  9. 19 3
      user/Makefile
  10. 1 1
      user/apps/shell/shell.lds
  11. 5 8
      user/libs/libc/src/Makefile
  12. 23 0
      user/libs/libc/src/arch/x86_64/Makefile
  13. 5 2
      user/libs/libc/src/arch/x86_64/crt0.c
  14. 13 0
      user/libs/libc/src/arch/x86_64/crti.S
  15. 9 0
      user/libs/libc/src/arch/x86_64/crtn.S
  16. 8 0
      user/libs/libc/src/cxa.c
  17. 13 7
      user/libs/libc/src/include/ctype.h
  18. 8 1
      user/libs/libc/src/include/dirent.h
  19. 9 1
      user/libs/libc/src/include/errno.h
  20. 9 1
      user/libs/libc/src/include/fcntl.h
  21. 8 0
      user/libs/libc/src/include/libm.h
  22. 10 2
      user/libs/libc/src/include/math.h
  23. 8 1
      user/libs/libc/src/include/printf.h
  24. 9 1
      user/libs/libc/src/include/signal.h
  25. 6 0
      user/libs/libc/src/include/stddef.h
  26. 29 1
      user/libs/libc/src/include/stdio.h
  27. 9 1
      user/libs/libc/src/include/stdlib.h
  28. 9 1
      user/libs/libc/src/include/string.h
  29. 9 1
      user/libs/libc/src/include/time.h
  30. 9 1
      user/libs/libc/src/include/unistd.h
  31. 18 0
      user/libs/libc/src/libc_init.c
  32. 69 0
      user/libs/libc/src/stdio.c
  33. 3 0
      user/libs/libc/src/stdlib.c
  34. 0 12
      user/libs/libc/src/sysdeps/x86_64/Makefile
  35. 15 0
      user/port/README.md
  36. 1 0
      user/port/binutils/2.38/.gitignore
  37. 41 0
      user/port/binutils/2.38/Dockerfile
  38. 25 0
      user/port/binutils/2.38/README.md
  39. 42 0
      user/port/binutils/2.38/build.sh
  40. 1 0
      user/port/binutils/2.38/run.sh
  41. 17 0
      user/port/build.sh
  42. 1 0
      user/port/flex/2.6.4/.gitignore
  43. 37 0
      user/port/flex/2.6.4/build.sh
  44. 1 0
      user/port/gcc/11.3.0/.gitignore
  45. 51 0
      user/port/gcc/11.3.0/build-hosted.sh
  46. 28 0
      user/port/gmp/6.2.1/build.sh
  47. 35 0
      user/port/mpc/1.2.1/build.sh
  48. 37 0
      user/port/mpfr/4.1.1/build.sh
  49. 15 0
      user/port/pkg-config.sh

+ 1 - 0
.gitignore

@@ -7,6 +7,7 @@ kernel/kernel
 .DS_Store
 
 *.o
+*.a
 *.s
 serial_opt.txt
 user/sys_api_lib

+ 1 - 5
Makefile

@@ -28,9 +28,6 @@ ifeq ($(DEBUG), DEBUG)
 GLOBAL_CFLAGS += -g 
 endif
 
-# ifeq ($(DragonOS_GCC), )
-# $(error 尚未安装DragonOS交叉编译器, 请使用tools文件夹下的build_gcc_toolchain.sh脚本安装)
-# endif
 
 export CC=$(DragonOS_GCC)/x86_64-elf-gcc
 export LD=ld
@@ -52,8 +49,7 @@ kernel:
 	
 .PHONY: user
 user:
-	mkdir -p bin/user/
-	mkdir -p bin/tmp/user
+
 	@if [ -z $$DragonOS_GCC ]; then echo "\033[31m  [错误]尚未安装DragonOS交叉编译器, 请使用tools文件夹下的build_gcc_toolchain.sh脚本安装  \033[0m"; exit 1; fi
 	$(MAKE) -C ./user all || (sh -c "echo 用户程序编译失败" && exit 1)
 

+ 4 - 2
kernel/src/process/fork.c

@@ -136,7 +136,7 @@ unsigned long do_fork(struct pt_regs *regs, unsigned long clone_flags, unsigned
     // 唤醒进程
     process_wakeup(tsk);
 
-    //创建对应procfs文件
+    // 创建对应procfs文件
     procfs_register_pid(tsk->pid);
 
     return retval;
@@ -188,8 +188,10 @@ int process_copy_files(uint64_t clone_flags, struct process_control_block *pcb)
     if (clone_flags & CLONE_FS)
         return retval;
 
+    // TODO: 这里是临时性的特殊处理stdio,待文件系统重构及tty设备实现后,需要改写这里
+    process_open_stdio(current_pcb);
     // 为新进程拷贝新的文件描述符
-    for (int i = 0; i < PROC_MAX_FD_NUM; ++i)
+    for (int i = 3; i < PROC_MAX_FD_NUM; ++i)
     {
         if (current_pcb->fds[i] == NULL)
             continue;

+ 23 - 4
kernel/src/process/process.c

@@ -409,6 +409,8 @@ ul do_execve(struct pt_regs *regs, char *path, char *argv[], char *envp[])
 
     // 关闭之前的文件描述符
     process_exit_files(current_pcb);
+    
+    process_open_stdio(current_pcb);
 
     // 清除进程的vfork标志位
     current_pcb->flags &= ~PF_VFORK;
@@ -640,6 +642,10 @@ void process_init()
 
     // 初始化init进程的signal相关的信息
     initial_proc_init_signal(current_pcb);
+
+    // TODO: 这里是临时性的特殊处理stdio,待文件系统重构及tty设备实现后,需要改写这里
+    process_open_stdio(current_pcb);
+
     // 临时设置IDLE进程的的虚拟运行时间为0,防止下面的这些内核线程的虚拟运行时间出错
     current_pcb->virtual_runtime = 0;
     barrier();
@@ -724,11 +730,13 @@ int process_wakeup_immediately(struct process_control_block *pcb)
  */
 uint64_t process_exit_files(struct process_control_block *pcb)
 {
+    // TODO: 当stdio不再被以-1来特殊处理时,在这里要释放stdio文件的内存
+
     // 不与父进程共享文件描述符
     if (!(pcb->flags & PF_VFORK))
     {
 
-        for (int i = 0; i < PROC_MAX_FD_NUM; ++i)
+        for (int i = 3; i < PROC_MAX_FD_NUM; ++i)
         {
             if (pcb->fds[i] == NULL)
                 continue;
@@ -843,15 +851,15 @@ int process_release_pcb(struct process_control_block *pcb)
 int process_fd_alloc(struct vfs_file_t *file)
 {
     int fd_num = -1;
-    struct vfs_file_t **f = current_pcb->fds;
 
     for (int i = 0; i < PROC_MAX_FD_NUM; ++i)
     {
+        // kdebug("currentpcb->fds[%d]=%#018lx", i, current_pcb->fds[i]);
         /* 找到指针数组中的空位 */
-        if (f[i] == NULL)
+        if (current_pcb->fds[i] == NULL)
         {
             fd_num = i;
-            f[i] = file;
+            current_pcb->fds[i] = file;
             break;
         }
     }
@@ -882,3 +890,14 @@ void process_set_pcb_name(struct process_control_block *pcb, const char *pcb_nam
 {
     __set_pcb_name(pcb, pcb_name);
 }
+
+void process_open_stdio(struct process_control_block *pcb)
+{
+    // TODO: 这里是临时性的特殊处理stdio,待文件系统重构及tty设备实现后,需要改写这里
+    // stdin
+    pcb->fds[0] = -1UL;
+    // stdout
+    pcb->fds[1] = -1UL;
+    // stderr
+    pcb->fds[2] = -1UL;
+}

+ 3 - 1
kernel/src/process/process.h

@@ -220,4 +220,6 @@ extern int process_try_to_wake_up(struct process_control_block *_pcb, uint64_t _
  * @return false 唤醒失败
  */
 extern int process_wake_up_state(struct process_control_block *pcb, uint64_t state);
-void __switch_to(struct process_control_block *prev, struct process_control_block *next);
+void __switch_to(struct process_control_block *prev, struct process_control_block *next);
+
+void process_open_stdio(struct process_control_block * pcb);

+ 31 - 5
kernel/src/syscall/syscall.c

@@ -6,8 +6,8 @@
 #include <driver/disk/ahci/ahci.h>
 #include <exception/gate.h>
 #include <exception/irq.h>
-#include <filesystem/vfs/VFS.h>
 #include <filesystem/fat32/fat32.h>
+#include <filesystem/vfs/VFS.h>
 #include <mm/slab.h>
 #include <process/process.h>
 #include <time/sleep.h>
@@ -19,10 +19,10 @@ extern uint64_t sys_mstat(struct pt_regs *regs);
 extern uint64_t sys_open(struct pt_regs *regs);
 extern uint64_t sys_unlink_at(struct pt_regs *regs);
 extern uint64_t sys_kill(struct pt_regs *regs);
-extern uint64_t sys_sigaction(struct pt_regs * regs);
-extern uint64_t sys_rt_sigreturn(struct pt_regs * regs);
-extern uint64_t sys_getpid(struct pt_regs * regs);
-extern uint64_t sys_sched(struct pt_regs * regs);
+extern uint64_t sys_sigaction(struct pt_regs *regs);
+extern uint64_t sys_rt_sigreturn(struct pt_regs *regs);
+extern uint64_t sys_getpid(struct pt_regs *regs);
+extern uint64_t sys_sched(struct pt_regs *regs);
 
 /**
  * @brief 导出系统调用处理函数的符号
@@ -173,6 +173,18 @@ uint64_t sys_read(struct pt_regs *regs)
     if (count < 0)
         return -EINVAL;
 
+    switch (fd_num)
+    {
+    case 0: // stdin
+        return 0;
+        break;
+    case 1: // stdout
+        return 0;
+        break;
+    case 2: // stderr
+        return 0;
+        break;
+    }
     struct vfs_file_t *file_ptr = current_pcb->fds[fd_num];
     uint64_t ret = 0;
     if (file_ptr->file_ops && file_ptr->file_ops->read)
@@ -212,6 +224,20 @@ uint64_t sys_write(struct pt_regs *regs)
     if (count < 0)
         return -EINVAL;
 
+    switch (fd_num)
+    {
+    case 0: // stdin
+        return 0;
+        break;
+    case 1: // stdout
+        printk("%s", buf);
+        return count;
+        break;
+    case 2: // stderr
+        printk("%s", buf);
+        return count;
+        break;
+    }
     struct vfs_file_t *file_ptr = current_pcb->fds[fd_num];
     uint64_t ret = 0;
     if (file_ptr->file_ops && file_ptr->file_ops->write)

+ 14 - 7
tools/build_gcc_toolchain.sh

@@ -17,11 +17,15 @@ KEEP_BINUTILS=0
 KEEP_GCC=0
 CHANGE_SOURCE=0
 FORCE=0
+SAVE_CACHE=0
 while true; do
 	if [ ! -n "$1" ]; then
 		break
 	fi
 	case "$1" in
+        "-save-cache")
+            SAVE_CACHE=1
+        ;;
 		"-rebuild")	
 			echo "清除${INSTALL_POS}目录下的所有信息"
             rm -rf "${INSTALL_POS}"
@@ -40,6 +44,7 @@ while true; do
         ;;
         "-help")
             echo "脚本选项如下:"
+            echo "-save-cache: 保留最后的下载压缩包"
             echo "-rebuild: 清除上一次安装的全部信息, 即删掉$INSTALL_POS目录下的所有内容, 然后重新构建gcc工具链."
             echo "-kg(keep-gcc): 您确保${STRUCTURE}-gcc已被编译安装, 本次调用脚本不重复编译安装gcc. 如果没有安装,脚本仍然会自动安装."
             echo "-kb(keep-binutils): 您确保binutils已被编译安装, 本次调用脚本不重复编译安装binutils. 如果没有安装,脚本仍然会自动安装."
@@ -167,13 +172,15 @@ source "$HOME/.bashrc"
 if [ -n "$(find $PREFIX/bin/* -name $TARGET_GCC)" ] &&
    [ -n "$(find $PREFIX/bin/* -name $TARGET_LD)" ] &&
    [ -n "$(find $PREFIX/bin/* -name $TARGET_AS)" ]; then
-    # 删除临时文件
-    rm -rf "$BIN_UTILS"
-    rm -rf "$BIN_UTILS_TAR"
-    rm -rf "build-binutils"
-    rm -rf "$GCC_FILE"
-    rm -rf "$GCC_FILE_TAR"
-    rm -rf "build-gcc"
+   if [ ${SAVE_CACHE} -eq 0 ]; then
+        # 删除临时文件
+        rm -rf "$BIN_UTILS"
+        rm -rf "$BIN_UTILS_TAR"
+        rm -rf "build-binutils"
+        rm -rf "$GCC_FILE"
+        rm -rf "$GCC_FILE_TAR"
+        rm -rf "build-gcc"
+    fi
 
     echo -e "\033[42;37m [构建成功] Build Successfully.(请重新打开另一个Shell窗口或者重新打开你的IDE以获取新的环境变量) \033[0m"
 else 	

+ 4 - 1
tools/write_disk_image.sh

@@ -87,8 +87,10 @@ cp ${kernel} ${root_folder}/bin/disk_mount/boot
 mkdir -p ${root_folder}/bin/disk_mount/bin
 mkdir -p ${root_folder}/bin/disk_mount/dev
 mkdir -p ${root_folder}/bin/disk_mount/proc
+mkdir -p ${root_folder}/bin/disk_mount/usr
 cp -r ${root_folder}/bin/user/* ${root_folder}/bin/disk_mount/bin
 touch ${root_folder}/bin/disk_mount/dev/keyboard.dev
+cp -r ${root_folder}/bin/sysroot/usr/* ${root_folder}/bin/disk_mount/usr/ 
 
 # 设置 grub 相关数据
 if [ ${ARCH} == "i386" ] || [ ${ARCH} == "x86_64" ]; then
@@ -121,7 +123,8 @@ case "$1" in
         esac
         ;;
     *)
-    echo "参数错误"
+    #传统bios
+    ${GRUB_PATH_I386_LEGACY_INSTALL} --target=i386-pc --boot-directory=${boot_folder} /dev/$LOOP_DEVICE
     ;;
            
 esac

+ 19 - 3
user/Makefile

@@ -2,7 +2,7 @@ user_sub_dirs = apps
 
 SUBDIR_ROOTS := . 
 DIRS := . $(shell find $(SUBDIR_ROOTS) -type d)
-GARBAGE_PATTERNS := *.o *.s~ *.s *.S~ *.c~ *.h~ sys_api_lib
+GARBAGE_PATTERNS := *.o *.s~ *.s *.S~ *.c~ *.h~ sys_api_lib *.a
 GARBAGE := $(foreach DIR,$(DIRS),$(addprefix $(DIR)/,$(GARBAGE_PATTERNS)))
 
 
@@ -22,16 +22,32 @@ $(user_sub_dirs): ECHO sys_api_lib
 app: $(user_sub_dirs)
 
 all: app
+
 	$(shell if [ ! -e $(tmp_output_dir) ];then mkdir -p $(tmp_output_dir); fi)
 	$(shell if [ ! -e $(output_dir) ];then mkdir -p $(output_dir); fi)
 
 	@echo 用户态程序编译完成
 
+make_output_dir: ECHO
+	mkdir -p $(ROOT_PATH)/bin/user/
+	mkdir -p $(ROOT_PATH)/bin/tmp/user
+	mkdir -p $(ROOT_PATH)/bin/sysroot/usr/include
+	mkdir -p $(ROOT_PATH)/bin/sysroot/usr/lib
+
+	$(shell if [ ! -e $(tmp_output_dir) ];then mkdir -p $(tmp_output_dir); fi)
+	$(shell if [ ! -e $(output_dir) ];then mkdir -p $(output_dir); fi)
 # 系统库
-sys_api_lib:
-	$(MAKE) -C libs all CFLAGS="$(CFLAGS)" tmp_output_dir="$(tmp_output_dir)" output_dir="$(output_dir)" sys_libs_dir="$(shell pwd)/libs"
 
+sys_api_lib_stage_1: make_output_dir
+	@echo Building sys_api_lib...
+	$(MAKE) -C libs all CFLAGS="$(CFLAGS)" tmp_output_dir="$(tmp_output_dir)" output_dir="$(output_dir)" sys_libs_dir="$(shell pwd)/libs"
+	
 
+sys_api_lib: sys_api_lib_stage_1
+	$(AR) crvs $(ROOT_PATH)/bin/sysroot/usr/lib/libc.a $(shell find ./libs/* -name "*.o")
+	$(shell find ./libs/* -name "*.o" | xargs -I {} cp {} $(ROOT_PATH)/bin/sysroot/usr/lib/)
+	$(shell cp -r $(ROOT_PATH)/user/libs/libc/src/include/* $(ROOT_PATH)/bin/sysroot/usr/include/)
+	$(shell cp -r $(ROOT_PATH)/user/libs/libc/src/arch/x86_64/c*.o $(ROOT_PATH)/bin/sysroot/usr/lib/)
 
 clean: 
 	rm -rf $(GARBAGE)

+ 1 - 1
user/apps/shell/shell.lds

@@ -1,7 +1,7 @@
 
 OUTPUT_FORMAT("elf64-x86-64","elf64-x86-64","elf64-x86-64")
 OUTPUT_ARCH(i386:x86-64)
-ENTRY(main)
+ENTRY(_start)
 
 SECTIONS
 {

+ 5 - 8
user/libs/libc/src/Makefile

@@ -8,9 +8,12 @@ CFLAGS += -I .
 libc_sub_dirs=math sys
 
 ifeq ($(ARCH), __x86_64__)
-libc_sub_dirs += sysdeps/x86_64
+libc_sub_dirs += arch/x86_64
 endif
 
+$(libc_sub_dirs): ECHO
+	$(MAKE) -C $@ all CFLAGS="$(CFLAGS)" ASFLAGS="$(ASFLAGS) -I $(shell pwd)"
+
 libc_objs:= $(shell find ./*.c)
 
 ECHO:
@@ -29,13 +32,7 @@ clean:
 		cd .. ;\
 	done
 
-libc: $(libc_objs) libc_rust
-	@list='$(libc_sub_dirs)'; for subdir in $$list; do \
-    		echo "make all in $$subdir";\
-    		cd $$subdir;\
-    		$(MAKE) all CFLAGS="$(CFLAGS) -I $(shell pwd)";\
-    		cd ..;\
-	done
+libc: $(libc_objs) $(libc_sub_dirs) libc_rust
 
 libc_rust:
 	rustup default nightly

+ 23 - 0
user/libs/libc/src/arch/x86_64/Makefile

@@ -0,0 +1,23 @@
+libc_arch_objs:= $(shell find ./*.c)
+
+ECHO:
+	@echo "$@"
+
+
+$(libc_arch_objs): ECHO
+	$(CC) $(CFLAGS) -c $@ -o $@.o
+
+all: $(libc_arch_objs) crti.o crtn.o
+	mv crt0.c.o crt0.o
+
+crti.o: crti.S
+	$(CC) -E crti.S > _crti.s # 预处理
+	$(AS) $(ASFLAGS) -o crti.o _crti.s
+
+crtn.o: crtn.S
+	$(CC) -E crtn.S > _crtn.s # 预处理
+	$(AS) $(ASFLAGS) -o crtn.o _crtn.s
+
+clean:
+	
+	echo "Done."

+ 5 - 2
user/libs/libc/src/sysdeps/x86_64/elf/start.c → user/libs/libc/src/arch/x86_64/crt0.c

@@ -3,11 +3,14 @@
 #include <stdlib.h>
 
 extern int main(int, char **);
+extern void _init();
+extern void _libc_init();
 
 void _start(int argc, char **argv)
 {
-    // printf("before main\n");
+    // Run the global constructors.
+    _init();
+    _libc_init();
     int retval = main(argc, argv);
-    // printf("before exit, code=%d\n", retval);
     exit(retval);
 }

+ 13 - 0
user/libs/libc/src/arch/x86_64/crti.S

@@ -0,0 +1,13 @@
+.section .init
+.global _init
+_init:
+   push %rbp
+   movq %rsp, %rbp
+   /* gcc will nicely put the contents of crtbegin.o's .init section here. */
+
+.section .fini
+.global _fini
+_fini:
+   push %rbp
+   movq %rsp, %rbp
+   /* gcc will nicely put the contents of crtbegin.o's .fini section here. */

+ 9 - 0
user/libs/libc/src/arch/x86_64/crtn.S

@@ -0,0 +1,9 @@
+.section .init
+   /* gcc will nicely put the contents of crtend.o's .init section here. */
+   popq %rbp
+   ret
+
+.section .fini
+   /* gcc will nicely put the contents of crtend.o's .fini section here. */
+   popq %rbp
+   ret

+ 8 - 0
user/libs/libc/src/cxa.c

@@ -0,0 +1,8 @@
+/* Register a function to be called by exit or when a shared library
+   is unloaded.  This function is only called from code generated by
+   the C++ compiler.  */
+int __cxa_atexit(void (*func)(void *), void *arg, void *d)
+{
+    // todo: 使用rust实现这个函数。参考:http://redox.longjin666.cn/xref/relibc/src/cxa.rs?r=c7d499d4&mo=323&fi=15#15
+    return 0;
+}

+ 13 - 7
user/libs/libc/src/include/ctype.h

@@ -6,19 +6,22 @@
 
 #include <__libc__.h>
 
-
-int isalnum(int c);
+ 
+#if defined(__cplusplus) 
+extern  "C"  { 
+#endif
+// int isalnum(int c);
 int isalpha(int c);
 int isdigit(int c);
 int islower(int c);
 int isprint(int c);
-int isgraph(int c);
-int iscntrl(int c);
-int isgraph(int c);
-int ispunct(int c);
+// int isgraph(int c);
+// int iscntrl(int c);
+// int isgraph(int c);
+// int ispunct(int c);
 int isspace(int c);
 int isupper(int c);
-int isxdigit(int c);
+// int isxdigit(int c);
 
 int isascii(int c);
 
@@ -36,3 +39,6 @@ int toupper(int c);
 
 extern char _ctype_[256];
 
+#if defined(__cplusplus) 
+}  /* extern "C" */ 
+#endif

+ 8 - 1
user/libs/libc/src/include/dirent.h

@@ -1,6 +1,9 @@
 #pragma once
 #include <sys/types.h>
 
+#if defined(__cplusplus) 
+extern  "C"  { 
+#endif
 
 /**
  * @brief inode的属性(copy from vfs.h)
@@ -63,4 +66,8 @@ int closedir(struct DIR *dirp);
  * @param dir 
  * @return struct dirent* 
  */
-struct dirent* readdir(struct DIR* dir);
+struct dirent* readdir(struct DIR* dir);
+
+#if defined(__cplusplus) 
+}  /* extern "C" */ 
+#endif

+ 9 - 1
user/libs/libc/src/include/errno.h

@@ -10,6 +10,10 @@
  */
 #pragma once
 
+#if defined(__cplusplus) 
+extern  "C"  { 
+#endif
+
 #define E2BIG 1            /* 参数列表过长,或者在输出buffer中缺少空间 或者参数比系统内建的最大值要大 Argument list too long. */
 #define EACCES 2           /* 访问被拒绝 Permission denied */
 #define EADDRINUSE 3       /* 地址正在被使用 Address in use.*/
@@ -100,4 +104,8 @@
 #define EWOULDBLOCK 80     /* 操作将被禁止 Operation would block (may be the same value as [EAGAIN]). */
 #define EXDEV 81           /* 跨设备连接 Cross-device link. */
 
-extern int errno;
+extern int errno;
+
+#if defined(__cplusplus) 
+}  /* extern "C" */ 
+#endif

+ 9 - 1
user/libs/libc/src/include/fcntl.h

@@ -10,6 +10,10 @@
  */
 #pragma once
 
+#if defined(__cplusplus) 
+extern  "C"  { 
+#endif
+
 #define O_RDONLY 00000000 // Open Read-only
 #define O_WRONLY 00000001 // Open Write-only
 #define O_RDWR 00000002   // Open read/write
@@ -62,4 +66,8 @@
  * @param ... 
  * @return int 文件描述符
  */
-int open(const char * path, int options, ...);
+int open(const char * path, int options, ...);
+
+#if defined(__cplusplus) 
+}  /* extern "C" */ 
+#endif

+ 8 - 0
user/libs/libc/src/include/libm.h

@@ -1,6 +1,10 @@
 #pragma once
 #include <sys/types.h>
 
+#if defined(__cplusplus) 
+extern  "C"  { 
+#endif
+
 // ===== 描述long double 的数据比特结构
 #if __LDBL_MANT_DIG__ == 53 && __LDBL_MAX_EXP__ == 1024
 #elif __LDBL_MANT_DIG__ == 64 && __LDBL_MAX_EXP__ == 16384 && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
@@ -73,3 +77,7 @@ union ldshape
             (void)__x;                        \
         }                                     \
     } while (0)
+
+#if defined(__cplusplus) 
+}  /* extern "C" */ 
+#endif

+ 10 - 2
user/libs/libc/src/include/math.h

@@ -1,12 +1,20 @@
 #pragma once
 #include <stddef.h>
 
+#if defined(__cplusplus) 
+extern  "C"  { 
+#endif
+
 double fabs(double x);
-float fabsf(float x);
+// float fabsf(float x);
 long double fabsl(long double x);
 
 double round(double x);
 float roundf(float x);
 long double roundl(long double x);
 
-int64_t pow(int64_t x, int y);
+int64_t pow(int64_t x, int y);
+
+#if defined(__cplusplus) 
+}  /* extern "C" */ 
+#endif

+ 8 - 1
user/libs/libc/src/include/printf.h

@@ -1,5 +1,8 @@
 #pragma once
 
+#if defined(__cplusplus) 
+extern  "C"  { 
+#endif
 
 #define PAD_ZERO 1 // 0填充
 #define LEFT 2     // 靠左对齐
@@ -10,4 +13,8 @@
 #define SMALL 64   // 十进制以上数字显示小写字母
 #define SIGN 128   // 显示符号位
 
-#define is_digit(c) ((c) >= '0' && (c) <= '9') // 用来判断是否是数字的宏
+#define is_digit(c) ((c) >= '0' && (c) <= '9') // 用来判断是否是数字的宏
+
+#if defined(__cplusplus) 
+}  /* extern "C" */ 
+#endif

+ 9 - 1
user/libs/libc/src/include/signal.h

@@ -1,6 +1,10 @@
 #pragma once
 #include <unistd.h>
 
+#if defined(__cplusplus) 
+extern  "C"  { 
+#endif
+
 #define SIGHUP 1
 #define SIGINT 2
 #define SIGQUIT 3
@@ -91,4 +95,8 @@ struct sigaction
 int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
 int signal(int signum, __sighandler_t handler);
 int raise(int sig);
-int kill(pid_t, int sig);
+int kill(pid_t, int sig);
+
+#if defined(__cplusplus) 
+}  /* extern "C" */ 
+#endif

+ 6 - 0
user/libs/libc/src/include/stddef.h

@@ -8,6 +8,12 @@
    #define NULL ((void *)0)
 #endif
 
+#if defined(__cplusplus) 
+extern  "C"  { 
+#endif
 
 typedef __PTRDIFF_TYPE__ ptrdiff_t; // Signed integer type of the result of subtracting two pointers.
 
+#if defined(__cplusplus) 
+}  /* extern "C" */ 
+#endif

+ 29 - 1
user/libs/libc/src/include/stdio.h

@@ -3,6 +3,10 @@
 #include <sys/types.h>
 #include <stdarg.h>
 
+#if defined(__cplusplus) 
+extern  "C"  { 
+#endif
+
 // 字体颜色的宏定义
 #define COLOR_WHITE 0x00ffffff  //白
 #define COLOR_BLACK 0x00000000  //黑
@@ -20,6 +24,18 @@
 
 #define SEEK_MAX 3
 
+/* The value returned by fgetc and similar functions to indicate the
+   end of the file.  */
+#define EOF (-1)
+
+typedef struct {
+    int fd;  // 文件描述符
+} FILE;
+
+extern FILE* stdin;
+extern FILE* stdout;
+extern FILE* stderr;
+
 /**
  * @brief 往屏幕上输出字符串
  *
@@ -32,4 +48,16 @@ int64_t put_string(char *str, uint64_t front_color, uint64_t bg_color);
 
 int printf(const char *fmt, ...);
 int sprintf(char *buf, const char *fmt, ...);
-int vsprintf(char *buf, const char *fmt, va_list args);
+int vsprintf(char *buf, const char *fmt, va_list args);
+
+int fflush(FILE *stream);
+int fprintf(FILE *restrict stream, const char *restrict format, ...);
+int ferror(FILE *stream);
+FILE *fopen(const char *restrict pathname, const char *restrict mode);
+int fclose(FILE *stream);
+int puts(const char *s);
+int putchar(int c);
+
+#if defined(__cplusplus) 
+}  /* extern "C" */ 
+#endif

+ 9 - 1
user/libs/libc/src/include/stdlib.h

@@ -1,6 +1,10 @@
 #pragma once
 #include <sys/types.h>
 
+#if defined(__cplusplus) 
+extern  "C"  { 
+#endif
+
 /**
  * @brief 获取一块堆内存
  * 
@@ -45,4 +49,8 @@ void exit(int status);
  * @brief 通过发送SIGABRT,从而退出当前进程
  * 
  */
-void abort();
+void abort();
+
+#if defined(__cplusplus) 
+}  /* extern "C" */ 
+#endif

+ 9 - 1
user/libs/libc/src/include/string.h

@@ -2,6 +2,10 @@
 
 #include <sys/types.h>
 
+#if defined(__cplusplus) 
+extern  "C"  { 
+#endif
+
 void *memset(void *dst, unsigned char C, uint64_t size);
 /**
  * @brief 获取字符串的大小
@@ -76,4 +80,8 @@ static void *memcpy(void *dst, const void *src, long Num)
                          : "0"(Num / 8), "q"(Num), "1"(dst), "2"(src)
                          : "memory");
     return dst;
-}
+}
+
+#if defined(__cplusplus) 
+}  /* extern "C" */ 
+#endif

+ 9 - 1
user/libs/libc/src/include/time.h

@@ -2,6 +2,10 @@
 
 #include <stddef.h>
 
+#if defined(__cplusplus) 
+extern  "C"  { 
+#endif
+
 // 操作系统定义时间以ns为单位
 #define CLOCKS_PER_SEC 1000000
 
@@ -42,4 +46,8 @@ int nanosleep(const struct timespec *rqtp, struct timespec *rmtp);
  * 
  * @return clock_t 
  */
-clock_t clock();
+clock_t clock();
+
+#if defined(__cplusplus) 
+}  /* extern "C" */ 
+#endif

+ 9 - 1
user/libs/libc/src/include/unistd.h

@@ -2,6 +2,10 @@
 #include <stdint.h>
 #include <sys/types.h>
 
+#if defined(__cplusplus) 
+extern  "C"  { 
+#endif
+
 /**
  * @brief 关闭文件接口
  *
@@ -116,4 +120,8 @@ int rm(const char * path);
  */
 void swab(void *restrict src, void *restrict dest, ssize_t nbytes);
 
-pid_t getpid(void);
+pid_t getpid(void);
+
+#if defined(__cplusplus) 
+}  /* extern "C" */ 
+#endif

+ 18 - 0
user/libs/libc/src/libc_init.c

@@ -0,0 +1,18 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+FILE *stdin;
+FILE *stdout;
+FILE *stderr;
+
+void _libc_init()
+{
+    // 初始化标准流对应的文件描述符
+    stdin = malloc(sizeof(FILE));
+    stdout = malloc(sizeof(FILE));
+    stderr = malloc(sizeof(FILE));
+
+    stdin->fd = 0;
+    stdout->fd = 1;
+    stderr->fd = 2;
+}

+ 69 - 0
user/libs/libc/src/stdio.c

@@ -0,0 +1,69 @@
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+int fprintf(FILE *restrict stream, const char *restrict format, ...)
+{
+    const int bufsize = 65536 * 2;
+    char *buf = malloc(bufsize);
+    memset(buf, 0, bufsize);
+    va_list args;
+
+    va_start(args, format);
+    vsprintf(buf, format, args);
+    va_end(args);
+
+    int len = strlen(buf);
+    if (len > bufsize - 1)
+    {
+        len = bufsize - 1;
+        buf[bufsize - 1] = 0;
+    }
+    write(stream->fd, buf, len);
+    free(buf);
+}
+
+int puts(const char *s)
+{
+    return put_string(s, COLOR_WHITE, COLOR_BLACK);
+}
+
+int putchar(int c)
+{
+    return printf("%c", (char)c);
+}
+
+int fflush(FILE *stream)
+{
+    return 0;
+}
+
+int ferror(FILE *stream)
+{
+    return 0;
+}
+
+int fclose(FILE *stream)
+{
+    if (stream->fd >= 3)
+    {
+        int retcval = close(stream);
+        free(stream);
+        return;
+    }
+    else
+        return 0;
+}
+
+FILE *fopen(const char *restrict pathname, const char *restrict mode)
+{
+    FILE *stream = malloc(sizeof(FILE));
+    memset(stream, 0, sizeof(FILE));
+
+    int fd = open(pathname, mode);
+    if (fd >= 0)
+        stream->fd = fd;
+    return stream;
+}

+ 3 - 0
user/libs/libc/src/stdlib.c

@@ -4,6 +4,8 @@
 #include <libsystem/syscall.h>
 #include <signal.h>
 
+extern void _fini();
+
 int abs(int i)
 {
     return i < 0 ? -i : i;
@@ -54,6 +56,7 @@ int atoi(const char *str)
  */
 void exit(int status)
 {
+    _fini();
     syscall_invoke(SYS_EXIT, status, 0, 0, 0, 0, 0, 0, 0);
 }
 

+ 0 - 12
user/libs/libc/src/sysdeps/x86_64/Makefile

@@ -1,12 +0,0 @@
-
-
-all: start.o
-
-ifeq ($(ARCH), __x86_64__)
-start.o:
-	$(CC) $(CFLAGS) -c elf/start.c -o elf/start.o
-endif
-
-clean:
-	
-	echo "Done."

+ 15 - 0
user/port/README.md

@@ -0,0 +1,15 @@
+# port目录
+---
+
+本目录移植到DragonOS的应用程序。
+
+可以包含以下类型的文件:
+
+- 移植的patch,以及编译脚本、编译用的Dockerfile等
+- 把子目录作为git仓库的submodule
+
+## 注意
+
+编译好libc之后,要把sysroot/usr/lib的文件,复制到$HOME/opt/dragonos-host-userspace/x86_64-dragonos/lib. 因为ld会从这里面找链接的东西。
+
+目前由于DragonOS的libc还不完善,所以尚未能使用用户态交叉编译器来编译flex。

+ 1 - 0
user/port/binutils/2.38/.gitignore

@@ -0,0 +1 @@
+build-binutils/

+ 41 - 0
user/port/binutils/2.38/Dockerfile

@@ -0,0 +1,41 @@
+# 本Dockerfile用于构建binutils 2.38的交叉编译环境
+
+FROM ubuntu:jammy
+
+# Install dependencies
+RUN apt-get update && apt-get install -y \
+    autoconf2.69 \
+    automake \
+    bison \
+    build-essential \
+    flex \
+    gawk \
+    gettext \
+    git \
+    libgmp-dev \
+    libmpc-dev \
+    libmpfr-dev \
+    libncurses5-dev \
+    libtool \
+    m4 \
+    make \
+    ninja-build \
+    python3 \
+    texinfo \
+    wget \
+    xz-utils \
+    zlib1g-dev \
+    wget \
+    && rm /usr/bin/autoconf && ln -s /usr/bin/autoconf2.69 /usr/bin/autoconf
+
+WORKDIR /opt
+
+# download automake 1.15.1
+RUN wget http://mirrors.ustc.edu.cn/gnu/automake/automake-1.15.1.tar.xz && \
+    tar -xvf automake-1.15.1.tar.xz && \
+    cd automake-1.15.1 && \
+    ./configure --prefix=/usr && \
+    make && \
+    make install && \
+    cd .. && \
+    rm -rf automake-1.15.1 automake-1.15.1.tar.xz

+ 25 - 0
user/port/binutils/2.38/README.md

@@ -0,0 +1,25 @@
+# binutils-2.38
+
+## 说明
+
+这里是移植到用户态的binutils-2.38,用于DragonOS的用户态编译器。在编译这里之前,请先在项目根目录下运行`make -j $(nproc)`, 以确保编译binutils所依赖的依赖库已经编译好。
+
+先修改build.sh中的路径,配置好需要的信息,再使用以下命令,即可开始编译:
+
+```bash
+bash build.sh
+```
+
+--- 
+
+请注意,如果您要修改binutils的代码,请先使用以下命令,构建编辑binutils代码配置的环境:
+
+```bash
+docker build --no-cache -t dragonos-binutils-build .
+```
+
+然后再在binutils目录下执行以下命令,进入容器:
+
+```bash
+docker run --rm -it -v $PWD:/workdir -w /workdir dragonos-binutils-build
+```

+ 42 - 0
user/port/binutils/2.38/build.sh

@@ -0,0 +1,42 @@
+# 编译前请先设置参数
+sys_root=$DRAGONOS_SYSROOT
+binutils_path=请填写binutils的路径
+
+# 要安装到的目录
+PREFIX=$HOME/opt/dragonos-host-userspace
+
+
+if [ ! -d ${binutils_path} ]; then
+    echo "Error: ${binutils_path} not found"
+    exit 1
+fi
+
+if [ ! -d ${sysroot} ]; then
+    echo "Error: ${sysroot} not found"
+    exit 1
+fi
+
+
+mkdir -p build-binutils || exit 1
+mkdir -p ${PREFIX} || exit 1
+
+# 安装依赖
+# 注意texinfo和binutils的版本是否匹配
+# 注意gmp/mpc/mpfr和gcc/g++的版本是否匹配
+sudo apt-get install -y \
+    g++ \
+    gcc \
+    make \
+    texinfo \
+    libgmp3-dev \
+    libmpc-dev \
+    libmpfr-dev \
+    flex \
+    wget
+
+cd build-binutils
+${binutils_path}/configure --prefix=${PREFIX} --target=x86_64-dragonos --with-sysroot=${sysroot} --disable-werror || exit 1
+make -j $(nproc) || exit 1
+make install || exit 1
+make clean || exit 1
+rm -rf build-binutils

+ 1 - 0
user/port/binutils/2.38/run.sh

@@ -0,0 +1 @@
+docker run --rm -it -v $PWD:/workdir -w /workdir binutils-2.38

+ 17 - 0
user/port/build.sh

@@ -0,0 +1,17 @@
+source pkg-config.sh
+path=(
+    gmp/6.2.1
+    mpfr/4.1.1
+    mpc/1.2.1
+    flex/2.6.4
+)
+
+current_path=$(pwd)
+
+for i in ${path[@]}; do
+    echo "Building $i"
+    cd $i
+    ./build.sh || exit 1
+    cd $current_path
+done
+cd $current_path

+ 1 - 0
user/port/flex/2.6.4/.gitignore

@@ -0,0 +1 @@
+build/

+ 37 - 0
user/port/flex/2.6.4/build.sh

@@ -0,0 +1,37 @@
+
+# 编译前请先设置参数
+sys_root=$DRAGONOS_SYSROOT
+src_path=请填写flex的路径
+
+current_path=$(pwd)
+# 要安装到的目录
+PREFIX=/usr
+
+
+if [ ! -d ${src_path} ]; then
+    echo "Error: ${src_path} not found"
+    exit 1
+fi
+
+if [ ! -d ${sysroot} ]; then
+    echo "Error: ${sysroot} not found"
+    exit 1
+fi
+
+cd ${src_path}
+autoreconf --install
+autoconf
+sed -i 's/ios[*]/ios* | dragonos* /' build-aux/config.sub
+
+cd ${current_path}
+
+mkdir -p build || exit 1
+mkdir -p ${PREFIX} || exit 1
+
+cd build
+${src_path}/configure --prefix=${PREFIX} --host=x86_64-dragonos || exit 1
+make -j $(nproc) || exit 1
+make DESTDIR=${sys_root} install|| exit 1
+make clean
+cd ..
+rm -rf build

+ 1 - 0
user/port/gcc/11.3.0/.gitignore

@@ -0,0 +1 @@
+build-gcc/

+ 51 - 0
user/port/gcc/11.3.0/build-hosted.sh

@@ -0,0 +1,51 @@
+##############################################
+# DragonOS hosted gcc build script
+#
+# This script is used to build userland gcc for DragonOS(Running on Linux)
+##############################################
+
+# 编译前请先设置参数
+sys_root=$DRAGONOS_SYSROOT
+gcc_path=请填写gcc的路径
+
+# 要安装到的目录
+PREFIX=$HOME/opt/dragonos-host-userspace
+
+
+if [ ! -d ${gcc_path} ]; then
+    echo "Error: ${gcc_path} not found"
+    exit 1
+fi
+
+if [ ! -d ${sysroot} ]; then
+    echo "Error: ${sysroot} not found"
+    exit 1
+fi
+
+# 安装依赖
+# 注意texinfo和binutils的版本是否匹配
+# 注意gmp/mpc/mpfr和gcc/g++的版本是否匹配
+sudo apt-get install -y \
+    g++ \
+    gcc \
+    make \
+    texinfo \
+    libgmp3-dev \
+    libmpc-dev \
+    libmpfr-dev \
+    flex \
+    wget
+
+mkdir -p build-gcc || exit 1
+mkdir -p ${PREFIX} || exit 1
+
+cd build-gcc
+${gcc_path}/configure --prefix=${PREFIX} --target=x86_64-dragonos --with-sysroot=${sysroot} --disable-werror --disable-shared --disable-bootstrap --enable-languages=c,c++ || exit 1
+make all-gcc all-target-libgcc -j $(nproc) || exit 1
+make install-gcc install-target-libgcc -j $(nproc)  || exit 1
+# 这里会报错,暂时不知道为什么
+# make all-target-libstdc++-v3 -j $(nproc) || exit 1
+# make install-target-libstdc++-v3 -j $(nproc) || exit 1
+make clean
+cd ..
+rm -rf build-gcc

+ 28 - 0
user/port/gmp/6.2.1/build.sh

@@ -0,0 +1,28 @@
+# 编译前请先设置参数
+sys_root=$DRAGONOS_SYSROOT
+gmp_path=请填写gmp的路径
+
+# 要安装到的目录
+PREFIX=/usr
+
+
+if [ ! -d ${gmp_path} ]; then
+    echo "Error: ${gmp_path} not found"
+    exit 1
+fi
+
+if [ ! -d ${sysroot} ]; then
+    echo "Error: ${sysroot} not found"
+    exit 1
+fi
+
+mkdir -p build-gmp || exit 1
+mkdir -p ${PREFIX} || exit 1
+
+cd build-gmp
+${gmp_path}/configure --prefix=${PREFIX} --host=x86_64-dragonos  || exit 1
+make -j $(nproc) || exit 1
+make DESTDIR=${sys_root} install|| exit 1
+make clean
+cd ..
+rm -rf build-gmp

+ 35 - 0
user/port/mpc/1.2.1/build.sh

@@ -0,0 +1,35 @@
+# 编译前请先设置参数
+sys_root=$DRAGONOS_SYSROOT
+mpc_path=请填写mpc的路径
+
+# 要安装到的目录
+PREFIX=/usr
+current_path=$(pwd)
+
+if [ ! -d ${mpc_path} ]; then
+    echo "Error: ${mpc_path} not found"
+    exit 1
+fi
+
+if [ ! -d ${sysroot} ]; then
+    echo "Error: ${sysroot} not found"
+    exit 1
+fi
+
+cd ${mpc_path}
+autoreconf --install || exit 1
+autoconf
+sed -i 's/ios[*]/ios* | dragonos* /' build-aux/config.sub
+
+cd ${current_path}
+
+mkdir -p build || exit 1
+mkdir -p ${PREFIX} || exit 1
+
+cd build
+${mpc_path}/configure --prefix=${PREFIX} --host=x86_64-dragonos --target=x86_64-dragonos --with-mpfr=$sys_root/usr --with-gmp=$sys_root/usr || exit 1
+make -j $(nproc) || exit 1
+make DESTDIR=${sys_root} install || exit 1
+make clean
+cd ..
+rm -rf build

+ 37 - 0
user/port/mpfr/4.1.1/build.sh

@@ -0,0 +1,37 @@
+
+# 编译前请先设置参数
+sys_root=$DRAGONOS_SYSROOT
+src_path=请填写mpfr的路径
+
+current_path=$(pwd)
+# 要安装到的目录
+PREFIX=/usr
+
+
+if [ ! -d ${src_path} ]; then
+    echo "Error: ${src_path} not found"
+    exit 1
+fi
+
+if [ ! -d ${sysroot} ]; then
+    echo "Error: ${sysroot} not found"
+    exit 1
+fi
+
+cd ${src_path}
+autoreconf --install
+autoconf
+sed -i 's/ios[*]/ios* | dragonos* /' config.sub
+
+cd ${current_path}
+
+mkdir -p build || exit 1
+mkdir -p ${PREFIX} || exit 1
+
+cd build
+${src_path}/configure --prefix=${PREFIX} --host=x86_64-dragonos  || exit 1
+make -j $(nproc) || exit 1
+make DESTDIR=${sys_root} install|| exit 1
+make clean
+cd ..
+rm -rf build

+ 15 - 0
user/port/pkg-config.sh

@@ -0,0 +1,15 @@
+#!/bin/sh
+# Fill these in appropriately:
+ROOT_PATH=$(dirname $(dirname $(pwd)))
+DRAGONOS_SYSROOT=$ROOT_PATH/bin/sysroot
+
+
+
+export PKG_CONFIG_SYSROOT_DIR=$DRAGONOS_SYSROOT
+export PKG_CONFIG_LIBDIR=$DRAGONOS_SYSROOT/usr/lib/pkgconfig
+# TODO: If it works this should probably just be set to the empty string.
+# export PKG_CONFIG_PATH=$PKG_CONFIG_LIBDIR
+# Use --static here if your OS only has static linking.
+# TODO: Perhaps it's a bug in the libraries if their pkg-config files doesn't
+#       record that only static libraries were built.
+# exec pkg-config --static "$@"