DynamicLoader: Use file backed mmap when possible

This commit is contained in:
Bananymous 2024-09-05 13:59:39 +03:00
parent 2f241e1b61
commit e8bcebfb8e
3 changed files with 46 additions and 77 deletions

View File

@ -622,98 +622,57 @@ static void load_program_header(const ElfNativeProgramHeader& program_header, in
return result;
}();
const uintptr_t aligned_vaddr = program_header.p_vaddr & ~(uintptr_t)0xFFF;
if ((program_header.p_vaddr & 0xFFF) || (program_header.p_offset & 0xFFF))
{
const uintptr_t aligned_addr = program_header.p_vaddr & ~(uintptr_t)0xFFF;
// unaligned addresses, cannot use file mmap
sys_mmap_t mmap_args;
mmap_args.addr = reinterpret_cast<void*>(aligned_vaddr);
mmap_args.addr = reinterpret_cast<void*>(aligned_addr);
mmap_args.fildes = -1;
mmap_args.flags = MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED;
mmap_args.len = (program_header.p_vaddr + program_header.p_memsz) - aligned_vaddr;
mmap_args.len = (program_header.p_vaddr + program_header.p_memsz) - aligned_addr;
mmap_args.off = 0;
mmap_args.prot = prot | PROT_WRITE;
if (auto ret = syscall(SYS_MMAP, &mmap_args); ret != static_cast<long>(aligned_vaddr))
print_error_and_exit("could not load program header", ret);
if (auto ret = syscall(SYS_PREAD, fd, program_header.p_vaddr, program_header.p_filesz, program_header.p_offset); ret != static_cast<long>(program_header.p_filesz))
if (auto ret = syscall(SYS_MMAP, &mmap_args); ret != static_cast<long>(aligned_addr))
print_error_and_exit("could not load program header", ret);
return;
const uintptr_t addr = program_header.p_vaddr;
const uintptr_t size = program_header.p_filesz;
const size_t offset = program_header.p_offset;
if (auto ret = syscall(SYS_PREAD, fd, addr, size, offset); ret != static_cast<long>(size))
print_error_and_exit("could not load program header", ret);
}
else
{
// aligned addresses, use file mmap
sys_mmap_t mmap_args;
mmap_args.addr = reinterpret_cast<void*>(program_header.p_vaddr);
mmap_args.fildes = fd;
mmap_args.flags = MAP_PRIVATE | MAP_FIXED;
mmap_args.len = program_header.p_memsz;
mmap_args.off = program_header.p_offset;
mmap_args.prot = prot | PROT_WRITE;
uintptr_t filesz = program_header.p_filesz;
if (auto ret = syscall(SYS_MMAP, &mmap_args); ret != static_cast<long>(program_header.p_vaddr))
print_error_and_exit("could not load program header", ret);
}
if (program_header.p_filesz != program_header.p_memsz)
{
const uintptr_t data_end_vaddr = program_header.p_vaddr + program_header.p_filesz;
const uintptr_t zero_end_vaddr = program_header.p_vaddr + program_header.p_memsz;
uintptr_t start_vaddr = data_end_vaddr & ~(uintptr_t)0xFFF;
if (program_header.p_vaddr & 0xFFF)
start_vaddr = program_header.p_vaddr & ~(uintptr_t)0xFFF;
if (start_vaddr != data_end_vaddr)
{
const uintptr_t end_vaddr = (data_end_vaddr + 4095) & ~(uintptr_t)0xFFF;
const ptrdiff_t length = min(end_vaddr - start_vaddr, zero_end_vaddr - start_vaddr);
sys_mmap_t mmap_args;
mmap_args.addr = reinterpret_cast<void*>(start_vaddr);
mmap_args.fildes = -1;
mmap_args.flags = MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED;
mmap_args.len = length;
mmap_args.off = 0;
mmap_args.prot = prot | PROT_WRITE;
if (auto ret = syscall(SYS_MMAP, &mmap_args); ret != static_cast<long>(start_vaddr))
print_error_and_exit("could not load program header", ret);
uintptr_t dummy_bytes = program_header.p_vaddr - start_vaddr;
if (program_header.p_vaddr & 0xFFF)
dummy_bytes = 0;
const uintptr_t data_vaddr = program_header.p_vaddr + dummy_bytes;
const ptrdiff_t data_bytes = data_end_vaddr - data_vaddr;
const uintptr_t data_offset = program_header.p_offset + dummy_bytes;
if (auto ret = syscall(SYS_PREAD, fd, data_vaddr, data_bytes, data_offset); ret != data_bytes)
print_error_and_exit("could not load program header", ret);
memset(
reinterpret_cast<void*>(program_header.p_vaddr + program_header.p_filesz),
0x00,
program_header.p_memsz - program_header.p_filesz
);
}
if (!(prot & PROT_WRITE) && !needs_writable)
{
// FIXME: Implement mprotect so PROT_WRITE can be removed
//syscall(SYS_MPROTECT, start_vaddr, length, prot);
}
filesz -= data_bytes;
start_vaddr += 4096;
}
if (start_vaddr < zero_end_vaddr)
{
sys_mmap_t mmap_args;
mmap_args.addr = reinterpret_cast<void*>(start_vaddr);
mmap_args.fildes = -1;
mmap_args.flags = MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED;
mmap_args.len = zero_end_vaddr - start_vaddr;
mmap_args.off = 0;
mmap_args.prot = prot | (needs_writable ? PROT_WRITE : 0);
if (auto ret = syscall(SYS_MMAP, &mmap_args); ret != static_cast<long>(start_vaddr))
print_error_and_exit("could not load program header", ret);
}
}
if (filesz)
{
sys_mmap_t mmap_args;
mmap_args.addr = reinterpret_cast<void*>(program_header.p_vaddr);
mmap_args.fildes = fd;
mmap_args.flags = MAP_PRIVATE | MAP_FIXED;
mmap_args.len = filesz;
mmap_args.off = program_header.p_offset;
mmap_args.prot = prot | (needs_writable ? PROT_WRITE : 0);
if (auto ret = syscall(SYS_MMAP, &mmap_args); ret != static_cast<long>(program_header.p_vaddr))
print_error_and_exit("could not load program header", ret);
}
}
static LoadedElf s_loaded_files[128];

View File

@ -56,6 +56,14 @@ void* memcpy(void* __restrict dstp, const void* __restrict srcp, size_t n)
return dstp;
}
void* memset(void* s, int c, size_t n)
{
unsigned char* p = static_cast<unsigned char*>(s);
for (size_t i = 0; i < n; i++)
p[i] = c;
return s;
}
static int s_random_fd;
void init_random()

View File

@ -42,7 +42,9 @@ inline void print_uint(int fd, T val, uint8_t base = 10)
int strcmp(const char* s1, const char* s2);
char* strcpy(char* __restrict s1, const char* __restrict s2);
void* memcpy(void* __restrict s1, const void* __restrict s2, size_t n);
void* memset(void* s, int c, size_t n);
void init_random();
void fini_random();