Browse Source

feat(gblibc): set entry point to _start

greatbridf 2 years ago
parent
commit
90b868a5cf

+ 1 - 0
gblibc/CMakeLists.txt

@@ -5,6 +5,7 @@ add_library(gblibc STATIC
     src/stdio.c
     src/arithmetic.c
     src/string.c
+    src/crt0.s
 )
 
 target_include_directories(gblibc PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include

+ 27 - 0
gblibc/src/crt0.s

@@ -0,0 +1,27 @@
+.code32
+
+.text
+
+# TODO: call .init and .fini, initialize c standard library
+.globl _start
+.type  _start @function
+_start:
+    movl (%esp), %eax   # argc
+    leal 4(%esp), %ecx  # argv
+    movl %esp, %edx
+
+    andl $0xfffffff0, %esp
+
+    pushl %edx
+    pushl $0
+
+    movl %esp, %ebp
+
+    pushl %ecx
+    pushl %eax
+
+    call main
+
+    movl %eax, %edi  # code
+    movl $0x05, %eax # SYS_exit
+    int $0x80        # syscall

+ 2 - 1
include/types/elf.hpp

@@ -111,7 +111,8 @@ struct PACKED elf32_program_header_entry {
 
 struct elf32_load_data {
     const char* exec;
-    const char** argv;
+    const char* const* argv;
+    const char* const* envp;
     int errcode;
     void* eip;
     uint32_t* sp;

+ 2 - 0
src/kernel/process.cpp

@@ -167,10 +167,12 @@ void NORETURN _kernel_init(void)
     current_thread->attr.system = 0;
 
     const char* argv[] = { "/mnt/INIT.ELF", nullptr };
+    const char* envp[] = { nullptr };
 
     types::elf::elf32_load_data d;
     d.exec = "/mnt/INIT.ELF";
     d.argv = argv;
+    d.envp = envp;
     d.system = false;
 
     assert(types::elf::elf32_load(&d) == GB_OK);

+ 4 - 3
src/kernel/syscall.cpp

@@ -131,15 +131,16 @@ void _syscall_crash(interrupt_stack*)
 // syscall_exec(const char* exec, const char** argv)
 // @param exec: the path of program to execute
 // @param argv: arguments end with nullptr
+// @param envp: environment variables end with nullptr
 void _syscall_exec(interrupt_stack* data)
 {
     const char* exec = reinterpret_cast<const char*>(data->s_regs.edi);
-    const char** argv = reinterpret_cast<const char**>(data->s_regs.esi);
-
-    current_process->mms.clear_user();
+    char* const* argv = reinterpret_cast<char* const*>(data->s_regs.esi);
+    char* const* envp = reinterpret_cast<char* const*>(data->s_regs.edx);
 
     types::elf::elf32_load_data d;
     d.argv = argv;
+    d.envp = envp;
     d.exec = exec;
     d.system = false;
 

+ 62 - 15
src/types/elf.cpp

@@ -1,15 +1,29 @@
 #include <kernel/errno.h>
+#include <kernel/mem.h>
 #include <stdint.h>
 #include <stdio.h>
+#include <string.h>
 #include <types/assert.h>
 #include <types/elf.hpp>
+#include <types/string.hpp>
+#include <types/vector.hpp>
+
+#define align16_down(sp) (sp = ((char*)((uint32_t)(sp)&0xfffffff0)))
 
 template <typename T>
-constexpr void _user_push(uint32_t** sp, T d)
+inline void _user_push(char** sp, T d)
 {
     *sp -= sizeof(T);
     *(T*)*sp = d;
 }
+template <>
+inline void _user_push(char** sp, const char* str)
+{
+    size_t len = strlen(str);
+    *sp -= (len + 1);
+    align16_down(*sp);
+    memcpy(*sp, str, len + 1);
+}
 
 int types::elf::elf32_load(types::elf::elf32_load_data* d)
 {
@@ -42,16 +56,34 @@ int types::elf::elf32_load(types::elf::elf32_load_data* d)
 
     // broken file or I/O error
     if (n_read != phents_size) {
+        k_free(phents);
+
         d->errcode = EINVAL;
         return GB_FAILED;
     }
 
+    // copy argv and envp
+    vector<string<>> argv, envp;
+    for (const char* const* p = d->argv; *p; ++p)
+        argv.emplace_back(*p);
+    for (const char* const* p = d->envp; *p; ++p)
+        envp.emplace_back(*p);
+
+    // from now on, caller process is recycled.
+    // so we can't just simply return to it on error.
+    current_process->mms.clear_user();
+
     for (int i = 0; i < hdr.phnum; ++i) {
         if (phents->type != types::elf::elf32_program_header_entry::PT_LOAD)
             continue;
 
         auto ret = mmap((void*)phents->vaddr, phents->memsz, ent_exec->ind, phents->offset, 1, d->system);
         if (ret != GB_OK) {
+            k_free(phents);
+
+            // TODO: kill process
+            assert(false);
+
             d->errcode = ret;
             return GB_FAILED;
         }
@@ -60,31 +92,46 @@ int types::elf::elf32_load(types::elf::elf32_load_data* d)
     }
 
     // map stack area
-    auto ret = mmap((void*)types::elf::ELF_STACK_TOP, types::elf::ELF_STACK_SIZE, fs::vfs_open("/dev/null")->ind, 0, 1, 0);
+    auto ret = mmap((void*)types::elf::ELF_STACK_TOP, types::elf::ELF_STACK_SIZE,
+        fs::vfs_open("/dev/null")->ind, 0, 1, 0);
     assert_likely(ret == GB_OK);
 
     d->eip = (void*)hdr.entry;
     d->sp = reinterpret_cast<uint32_t*>(types::elf::ELF_STACK_BOTTOM);
 
-    auto* sp = &d->sp;
+    auto* sp = (char**)&d->sp;
 
-    types::vector<const char*> arr;
-    for (const char** ptr = d->argv; *ptr != nullptr; ++ptr) {
-        auto len = strlen(*ptr);
-        *sp -= (len + 1);
-        *sp = (uint32_t*)((uint32_t)*sp & 0xfffffff0);
-        memcpy((char*)*sp, *ptr, len + 1);
-        arr.push_back((const char*)*sp);
+    // fill information block area
+    vector<char*> args, envs;
+    for (const auto& env : envp) {
+        _user_push(sp, env.c_str());
+        envs.push_back(*sp);
+    }
+    for (const auto& arg : argv) {
+        _user_push(sp, arg.c_str());
+        args.push_back(*sp);
     }
 
-    *sp -= sizeof(const char*) * arr.size();
-    *sp = (uint32_t*)((uint32_t)*sp & 0xfffffff0);
-    memcpy((char*)*sp, arr.data(), sizeof(const char*) * arr.size());
+    // push null auxiliary vector entry
+    _user_push(sp, 0);
+    _user_push(sp, 0);
 
+    // push 0 for envp
     _user_push(sp, 0);
+
+    // push envp
+    *sp -= sizeof(void*) * envs.size();
+    memcpy(*sp, envs.data(), sizeof(void*) * envs.size());
+
+    // push 0 for argv
     _user_push(sp, 0);
-    _user_push(sp, *sp + 8);
-    _user_push(sp, arr.size());
+
+    // push argv
+    *sp -= sizeof(void*) * args.size();
+    memcpy(*sp, args.data(), sizeof(void*) * args.size());
+
+    // push argc
+    _user_push(sp, args.size());
 
     return GB_OK;
 }

+ 1 - 1
user-space-program/CMakeLists.txt

@@ -5,7 +5,7 @@ set(CMAKE_C_FLAGS "-nostdinc -nostdlib -static -m32 -W -Wall -Wextra -Werror -ms
 set(CMAKE_ASM_FLAGS "-m32 -static -mstack-protector-guard=global -g0")
 
 link_libraries(gblibc)
-add_link_options(-nostdlib -e main -Ttext 0x40000000 -T ${CMAKE_CURRENT_SOURCE_DIR}/script.ld)
+add_link_options(-nostdlib -Ttext 0x40000000 -T ${CMAKE_CURRENT_SOURCE_DIR}/script.ld)
 # set(LINK_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/script.ld)
 
 set(CMAKE_C_IMPLICIT_LINK_DIRECTORIES "")

+ 2 - 0
user-space-program/script.ld

@@ -1,6 +1,8 @@
 OUTPUT_FORMAT(elf32-i386)
 OUTPUT_ARCH(i386:i386)
 
+ENTRY(_start)
+
 MEMORY
 {
     MEM : org = 0x40000000, l = 3072M