Kernel/LibC/DynamicLoader: Update process start ABI
We now use SysV abi for process startup
This commit is contained in:
parent
e6026cb0b8
commit
36baf7b0af
|
@ -41,15 +41,6 @@ start_userspace_thread:
|
||||||
call get_thread_start_sp
|
call get_thread_start_sp
|
||||||
movl %eax, %esp
|
movl %eax, %esp
|
||||||
|
|
||||||
# STACK LAYOUT
|
|
||||||
# entry
|
|
||||||
# argc
|
|
||||||
# argv
|
|
||||||
# envp
|
|
||||||
# userspace stack
|
|
||||||
|
|
||||||
call get_userspace_thread_stack_top
|
|
||||||
|
|
||||||
movw $(0x20 | 3), %bx
|
movw $(0x20 | 3), %bx
|
||||||
movw %bx, %ds
|
movw %bx, %ds
|
||||||
movw %bx, %es
|
movw %bx, %es
|
||||||
|
@ -57,15 +48,4 @@ start_userspace_thread:
|
||||||
movw %bx, %gs
|
movw %bx, %gs
|
||||||
xorw %bx, %bx
|
xorw %bx, %bx
|
||||||
|
|
||||||
popl %edi
|
|
||||||
popl %esi
|
|
||||||
popl %edx
|
|
||||||
popl %ecx
|
|
||||||
popl %ebx
|
|
||||||
|
|
||||||
pushl $(0x20 | 3)
|
|
||||||
pushl %eax
|
|
||||||
pushl $0x202
|
|
||||||
pushl $(0x18 | 3)
|
|
||||||
pushl %ebx
|
|
||||||
iret
|
iret
|
||||||
|
|
|
@ -32,24 +32,4 @@ start_userspace_thread:
|
||||||
call get_thread_start_sp
|
call get_thread_start_sp
|
||||||
movq %rax, %rsp
|
movq %rax, %rsp
|
||||||
|
|
||||||
# STACK LAYOUT
|
|
||||||
# entry
|
|
||||||
# argc
|
|
||||||
# argv
|
|
||||||
# envp
|
|
||||||
# userspace stack
|
|
||||||
|
|
||||||
call get_userspace_thread_stack_top
|
|
||||||
|
|
||||||
popq %rdi
|
|
||||||
popq %rsi
|
|
||||||
popq %rdx
|
|
||||||
popq %rcx
|
|
||||||
popq %rbx
|
|
||||||
|
|
||||||
pushq $(0x20 | 3)
|
|
||||||
pushq %rax
|
|
||||||
pushq $0x202
|
|
||||||
pushq $(0x18 | 3)
|
|
||||||
pushq %rbx
|
|
||||||
iretq
|
iretq
|
||||||
|
|
|
@ -34,15 +34,6 @@ namespace Kernel
|
||||||
public:
|
public:
|
||||||
using entry_t = Thread::entry_t;
|
using entry_t = Thread::entry_t;
|
||||||
|
|
||||||
struct userspace_info_t
|
|
||||||
{
|
|
||||||
uintptr_t entry { 0 };
|
|
||||||
int argc { 0 };
|
|
||||||
char** argv { nullptr };
|
|
||||||
char** envp { nullptr };
|
|
||||||
int file_fd { -1 };
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static Process* create_kernel();
|
static Process* create_kernel();
|
||||||
static Process* create_kernel(entry_t, void*);
|
static Process* create_kernel(entry_t, void*);
|
||||||
|
@ -183,7 +174,7 @@ namespace Kernel
|
||||||
BAN::ErrorOr<long> sys_sigprocmask(int how, const sigset_t* set, sigset_t* oset);
|
BAN::ErrorOr<long> sys_sigprocmask(int how, const sigset_t* set, sigset_t* oset);
|
||||||
|
|
||||||
BAN::ErrorOr<long> sys_yield();
|
BAN::ErrorOr<long> sys_yield();
|
||||||
BAN::ErrorOr<long> sys_pthread_create(const pthread_attr_t* __restrict attr, void (*entry)(void*), void* arg);
|
BAN::ErrorOr<long> sys_pthread_create(const pthread_attr_t* attr, void (*entry)(void*), void* arg);
|
||||||
BAN::ErrorOr<long> sys_pthread_exit(void* value);
|
BAN::ErrorOr<long> sys_pthread_exit(void* value);
|
||||||
BAN::ErrorOr<long> sys_pthread_join(pthread_t thread, void** value);
|
BAN::ErrorOr<long> sys_pthread_join(pthread_t thread, void** value);
|
||||||
BAN::ErrorOr<long> sys_pthread_self();
|
BAN::ErrorOr<long> sys_pthread_self();
|
||||||
|
@ -208,7 +199,6 @@ namespace Kernel
|
||||||
size_t proc_environ(off_t offset, BAN::ByteSpan) const;
|
size_t proc_environ(off_t offset, BAN::ByteSpan) const;
|
||||||
|
|
||||||
bool is_userspace() const { return m_is_userspace; }
|
bool is_userspace() const { return m_is_userspace; }
|
||||||
const userspace_info_t& userspace_info() const { return m_userspace_info; }
|
|
||||||
|
|
||||||
// Returns error if page could not be allocated
|
// Returns error if page could not be allocated
|
||||||
// Returns true if the page was allocated successfully
|
// Returns true if the page was allocated successfully
|
||||||
|
@ -315,7 +305,6 @@ namespace Kernel
|
||||||
BAN::Vector<BAN::String> m_environ;
|
BAN::Vector<BAN::String> m_environ;
|
||||||
|
|
||||||
bool m_is_userspace { false };
|
bool m_is_userspace { false };
|
||||||
userspace_info_t m_userspace_info;
|
|
||||||
|
|
||||||
SpinLock m_child_exit_lock;
|
SpinLock m_child_exit_lock;
|
||||||
BAN::Vector<ChildExitStatus> m_child_exit_statuses;
|
BAN::Vector<ChildExitStatus> m_child_exit_statuses;
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
#include <kernel/Memory/VirtualRange.h>
|
#include <kernel/Memory/VirtualRange.h>
|
||||||
#include <kernel/ThreadBlocker.h>
|
#include <kernel/ThreadBlocker.h>
|
||||||
|
|
||||||
|
#include <LibELF/AuxiliaryVector.h>
|
||||||
|
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
@ -41,9 +43,10 @@ namespace Kernel
|
||||||
BAN::ErrorOr<Thread*> pthread_create(entry_t, void*);
|
BAN::ErrorOr<Thread*> pthread_create(entry_t, void*);
|
||||||
|
|
||||||
BAN::ErrorOr<Thread*> clone(Process*, uintptr_t sp, uintptr_t ip);
|
BAN::ErrorOr<Thread*> clone(Process*, uintptr_t sp, uintptr_t ip);
|
||||||
void setup_exec();
|
|
||||||
void setup_process_cleanup();
|
void setup_process_cleanup();
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> initialize_userspace(vaddr_t entry, BAN::Span<BAN::String> argv, BAN::Span<BAN::String> envp, BAN::Span<LibELF::AuxiliaryVector> auxv);
|
||||||
|
|
||||||
// Returns true, if thread is going to trigger signal
|
// Returns true, if thread is going to trigger signal
|
||||||
bool is_interrupted_by_signal() const;
|
bool is_interrupted_by_signal() const;
|
||||||
|
|
||||||
|
@ -100,7 +103,7 @@ namespace Kernel
|
||||||
private:
|
private:
|
||||||
Thread(pid_t tid, Process*);
|
Thread(pid_t tid, Process*);
|
||||||
|
|
||||||
void setup_exec_impl(uintptr_t entry, uintptr_t arg0, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3);
|
void setup_exec(vaddr_t ip, vaddr_t sp);
|
||||||
|
|
||||||
static void on_exit_trampoline(Thread*);
|
static void on_exit_trampoline(Thread*);
|
||||||
void on_exit();
|
void on_exit();
|
||||||
|
|
|
@ -248,11 +248,7 @@ namespace Kernel
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Thread::current().has_process() && Process::current().is_userspace())
|
if (Thread::current().has_process() && Process::current().is_userspace())
|
||||||
{
|
process_name = Process::current().name();
|
||||||
const char* const* argv = Process::current().userspace_info().argv;
|
|
||||||
if (argv && *argv)
|
|
||||||
process_name = *argv;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if ARCH(x86_64)
|
#if ARCH(x86_64)
|
||||||
dwarnln(
|
dwarnln(
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
#include <kernel/Terminal/PseudoTerminal.h>
|
#include <kernel/Terminal/PseudoTerminal.h>
|
||||||
#include <kernel/Timer/Timer.h>
|
#include <kernel/Timer/Timer.h>
|
||||||
|
|
||||||
|
#include <LibELF/AuxiliaryVector.h>
|
||||||
|
|
||||||
#include <LibInput/KeyboardLayout.h>
|
#include <LibInput/KeyboardLayout.h>
|
||||||
|
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
@ -116,76 +118,51 @@ namespace Kernel
|
||||||
process->m_working_directory = VirtualFileSystem::get().root_file();
|
process->m_working_directory = VirtualFileSystem::get().root_file();
|
||||||
process->m_page_table = BAN::UniqPtr<PageTable>::adopt(MUST(PageTable::create_userspace()));
|
process->m_page_table = BAN::UniqPtr<PageTable>::adopt(MUST(PageTable::create_userspace()));
|
||||||
|
|
||||||
TRY(process->m_cmdline.push_back({}));
|
TRY(process->m_cmdline.emplace_back());
|
||||||
TRY(process->m_cmdline.back().append(path));
|
TRY(process->m_cmdline.back().append(path));
|
||||||
|
for (auto argument : arguments)
|
||||||
|
{
|
||||||
|
TRY(process->m_cmdline.emplace_back());
|
||||||
|
TRY(process->m_cmdline.back().append(argument));
|
||||||
|
}
|
||||||
|
|
||||||
LockGuard _(process->m_process_lock);
|
LockGuard _(process->m_process_lock);
|
||||||
|
|
||||||
auto executable_inode = TRY(process->find_file(AT_FDCWD, path.data(), O_EXEC)).inode;
|
auto executable_file = TRY(process->find_file(AT_FDCWD, path.data(), O_EXEC));
|
||||||
|
auto executable_inode = executable_file.inode;
|
||||||
|
|
||||||
auto executable = TRY(ELF::load_from_inode(executable_inode, process->m_credentials, process->page_table()));
|
auto executable = TRY(ELF::load_from_inode(executable_inode, process->m_credentials, process->page_table()));
|
||||||
process->m_mapped_regions = BAN::move(executable.regions);
|
process->m_mapped_regions = BAN::move(executable.regions);
|
||||||
|
|
||||||
char** argv_addr = nullptr;
|
|
||||||
{
|
|
||||||
size_t needed_bytes = sizeof(char*) + path.size() + 1;
|
|
||||||
for (auto argument : arguments)
|
|
||||||
needed_bytes += sizeof(char*) + argument.size() + 1;
|
|
||||||
needed_bytes += sizeof(char*);
|
|
||||||
|
|
||||||
if (auto rem = needed_bytes % PAGE_SIZE)
|
|
||||||
needed_bytes += PAGE_SIZE - rem;
|
|
||||||
|
|
||||||
auto argv_region = MUST(MemoryBackedRegion::create(
|
|
||||||
process->page_table(),
|
|
||||||
needed_bytes,
|
|
||||||
{ .start = 0x400000, .end = KERNEL_OFFSET },
|
|
||||||
MemoryRegion::Type::PRIVATE,
|
|
||||||
PageTable::Flags::UserSupervisor | PageTable::Flags::Present
|
|
||||||
));
|
|
||||||
argv_addr = reinterpret_cast<char**>(argv_region->vaddr());
|
|
||||||
|
|
||||||
uintptr_t offset = sizeof(char*) * (1 + arguments.size() + 1);
|
|
||||||
for (size_t i = 0; i <= arguments.size(); i++)
|
|
||||||
{
|
|
||||||
const uintptr_t addr = argv_region->vaddr() + offset;
|
|
||||||
TRY(argv_region->copy_data_to_region(i * sizeof(char*), reinterpret_cast<const uint8_t*>(&addr), sizeof(char*)));
|
|
||||||
|
|
||||||
const auto current = (i == 0) ? path : arguments[i - 1];
|
|
||||||
TRY(argv_region->copy_data_to_region(offset, reinterpret_cast<const uint8_t*>(current.data()), current.size()));
|
|
||||||
|
|
||||||
const uint8_t zero = 0;
|
|
||||||
TRY(argv_region->copy_data_to_region(offset + current.size(), &zero, 1));
|
|
||||||
|
|
||||||
offset += current.size() + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
const uintptr_t zero = 0;
|
|
||||||
TRY(argv_region->copy_data_to_region((1 + arguments.size()) * sizeof(char*), reinterpret_cast<const uint8_t*>(&zero), sizeof(char*)));
|
|
||||||
|
|
||||||
TRY(process->m_mapped_regions.push_back(BAN::move(argv_region)));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (executable_inode->mode().mode & +Inode::Mode::ISUID)
|
if (executable_inode->mode().mode & +Inode::Mode::ISUID)
|
||||||
process->m_credentials.set_euid(executable_inode->uid());
|
process->m_credentials.set_euid(executable_inode->uid());
|
||||||
if (executable_inode->mode().mode & +Inode::Mode::ISGID)
|
if (executable_inode->mode().mode & +Inode::Mode::ISGID)
|
||||||
process->m_credentials.set_egid(executable_inode->gid());
|
process->m_credentials.set_egid(executable_inode->gid());
|
||||||
|
|
||||||
|
BAN::Vector<LibELF::AuxiliaryVector> auxiliary_vector;
|
||||||
|
TRY(auxiliary_vector.reserve(1 + executable.open_execfd));
|
||||||
|
|
||||||
if (executable.has_interpreter)
|
if (executable.has_interpreter)
|
||||||
{
|
{
|
||||||
VirtualFileSystem::File file;
|
const int execfd = TRY(process->m_open_file_descriptors.open(BAN::move(executable_file), O_RDONLY));
|
||||||
TRY(file.canonical_path.append("<self>"));
|
TRY(auxiliary_vector.push_back({
|
||||||
file.inode = executable_inode;
|
.a_type = LibELF::AT_EXECFD,
|
||||||
process->m_userspace_info.file_fd = TRY(process->m_open_file_descriptors.open(BAN::move(file), O_RDONLY));
|
.a_un = { .a_val = static_cast<uint32_t>(execfd) },
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
process->m_is_userspace = true;
|
TRY(auxiliary_vector.push_back({
|
||||||
process->m_userspace_info.entry = executable.entry_point;
|
.a_type = LibELF::AT_NULL,
|
||||||
process->m_userspace_info.argc = 1 + arguments.size();
|
.a_un = { .a_val = 0 },
|
||||||
process->m_userspace_info.argv = argv_addr;
|
}));
|
||||||
process->m_userspace_info.envp = nullptr;
|
|
||||||
|
|
||||||
auto* thread = MUST(Thread::create_userspace(process, process->page_table()));
|
auto* thread = MUST(Thread::create_userspace(process, process->page_table()));
|
||||||
thread->setup_exec();
|
MUST(thread->initialize_userspace(
|
||||||
|
executable.entry_point,
|
||||||
|
process->m_cmdline.span(),
|
||||||
|
process->m_environ.span(),
|
||||||
|
auxiliary_vector.span()
|
||||||
|
));
|
||||||
|
|
||||||
process->add_thread(thread);
|
process->add_thread(thread);
|
||||||
process->register_to_scheduler();
|
process->register_to_scheduler();
|
||||||
|
@ -534,7 +511,6 @@ namespace Kernel
|
||||||
forked->m_open_file_descriptors = BAN::move(*open_file_descriptors);
|
forked->m_open_file_descriptors = BAN::move(*open_file_descriptors);
|
||||||
forked->m_mapped_regions = BAN::move(mapped_regions);
|
forked->m_mapped_regions = BAN::move(mapped_regions);
|
||||||
forked->m_is_userspace = m_is_userspace;
|
forked->m_is_userspace = m_is_userspace;
|
||||||
forked->m_userspace_info = m_userspace_info;
|
|
||||||
forked->m_has_called_exec = false;
|
forked->m_has_called_exec = false;
|
||||||
memcpy(forked->m_signal_handlers, m_signal_handlers, sizeof(m_signal_handlers));
|
memcpy(forked->m_signal_handlers, m_signal_handlers, sizeof(m_signal_handlers));
|
||||||
|
|
||||||
|
@ -561,77 +537,62 @@ namespace Kernel
|
||||||
|
|
||||||
TRY(validate_string_access(path));
|
TRY(validate_string_access(path));
|
||||||
|
|
||||||
auto executable_file = TRY(find_file(AT_FDCWD, path, O_EXEC));
|
|
||||||
auto executable_inode = executable_file.inode;
|
|
||||||
|
|
||||||
BAN::Vector<BAN::String> str_argv;
|
BAN::Vector<BAN::String> str_argv;
|
||||||
for (int i = 0; argv && argv[i]; i++)
|
for (int i = 0; argv && argv[i]; i++)
|
||||||
{
|
{
|
||||||
TRY(validate_pointer_access(argv + i, sizeof(char*), false));
|
TRY(validate_pointer_access(argv + i, sizeof(char*), false));
|
||||||
TRY(validate_string_access(argv[i]));
|
TRY(validate_string_access(argv[i]));
|
||||||
TRY(str_argv.emplace_back(argv[i]));
|
TRY(str_argv.emplace_back());
|
||||||
|
TRY(str_argv.back().append(argv[i]));
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::Vector<BAN::String> str_envp;
|
BAN::Vector<BAN::String> str_envp;
|
||||||
for (int i = 0; envp && envp[i]; i++)
|
for (int i = 0; envp && envp[i]; i++)
|
||||||
{
|
{
|
||||||
TRY(validate_pointer_access(envp + 1, sizeof(char*), false));
|
TRY(validate_pointer_access(envp + i, sizeof(char*), false));
|
||||||
TRY(validate_string_access(envp[i]));
|
TRY(validate_string_access(envp[i]));
|
||||||
TRY(str_envp.emplace_back(envp[i]));
|
TRY(str_envp.emplace_back());
|
||||||
|
TRY(str_envp.back().append(envp[i]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto executable_file = TRY(find_file(AT_FDCWD, path, O_EXEC));
|
||||||
|
auto executable_inode = executable_file.inode;
|
||||||
|
|
||||||
auto executable = TRY(ELF::load_from_inode(executable_inode, m_credentials, *new_page_table));
|
auto executable = TRY(ELF::load_from_inode(executable_inode, m_credentials, *new_page_table));
|
||||||
auto new_mapped_regions = BAN::move(executable.regions);
|
auto new_mapped_regions = BAN::move(executable.regions);
|
||||||
|
|
||||||
int file_fd = -1;
|
BAN::Vector<LibELF::AuxiliaryVector> auxiliary_vector;
|
||||||
|
TRY(auxiliary_vector.reserve(1 + executable.open_execfd));
|
||||||
|
|
||||||
|
BAN::ScopeGuard execfd_guard([this, &auxiliary_vector] {
|
||||||
|
if (auxiliary_vector.empty())
|
||||||
|
return;
|
||||||
|
if (auxiliary_vector.front().a_type != LibELF::AT_EXECFD)
|
||||||
|
return;
|
||||||
|
MUST(m_open_file_descriptors.close(auxiliary_vector.front().a_un.a_val));
|
||||||
|
});
|
||||||
|
|
||||||
if (executable.has_interpreter)
|
if (executable.has_interpreter)
|
||||||
{
|
{
|
||||||
VirtualFileSystem::File file;
|
const int execfd = TRY(m_open_file_descriptors.open(BAN::move(executable_file), O_RDONLY));
|
||||||
file.canonical_path = BAN::move(executable_file.canonical_path);
|
TRY(auxiliary_vector.push_back({
|
||||||
file.inode = executable_inode;
|
.a_type = LibELF::AT_EXECFD,
|
||||||
file_fd = TRY(m_open_file_descriptors.open(BAN::move(file), O_RDONLY));
|
.a_un = { .a_val = static_cast<uint32_t>(execfd) },
|
||||||
}
|
}));
|
||||||
BAN::ScopeGuard file_closer([&] { if (file_fd != -1) MUST(m_open_file_descriptors.close(file_fd)); });
|
|
||||||
|
|
||||||
// allocate memory on the new process for arguments and environment
|
|
||||||
auto create_region =
|
|
||||||
[&](BAN::Span<BAN::String> container) -> BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>>
|
|
||||||
{
|
|
||||||
size_t bytes = sizeof(char*);
|
|
||||||
for (auto& elem : container)
|
|
||||||
bytes += sizeof(char*) + elem.size() + 1;
|
|
||||||
|
|
||||||
if (auto rem = bytes % PAGE_SIZE)
|
|
||||||
bytes += PAGE_SIZE - rem;
|
|
||||||
|
|
||||||
auto region = TRY(MemoryBackedRegion::create(
|
|
||||||
*new_page_table,
|
|
||||||
bytes,
|
|
||||||
{ .start = executable.entry_point, .end = KERNEL_OFFSET },
|
|
||||||
MemoryRegion::Type::PRIVATE,
|
|
||||||
PageTable::Flags::UserSupervisor | PageTable::Flags::ReadWrite | PageTable::Flags::Present
|
|
||||||
));
|
|
||||||
|
|
||||||
size_t data_offset = sizeof(char*) * (container.size() + 1);
|
|
||||||
for (size_t i = 0; i < container.size(); i++)
|
|
||||||
{
|
|
||||||
uintptr_t ptr_addr = region->vaddr() + data_offset;
|
|
||||||
TRY(region->copy_data_to_region(sizeof(char*) * i, (const uint8_t*)&ptr_addr, sizeof(char*)));
|
|
||||||
TRY(region->copy_data_to_region(data_offset, (const uint8_t*)container[i].data(), container[i].size()));
|
|
||||||
data_offset += container[i].size() + 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uintptr_t null = 0;
|
TRY(auxiliary_vector.push_back({
|
||||||
TRY(region->copy_data_to_region(sizeof(char*) * container.size(), (const uint8_t*)&null, sizeof(char*)));
|
.a_type = LibELF::AT_NULL,
|
||||||
|
.a_un = { .a_val = 0 },
|
||||||
return BAN::UniqPtr<MemoryRegion>(BAN::move(region));
|
}));
|
||||||
};
|
|
||||||
|
|
||||||
TRY(new_mapped_regions.reserve(new_mapped_regions.size() + 2));
|
|
||||||
MUST(new_mapped_regions.push_back(TRY(create_region(str_argv.span()))));
|
|
||||||
MUST(new_mapped_regions.push_back(TRY(create_region(str_envp.span()))));
|
|
||||||
|
|
||||||
auto* new_thread = TRY(Thread::create_userspace(this, *new_page_table));
|
auto* new_thread = TRY(Thread::create_userspace(this, *new_page_table));
|
||||||
|
TRY(new_thread->initialize_userspace(
|
||||||
|
executable.entry_point,
|
||||||
|
str_argv.span(),
|
||||||
|
str_envp.span(),
|
||||||
|
auxiliary_vector.span()
|
||||||
|
));
|
||||||
|
|
||||||
ASSERT(Processor::get_interrupt_state() == InterruptState::Enabled);
|
ASSERT(Processor::get_interrupt_state() == InterruptState::Enabled);
|
||||||
Processor::set_interrupt_state(InterruptState::Disabled);
|
Processor::set_interrupt_state(InterruptState::Disabled);
|
||||||
|
@ -655,8 +616,8 @@ namespace Kernel
|
||||||
m_threads.front()->m_process = nullptr;
|
m_threads.front()->m_process = nullptr;
|
||||||
m_threads.front()->give_keep_alive_page_table(BAN::move(m_page_table));
|
m_threads.front()->give_keep_alive_page_table(BAN::move(m_page_table));
|
||||||
|
|
||||||
|
MUST(Processor::scheduler().add_thread(new_thread));
|
||||||
m_threads.front() = new_thread;
|
m_threads.front() = new_thread;
|
||||||
MUST(Processor::scheduler().add_thread(m_threads.front()));
|
|
||||||
|
|
||||||
for (size_t i = 0; i < sizeof(m_signal_handlers) / sizeof(*m_signal_handlers); i++)
|
for (size_t i = 0; i < sizeof(m_signal_handlers) / sizeof(*m_signal_handlers); i++)
|
||||||
{
|
{
|
||||||
|
@ -673,21 +634,13 @@ namespace Kernel
|
||||||
m_mapped_regions = BAN::move(new_mapped_regions);
|
m_mapped_regions = BAN::move(new_mapped_regions);
|
||||||
m_page_table = BAN::move(new_page_table);
|
m_page_table = BAN::move(new_page_table);
|
||||||
|
|
||||||
file_closer.disable();
|
execfd_guard.disable();
|
||||||
|
|
||||||
m_userspace_info.argc = str_argv.size();
|
|
||||||
m_userspace_info.argv = reinterpret_cast<char**>(m_mapped_regions[m_mapped_regions.size() - 2]->vaddr());
|
|
||||||
m_userspace_info.envp = reinterpret_cast<char**>(m_mapped_regions[m_mapped_regions.size() - 1]->vaddr());
|
|
||||||
m_userspace_info.entry = executable.entry_point;
|
|
||||||
m_userspace_info.file_fd = file_fd;
|
|
||||||
|
|
||||||
m_cmdline = BAN::move(str_argv);
|
m_cmdline = BAN::move(str_argv);
|
||||||
m_environ = BAN::move(str_envp);
|
m_environ = BAN::move(str_envp);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_has_called_exec = true;
|
m_has_called_exec = true;
|
||||||
|
|
||||||
m_threads.front()->setup_exec();
|
|
||||||
Processor::yield();
|
Processor::yield();
|
||||||
ASSERT_NOT_REACHED();
|
ASSERT_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
@ -2084,7 +2037,7 @@ namespace Kernel
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<long> Process::sys_pthread_create(const pthread_attr_t* __restrict attr, void (*entry)(void*), void* arg)
|
BAN::ErrorOr<long> Process::sys_pthread_create(const pthread_attr_t* attr, void (*entry)(void*), void* arg)
|
||||||
{
|
{
|
||||||
if (attr != nullptr)
|
if (attr != nullptr)
|
||||||
{
|
{
|
||||||
|
|
|
@ -44,11 +44,7 @@ namespace Kernel
|
||||||
|
|
||||||
BAN::ErrorOr<long> ret = BAN::Error::from_errno(ENOSYS);
|
BAN::ErrorOr<long> ret = BAN::Error::from_errno(ENOSYS);
|
||||||
|
|
||||||
const char* process_path = nullptr;
|
const char* process_path = Process::current().name();
|
||||||
if (Process::current().userspace_info().argc > 0 && Process::current().userspace_info().argv)
|
|
||||||
process_path = Process::current().userspace_info().argv[0];
|
|
||||||
if (process_path == nullptr)
|
|
||||||
process_path = "<null>";
|
|
||||||
|
|
||||||
#if DUMP_ALL_SYSCALLS
|
#if DUMP_ALL_SYSCALLS
|
||||||
dprintln("{} pid {}: {}", process_path, Process::current().pid(), s_syscall_names[syscall]);
|
dprintln("{} pid {}: {}", process_path, Process::current().pid(), s_syscall_names[syscall]);
|
||||||
|
|
|
@ -29,11 +29,6 @@ namespace Kernel
|
||||||
return Thread::current().interrupt_stack().sp;
|
return Thread::current().interrupt_stack().sp;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" uintptr_t get_userspace_thread_stack_top()
|
|
||||||
{
|
|
||||||
return Thread::current().userspace_stack_top() - 4 * sizeof(uintptr_t);
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" void load_thread_sse()
|
extern "C" void load_thread_sse()
|
||||||
{
|
{
|
||||||
Thread::current().load_sse();
|
Thread::current().load_sse();
|
||||||
|
@ -176,11 +171,12 @@ namespace Kernel
|
||||||
save_sse();
|
save_sse();
|
||||||
memcpy(thread->m_sse_storage, m_sse_storage, sizeof(m_sse_storage));
|
memcpy(thread->m_sse_storage, m_sse_storage, sizeof(m_sse_storage));
|
||||||
|
|
||||||
thread->setup_exec_impl(
|
PageTable::with_fast_page(thread->userspace_stack().paddr_of(thread->userspace_stack_top() - PAGE_SIZE), [=] {
|
||||||
reinterpret_cast<uintptr_t>(entry),
|
PageTable::fast_page_as<void*>(PAGE_SIZE - sizeof(uintptr_t)) = arg;
|
||||||
reinterpret_cast<uintptr_t>(arg),
|
});
|
||||||
0, 0, 0
|
|
||||||
);
|
const vaddr_t entry_addr = reinterpret_cast<vaddr_t>(entry);
|
||||||
|
thread->setup_exec(entry_addr, thread->userspace_stack_top() - sizeof(uintptr_t));
|
||||||
|
|
||||||
return thread;
|
return thread;
|
||||||
}
|
}
|
||||||
|
@ -222,21 +218,112 @@ namespace Kernel
|
||||||
return thread;
|
return thread;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Thread::setup_exec()
|
BAN::ErrorOr<void> Thread::initialize_userspace(vaddr_t entry, BAN::Span<BAN::String> argv, BAN::Span<BAN::String> envp, BAN::Span<LibELF::AuxiliaryVector> auxv)
|
||||||
{
|
{
|
||||||
const auto& userspace_info = process().userspace_info();
|
// System V ABI: Initial process stack
|
||||||
ASSERT(userspace_info.entry);
|
|
||||||
|
|
||||||
setup_exec_impl(
|
ASSERT(m_is_userspace);
|
||||||
userspace_info.entry,
|
ASSERT(m_userspace_stack);
|
||||||
userspace_info.argc,
|
|
||||||
reinterpret_cast<uintptr_t>(userspace_info.argv),
|
size_t needed_size = 0;
|
||||||
reinterpret_cast<uintptr_t>(userspace_info.envp),
|
|
||||||
userspace_info.file_fd
|
// argc
|
||||||
);
|
needed_size += sizeof(uintptr_t);
|
||||||
|
|
||||||
|
// argv
|
||||||
|
needed_size += (argv.size() + 1) * sizeof(uintptr_t);
|
||||||
|
for (auto arg : argv)
|
||||||
|
needed_size += arg.size() + 1;
|
||||||
|
|
||||||
|
// envp
|
||||||
|
needed_size += (envp.size() + 1) * sizeof(uintptr_t);
|
||||||
|
for (auto env : envp)
|
||||||
|
needed_size += env.size() + 1;
|
||||||
|
|
||||||
|
// auxv
|
||||||
|
needed_size += auxv.size() * sizeof(LibELF::AuxiliaryVector);
|
||||||
|
|
||||||
|
if (needed_size > m_userspace_stack->size())
|
||||||
|
return BAN::Error::from_errno(ENOBUFS);
|
||||||
|
|
||||||
|
vaddr_t vaddr = userspace_stack_top() - needed_size;
|
||||||
|
|
||||||
|
const auto stack_copy_buf =
|
||||||
|
[this](BAN::ConstByteSpan buffer, vaddr_t vaddr) -> void
|
||||||
|
{
|
||||||
|
ASSERT(vaddr + buffer.size() <= userspace_stack_top());
|
||||||
|
|
||||||
|
size_t bytes_copied = 0;
|
||||||
|
while (bytes_copied < buffer.size())
|
||||||
|
{
|
||||||
|
const size_t to_copy = BAN::Math::min<size_t>(buffer.size() - bytes_copied, PAGE_SIZE - (vaddr % PAGE_SIZE));
|
||||||
|
|
||||||
|
PageTable::with_fast_page(userspace_stack().paddr_of(vaddr & PAGE_ADDR_MASK), [=]() {
|
||||||
|
memcpy(PageTable::fast_page_as_ptr(vaddr % PAGE_SIZE), buffer.data() + bytes_copied, to_copy);
|
||||||
|
});
|
||||||
|
|
||||||
|
vaddr += to_copy;
|
||||||
|
bytes_copied += to_copy;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto stack_push_buf =
|
||||||
|
[&stack_copy_buf, &vaddr](BAN::ConstByteSpan buffer) -> void
|
||||||
|
{
|
||||||
|
stack_copy_buf(buffer, vaddr);
|
||||||
|
vaddr += buffer.size();
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto stack_push_uint =
|
||||||
|
[&stack_push_buf](uintptr_t value) -> void
|
||||||
|
{
|
||||||
|
stack_push_buf(BAN::ConstByteSpan::from(value));
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto stack_push_str =
|
||||||
|
[&stack_push_buf](BAN::StringView string) -> void
|
||||||
|
{
|
||||||
|
const uint8_t* string_u8 = reinterpret_cast<const uint8_t*>(string.data());
|
||||||
|
stack_push_buf(BAN::ConstByteSpan(string_u8, string.size() + 1));
|
||||||
|
};
|
||||||
|
|
||||||
|
// argc
|
||||||
|
stack_push_uint(argv.size());
|
||||||
|
|
||||||
|
// argv
|
||||||
|
const vaddr_t argv_vaddr = vaddr;
|
||||||
|
vaddr += argv.size() * sizeof(uintptr_t);
|
||||||
|
stack_push_uint(0);
|
||||||
|
|
||||||
|
// envp
|
||||||
|
const vaddr_t envp_vaddr = vaddr;
|
||||||
|
vaddr += envp.size() * sizeof(uintptr_t);
|
||||||
|
stack_push_uint(0);
|
||||||
|
|
||||||
|
// auxv
|
||||||
|
for (auto aux : auxv)
|
||||||
|
stack_push_buf(BAN::ConstByteSpan::from(aux));
|
||||||
|
|
||||||
|
// information
|
||||||
|
for (size_t i = 0; i < argv.size(); i++)
|
||||||
|
{
|
||||||
|
stack_copy_buf(BAN::ConstByteSpan::from(vaddr), argv_vaddr + i * sizeof(uintptr_t));
|
||||||
|
stack_push_str(argv[i]);
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < envp.size(); i++)
|
||||||
|
{
|
||||||
|
stack_copy_buf(BAN::ConstByteSpan::from(vaddr), envp_vaddr + i * sizeof(uintptr_t));
|
||||||
|
stack_push_str(envp[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Thread::setup_exec_impl(uintptr_t entry, uintptr_t arg0, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3)
|
ASSERT(vaddr == userspace_stack_top());
|
||||||
|
|
||||||
|
setup_exec(entry, userspace_stack_top() - needed_size);
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void Thread::setup_exec(vaddr_t ip, vaddr_t sp)
|
||||||
{
|
{
|
||||||
ASSERT(is_userspace());
|
ASSERT(is_userspace());
|
||||||
m_state = State::NotStarted;
|
m_state = State::NotStarted;
|
||||||
|
@ -244,13 +331,13 @@ namespace Kernel
|
||||||
// Signal mask is inherited
|
// Signal mask is inherited
|
||||||
|
|
||||||
// Initialize stack for returning
|
// Initialize stack for returning
|
||||||
PageTable::with_fast_page(process().page_table().physical_address_of(kernel_stack_top() - PAGE_SIZE), [&] {
|
PageTable::with_fast_page(kernel_stack().paddr_of(kernel_stack_top() - PAGE_SIZE), [=] {
|
||||||
uintptr_t sp = PageTable::fast_page() + PAGE_SIZE;
|
uintptr_t cur_sp = PageTable::fast_page() + PAGE_SIZE;
|
||||||
write_to_stack(sp, entry);
|
write_to_stack(cur_sp, 0x20 | 3);
|
||||||
write_to_stack(sp, arg3);
|
write_to_stack(cur_sp, sp);
|
||||||
write_to_stack(sp, arg2);
|
write_to_stack(cur_sp, 0x202);
|
||||||
write_to_stack(sp, arg1);
|
write_to_stack(cur_sp, 0x18 | 3);
|
||||||
write_to_stack(sp, arg0);
|
write_to_stack(cur_sp, ip);
|
||||||
});
|
});
|
||||||
|
|
||||||
m_interrupt_stack.ip = reinterpret_cast<vaddr_t>(start_userspace_thread);
|
m_interrupt_stack.ip = reinterpret_cast<vaddr_t>(start_userspace_thread);
|
||||||
|
@ -286,7 +373,7 @@ namespace Kernel
|
||||||
m_signal_pending_mask = 0;
|
m_signal_pending_mask = 0;
|
||||||
m_signal_block_mask = ~0ull;
|
m_signal_block_mask = ~0ull;
|
||||||
|
|
||||||
PageTable::with_fast_page(process().page_table().physical_address_of(kernel_stack_top() - PAGE_SIZE), [&] {
|
PageTable::with_fast_page(kernel_stack().paddr_of(kernel_stack_top() - PAGE_SIZE), [&] {
|
||||||
uintptr_t sp = PageTable::fast_page() + PAGE_SIZE;
|
uintptr_t sp = PageTable::fast_page() + PAGE_SIZE;
|
||||||
write_to_stack(sp, this);
|
write_to_stack(sp, this);
|
||||||
write_to_stack(sp, &Thread::on_exit_trampoline);
|
write_to_stack(sp, &Thread::on_exit_trampoline);
|
||||||
|
|
|
@ -2,18 +2,22 @@
|
||||||
|
|
||||||
.global _start
|
.global _start
|
||||||
_start:
|
_start:
|
||||||
pushl $0
|
# get argc, argv, envp
|
||||||
|
movl (%esp), %edi
|
||||||
|
leal 4(%esp), %esi
|
||||||
|
leal 4(%esi, %edi, 4), %edx
|
||||||
|
|
||||||
|
# align stack
|
||||||
|
andl $-16, %esp
|
||||||
|
xorl %ebp, %ebp
|
||||||
|
|
||||||
|
# save argc, argv, envp
|
||||||
|
subl $4, %esp
|
||||||
pushl %edx
|
pushl %edx
|
||||||
pushl %esi
|
pushl %esi
|
||||||
pushl %edi
|
pushl %edi
|
||||||
|
|
||||||
# STACK LAYOUT
|
subl $4, %esp
|
||||||
# null
|
|
||||||
# argc
|
|
||||||
# argv
|
|
||||||
# envp
|
|
||||||
|
|
||||||
xorl %ebp, %ebp
|
|
||||||
|
|
||||||
pushl $__fini_array_end
|
pushl $__fini_array_end
|
||||||
pushl $__fini_array_start
|
pushl $__fini_array_start
|
||||||
|
|
|
@ -2,21 +2,22 @@
|
||||||
|
|
||||||
.global _start
|
.global _start
|
||||||
_start:
|
_start:
|
||||||
pushq $0
|
# get argc, argv, envp
|
||||||
|
movq (%rsp), %rdi
|
||||||
|
leaq 8(%rsp), %rsi
|
||||||
|
leaq 8(%rsi, %rdi, 8), %rdx
|
||||||
|
|
||||||
|
# align stack
|
||||||
|
andq $-16, %rsp
|
||||||
|
xorq %rbp, %rbp
|
||||||
|
|
||||||
|
# save argc, argv, envp
|
||||||
|
subq $8, %rsp
|
||||||
pushq %rdi
|
pushq %rdi
|
||||||
pushq %rsi
|
pushq %rsi
|
||||||
pushq %rdx
|
pushq %rdx
|
||||||
|
|
||||||
# STACK LAYOUT
|
movq %rdx, %rdi # environ
|
||||||
# null
|
|
||||||
# argc
|
|
||||||
# argv
|
|
||||||
# envp
|
|
||||||
|
|
||||||
xorq %rbp, %rbp
|
|
||||||
|
|
||||||
# init libc
|
|
||||||
movq 0(%rsp), %rdi
|
|
||||||
|
|
||||||
pushq $__fini_array_end
|
pushq $__fini_array_end
|
||||||
pushq $__fini_array_start
|
pushq $__fini_array_start
|
||||||
|
@ -31,9 +32,10 @@ _start:
|
||||||
addq $(6 * 8), %rsp
|
addq $(6 * 8), %rsp
|
||||||
|
|
||||||
# call main
|
# call main
|
||||||
movq 16(%rsp), %rdi
|
popq %rdx
|
||||||
movq 8(%rsp), %rsi
|
popq %rsi
|
||||||
movq 0(%rsp), %rdx
|
popq %rdi
|
||||||
|
addq $8, %rsp
|
||||||
call main
|
call main
|
||||||
|
|
||||||
# call exit
|
# call exit
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
#include <BAN/Atomic.h>
|
#include <BAN/Atomic.h>
|
||||||
#include <BAN/PlacementNew.h>
|
#include <BAN/PlacementNew.h>
|
||||||
|
|
||||||
|
#include <kernel/Arch.h>
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
@ -16,15 +18,30 @@ struct pthread_trampoline_info_t
|
||||||
};
|
};
|
||||||
|
|
||||||
// stack is 16 byte aligned on entry, this `call` is used to align it
|
// stack is 16 byte aligned on entry, this `call` is used to align it
|
||||||
extern "C" void pthread_trampoline(void*);
|
extern "C" void _pthread_trampoline(void*);
|
||||||
asm("pthread_trampoline: call pthread_trampoline_cpp");
|
asm(
|
||||||
|
#if ARCH(x86_64)
|
||||||
|
"_pthread_trampoline:"
|
||||||
|
"popq %rdi;"
|
||||||
|
"andq $-16, %rsp;"
|
||||||
|
"xorq %rbp, %rbp;"
|
||||||
|
"call _pthread_trampoline_cpp"
|
||||||
|
#elif ARCH(i686)
|
||||||
|
"_pthread_trampoline:"
|
||||||
|
"ud2;"
|
||||||
|
"popl %edi;"
|
||||||
|
"andl $-16, %esp;"
|
||||||
|
"xorl %ebp, %ebp;"
|
||||||
|
"subl $12, %esp;"
|
||||||
|
"pushl %edi;"
|
||||||
|
"call _pthread_trampoline_cpp"
|
||||||
|
#endif
|
||||||
|
);
|
||||||
|
|
||||||
extern "C" void pthread_trampoline_cpp(void* arg)
|
extern "C" void _pthread_trampoline_cpp(void* arg)
|
||||||
{
|
{
|
||||||
pthread_trampoline_info_t info;
|
auto info = *reinterpret_cast<pthread_trampoline_info_t*>(arg);
|
||||||
memcpy(&info, arg, sizeof(pthread_trampoline_info_t));
|
|
||||||
free(arg);
|
free(arg);
|
||||||
|
|
||||||
pthread_exit(info.start_routine(info.arg));
|
pthread_exit(info.start_routine(info.arg));
|
||||||
ASSERT_NOT_REACHED();
|
ASSERT_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
@ -63,24 +80,30 @@ void pthread_cleanup_push(void (*routine)(void*), void* arg)
|
||||||
s_cleanup_stack = cleanup;
|
s_cleanup_stack = cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
int pthread_create(pthread_t* __restrict thread, const pthread_attr_t* __restrict attr, void* (*start_routine)(void*), void* __restrict arg)
|
int pthread_create(pthread_t* __restrict thread_id, const pthread_attr_t* __restrict attr, void* (*start_routine)(void*), void* __restrict arg)
|
||||||
{
|
{
|
||||||
auto* info = static_cast<pthread_trampoline_info_t*>(malloc(sizeof(pthread_trampoline_info_t)));
|
auto* info = static_cast<pthread_trampoline_info_t*>(malloc(sizeof(pthread_trampoline_info_t)));
|
||||||
if (info == nullptr)
|
if (info == nullptr)
|
||||||
return -1;
|
return errno;
|
||||||
info->start_routine = start_routine;
|
|
||||||
info->arg = arg;
|
*info = {
|
||||||
|
.start_routine = start_routine,
|
||||||
|
.arg = arg,
|
||||||
|
};
|
||||||
|
|
||||||
const auto ret = syscall(SYS_PTHREAD_CREATE, attr, pthread_trampoline, info);
|
const auto ret = syscall(SYS_PTHREAD_CREATE, attr, pthread_trampoline, info);
|
||||||
if (ret == -1)
|
if (ret == -1)
|
||||||
{
|
goto pthread_create_error;
|
||||||
free(info);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (thread)
|
|
||||||
*thread = ret;
|
if (thread_id)
|
||||||
|
*thread_id = ret;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
pthread_create_error:
|
||||||
|
const int return_code = errno;
|
||||||
|
free(info);
|
||||||
|
return return_code;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pthread_exit(void* value_ptr)
|
void pthread_exit(void* value_ptr)
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
|
#include <LibELF/AuxiliaryVector.h>
|
||||||
#include <LibELF/Types.h>
|
#include <LibELF/Types.h>
|
||||||
#include <LibELF/Values.h>
|
#include <LibELF/Values.h>
|
||||||
|
|
||||||
|
@ -15,42 +16,44 @@ void _start()
|
||||||
{
|
{
|
||||||
#if defined(__x86_64__)
|
#if defined(__x86_64__)
|
||||||
asm volatile(
|
asm volatile(
|
||||||
"xorq %rbp, %rbp;"
|
"movq (%rsp), %rdi;"
|
||||||
|
"leaq 8(%rsp), %rsi;"
|
||||||
|
"leaq 8(%rsi, %rdi, 8), %rdx;"
|
||||||
|
|
||||||
|
"movq %rsp, %rbp;"
|
||||||
|
"andq $-16, %rsp;"
|
||||||
|
|
||||||
"call _entry;"
|
"call _entry;"
|
||||||
|
|
||||||
|
"movq %rbp, %rsp;"
|
||||||
|
"xorq %rbp, %rbp;"
|
||||||
|
|
||||||
|
"jmp *%rax;"
|
||||||
|
|
||||||
"ud2;"
|
"ud2;"
|
||||||
);
|
);
|
||||||
#elif defined(__i686__)
|
#elif defined(__i686__)
|
||||||
asm volatile(
|
asm volatile(
|
||||||
"xorl %ebp, %ebp;"
|
"movl (%esp), %edi;"
|
||||||
"pushl %ecx;"
|
"leal 4(%esp), %esi;"
|
||||||
|
"leal 4(%esi, %edi, 4), %edx;"
|
||||||
|
|
||||||
|
"movl %esp, %ebp;"
|
||||||
|
"andl $-16, %esp;"
|
||||||
|
|
||||||
|
"subl $4, %esp;"
|
||||||
"pushl %edx;"
|
"pushl %edx;"
|
||||||
"pushl %esi;"
|
"pushl %esi;"
|
||||||
"pushl %edi;"
|
"pushl %edi;"
|
||||||
"call _entry;"
|
|
||||||
"ud2;"
|
|
||||||
);
|
|
||||||
#else
|
|
||||||
#error "unsupported architecture"
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
__attribute__((naked, noreturn))
|
"call _entry;"
|
||||||
static void call_entry_point(int, char**, char**, uintptr_t)
|
|
||||||
{
|
"movl %ebp, %esp;"
|
||||||
#if defined(__x86_64__)
|
"xorl %ebp, %ebp;"
|
||||||
asm volatile(
|
|
||||||
"andq $-16, %rsp;"
|
"jmp *%eax;"
|
||||||
"jmp *%rcx;"
|
|
||||||
);
|
"ud2;"
|
||||||
#elif defined(__i686__)
|
|
||||||
asm volatile(
|
|
||||||
"addl $4, %esp;"
|
|
||||||
"popl %edi;"
|
|
||||||
"popl %esi;"
|
|
||||||
"popl %edx;"
|
|
||||||
"popl %ecx;"
|
|
||||||
"andl $-16, %esp;"
|
|
||||||
"jmp *%ecx;"
|
|
||||||
);
|
);
|
||||||
#else
|
#else
|
||||||
#error "unsupported architecture"
|
#error "unsupported architecture"
|
||||||
|
@ -901,16 +904,33 @@ static void call_init_funcs(LoadedElf& elf, bool is_main_elf)
|
||||||
reinterpret_cast<init_t>(elf.init)();
|
reinterpret_cast<init_t>(elf.init)();
|
||||||
for (size_t i = 0; i < elf.init_arraysz / sizeof(init_t); i++)
|
for (size_t i = 0; i < elf.init_arraysz / sizeof(init_t); i++)
|
||||||
reinterpret_cast<init_t*>(elf.init_array)[i]();
|
reinterpret_cast<init_t*>(elf.init_array)[i]();
|
||||||
|
}
|
||||||
|
|
||||||
|
static LibELF::AuxiliaryVector* find_auxv(char** envp)
|
||||||
|
{
|
||||||
|
if (envp == nullptr)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
char** null_env = envp;
|
||||||
|
while (*null_env)
|
||||||
|
null_env++;
|
||||||
|
|
||||||
|
return reinterpret_cast<LibELF::AuxiliaryVector*>(null_env + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C"
|
extern "C"
|
||||||
__attribute__((used, noreturn))
|
__attribute__((used))
|
||||||
int _entry(int argc, char** argv, char** envp, int fd)
|
uintptr_t _entry(int argc, char* argv[], char* envp[])
|
||||||
{
|
{
|
||||||
const bool invoked_directly = (fd < 0);
|
int execfd = -1;
|
||||||
if (invoked_directly)
|
if (auto* auxv = find_auxv(envp))
|
||||||
|
for (auto* aux = auxv; aux->a_type != LibELF::AT_NULL; aux++)
|
||||||
|
if (aux->a_type == LibELF::AT_EXECFD) {
|
||||||
|
execfd = aux->a_un.a_val;
|
||||||
|
aux->a_type = LibELF::AT_IGNORE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (execfd == -1)
|
||||||
{
|
{
|
||||||
if (argc < 2)
|
if (argc < 2)
|
||||||
print_error_and_exit("missing program name", 0);
|
print_error_and_exit("missing program name", 0);
|
||||||
|
@ -918,18 +938,19 @@ int _entry(int argc, char** argv, char** envp, int fd)
|
||||||
argc--;
|
argc--;
|
||||||
argv++;
|
argv++;
|
||||||
|
|
||||||
fd = syscall(SYS_OPENAT, AT_FDCWD, argv[0], O_RDONLY);
|
execfd = syscall(SYS_OPENAT, AT_FDCWD, argv[0], O_RDONLY);
|
||||||
if (fd < 0)
|
if (execfd < 0)
|
||||||
print_error_and_exit("could not open program", fd);
|
print_error_and_exit("could not open program", execfd);
|
||||||
}
|
}
|
||||||
|
|
||||||
init_random();
|
init_random();
|
||||||
auto& elf = load_elf(argv[0], fd);
|
auto& elf = load_elf(argv[0], execfd);
|
||||||
syscall(SYS_CLOSE, fd);
|
syscall(SYS_CLOSE, fd);
|
||||||
fini_random();
|
fini_random();
|
||||||
|
|
||||||
relocate_elf(elf, true);
|
relocate_elf(elf, true);
|
||||||
initialize_environ(envp);
|
initialize_environ(envp);
|
||||||
call_init_funcs(elf, true);
|
call_init_funcs(elf, true);
|
||||||
call_entry_point(argc, argv, envp, elf.base + elf.file_header.e_entry);
|
|
||||||
|
return elf.base + elf.file_header.e_entry;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue