Introducing the program launching mega-function: launch()
This commit is contained in:
323
photon/libc/sys/horizon/__elf.h
Normal file
323
photon/libc/sys/horizon/__elf.h
Normal file
@@ -0,0 +1,323 @@
|
||||
#ifndef SYS_HORIZON_SYS___ELF_H_
|
||||
#define SYS_HORIZON_SYS___ELF_H_
|
||||
|
||||
#include <magenta/types.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define ELF_LOAD_ERR -1
|
||||
#define ELF_LOADED_EXEC 0
|
||||
#define ELF_LOADED_INTERP 1
|
||||
|
||||
#define ELF_MAG0 0x7f
|
||||
#define ELF_MAG1 'E'
|
||||
#define ELF_MAG2 'L'
|
||||
#define ELF_MAG3 'F'
|
||||
#define ELF_NIDENT 16
|
||||
|
||||
#define SHT_NONE 0
|
||||
#define SHT_PROGBITS 1
|
||||
#define SHT_SYMTAB 2
|
||||
#define SHT_STRTAB 3
|
||||
#define SHT_RELA 4
|
||||
#define SHT_DYNAMIC 6
|
||||
#define SHT_NOBITS 8
|
||||
#define SHT_REL 9
|
||||
#define SHT_DYNSYM 11
|
||||
|
||||
/** Little endian. */
|
||||
#define ELFDATA2LSB (1)
|
||||
|
||||
/** 64-bit. */
|
||||
#define ELFCLASS64 (2)
|
||||
|
||||
/** x86_64 machine type. */
|
||||
#define EM_X86_64 (62)
|
||||
|
||||
/** ELF current version. */
|
||||
#define EV_CURRENT (1)
|
||||
|
||||
/** Dynamic section tags. */
|
||||
#define DT_NULL 0
|
||||
#define DT_NEEDED 1
|
||||
#define DT_PLTRELSZ 2
|
||||
#define DT_PLTGOT 3
|
||||
#define DT_HASH 4
|
||||
#define DT_STRTAB 5
|
||||
#define DT_SYMTAB 6
|
||||
#define DT_RELA 7
|
||||
#define DT_RELASZ 8
|
||||
#define DT_RELAENT 9
|
||||
#define DT_STRSZ 10
|
||||
#define DT_SYMENT 11
|
||||
#define DT_INIT 12
|
||||
#define DT_FINI 13
|
||||
#define DT_REL 17
|
||||
#define DT_RELSZ 18
|
||||
#define DT_RELENT 19
|
||||
#define DT_PLTREL 20
|
||||
#define DT_JMPREL 23
|
||||
#define DT_GNU_HASH 0x6ffffef5
|
||||
#define DT_AUXILIARY 0x7ffffffd
|
||||
|
||||
#define R_386_32 1
|
||||
#define R_386_PC32 2
|
||||
#define R_386_GOT32 3
|
||||
#define R_386_PLT32 4
|
||||
#define R_386_GOTOFF 9
|
||||
#define R_386_GOTPC 10
|
||||
#define R_386_GOT32X 43
|
||||
|
||||
#define R_X86_64_64 1
|
||||
#define R_X86_64_PC32 2
|
||||
#define R_X86_64_GOT32 3
|
||||
#define R_X86_64_PLT32 4
|
||||
#define R_X86_64_COPY 5
|
||||
#define R_X86_64_GLOB_DAT 6
|
||||
#define R_X86_64_JUMP_SLOT 7
|
||||
#define R_X86_64_RELATIVE 8
|
||||
#define R_X86_64_GOTPCREL 9
|
||||
#define R_X86_64_32 10
|
||||
|
||||
#define STT_NOTYPE 0
|
||||
#define STT_OBJECT 1
|
||||
#define STT_FUNC 2
|
||||
#define STT_SECTION 3
|
||||
#define STT_FILE 4
|
||||
#define STT_LOPROC 13
|
||||
#define STT_HIPROC 15
|
||||
|
||||
/* Section flags */
|
||||
#define SHF_WRITE 0x1
|
||||
#define SHF_ALLOC 0x2
|
||||
#define SHF_EXECINSTR 0x4
|
||||
|
||||
#define SHN_UNDEF 0
|
||||
|
||||
#define ELF64_R_SYM(i) ((i) >> 32)
|
||||
#define ELF64_R_TYPE(i) ((elf_word_t)(i))
|
||||
#define ELF64_ST_BIND(i) ((i) >> 4)
|
||||
#define ELF64_ST_TYPE(i) ((i)&0xf)
|
||||
|
||||
#define STB_LOCAL 0
|
||||
#define STB_GLOBAL 1
|
||||
#define STB_WEAK 2
|
||||
#define STB_NUM 3
|
||||
|
||||
typedef uint64_t elf_addr_t;
|
||||
typedef uint64_t elf_off_t;
|
||||
typedef uint16_t elf_half_t;
|
||||
typedef uint32_t elf_word_t;
|
||||
typedef int32_t elf_sword_t;
|
||||
typedef uint64_t elf_xword_t;
|
||||
typedef int64_t elf_sxword_t;
|
||||
|
||||
/**
|
||||
* ELF file header.
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t e_ident[ELF_NIDENT];
|
||||
elf_half_t e_type;
|
||||
elf_half_t e_machine;
|
||||
elf_word_t e_version;
|
||||
elf_addr_t e_entry;
|
||||
elf_off_t e_phoff;
|
||||
elf_off_t e_shoff;
|
||||
elf_word_t e_flags;
|
||||
elf_half_t e_ehsize;
|
||||
elf_half_t e_phentsize;
|
||||
elf_half_t e_phnum;
|
||||
elf_half_t e_shentsize;
|
||||
elf_half_t e_shnum;
|
||||
elf_half_t e_shstrndx;
|
||||
} elf_ehdr_t;
|
||||
|
||||
/**
|
||||
* ELF section header.
|
||||
*/
|
||||
typedef struct {
|
||||
elf_word_t sh_name;
|
||||
elf_word_t sh_type;
|
||||
elf_xword_t sh_flags;
|
||||
elf_addr_t sh_addr;
|
||||
elf_off_t sh_offset;
|
||||
elf_xword_t sh_size;
|
||||
elf_word_t sh_link;
|
||||
elf_word_t sh_info;
|
||||
elf_xword_t sh_addralign;
|
||||
elf_xword_t sh_entsize;
|
||||
} elf_shdr_t;
|
||||
|
||||
/**
|
||||
* ELF symbol.
|
||||
*/
|
||||
typedef struct {
|
||||
elf_word_t st_name;
|
||||
unsigned char st_info;
|
||||
unsigned char st_other;
|
||||
elf_half_t st_shndx;
|
||||
elf_addr_t st_value;
|
||||
elf_xword_t st_size;
|
||||
} elf_sym_t;
|
||||
|
||||
/**
|
||||
* ELF program header.
|
||||
*/
|
||||
typedef struct {
|
||||
elf_word_t p_type;
|
||||
elf_word_t p_flags;
|
||||
elf_off_t p_offset;
|
||||
elf_addr_t p_vaddr;
|
||||
elf_addr_t p_paddr;
|
||||
elf_xword_t p_filesz;
|
||||
elf_xword_t p_memsz;
|
||||
elf_xword_t p_align;
|
||||
} elf_phdr_t;
|
||||
|
||||
/**
|
||||
* Extended ELF relocation information.
|
||||
*/
|
||||
typedef struct {
|
||||
elf_addr_t r_offset;
|
||||
elf_xword_t r_info;
|
||||
elf_sxword_t r_addend;
|
||||
} elf_rela_t;
|
||||
|
||||
/**
|
||||
* Dynamic section entries
|
||||
*/
|
||||
typedef struct {
|
||||
elf_sxword_t d_tag;
|
||||
union {
|
||||
elf_xword_t d_val;
|
||||
elf_addr_t d_ptr;
|
||||
} d_un;
|
||||
} elf_dyn_t;
|
||||
|
||||
/**
|
||||
* Section header types.
|
||||
*/
|
||||
enum elf_stype {
|
||||
ST_NONE = 0,
|
||||
ST_PROGBITS = 1,
|
||||
ST_SYMTAB = 2,
|
||||
ST_STRTAB = 3,
|
||||
ST_NOBITS = 8,
|
||||
ST_REL = 9
|
||||
};
|
||||
|
||||
/**
|
||||
* Program header types.
|
||||
*/
|
||||
enum elf_ptype {
|
||||
PT_NULL = 0,
|
||||
PT_LOAD = 1,
|
||||
PT_DYNAMIC = 2,
|
||||
PT_INTERP = 3,
|
||||
PT_NOTE = 4,
|
||||
PT_SHLIB = 5,
|
||||
PT_PHDR = 6
|
||||
};
|
||||
|
||||
#define PF_X 0x1
|
||||
#define PF_W 0x2
|
||||
#define PF_R 0x4
|
||||
|
||||
#define PT_LOPROC 0x70000000
|
||||
#define PT_HIPROC 0x7FFFFFFF
|
||||
|
||||
/**
|
||||
* ELF identification byte locations.
|
||||
*/
|
||||
enum elf_ident {
|
||||
EI_MAG0 = 0,
|
||||
EI_MAG1 = 1,
|
||||
EI_MAG2 = 2,
|
||||
EI_MAG3 = 3,
|
||||
EI_CLASS = 4,
|
||||
EI_DATA = 5,
|
||||
EI_VERSION = 6,
|
||||
EI_OSABI = 7,
|
||||
EI_ABIVERSION = 8,
|
||||
EI_PAD = 9
|
||||
};
|
||||
|
||||
enum elf_type {
|
||||
ET_NONE = 0,
|
||||
ET_REL = 1,
|
||||
ET_EXEC = 2,
|
||||
ET_DYN = 3,
|
||||
};
|
||||
|
||||
#define AT_NULL 0
|
||||
#define AT_IGNORE 1
|
||||
#define AT_EXECFD 2
|
||||
#define AT_PHDR 3
|
||||
#define AT_PHENT 4
|
||||
#define AT_PHNUM 5
|
||||
#define AT_PAGESZ 6
|
||||
#define AT_BASE 7
|
||||
#define AT_FLAGS 8
|
||||
#define AT_ENTRY 9
|
||||
#define AT_NOTELF 10
|
||||
#define AT_UID 11
|
||||
#define AT_EUID 12
|
||||
#define AT_GID 13
|
||||
#define AT_EGID 14
|
||||
#define AT_CLKTCK 17
|
||||
#define AT_PLATFORM 15
|
||||
#define AT_HWCAP 16
|
||||
#define AT_FPUCW 18
|
||||
#define AT_DCACHEBSIZE 19
|
||||
#define AT_ICACHEBSIZE 20
|
||||
#define AT_UCACHEBSIZE 21
|
||||
#define AT_IGNOREPPC 22
|
||||
#define AT_SECURE 23
|
||||
#define AT_BASE_PLATFORM 24
|
||||
#define AT_RANDOM 25
|
||||
#define AT_HWCAP2 26
|
||||
#define AT_EXECFN 31
|
||||
#define AT_SYSINFO 32
|
||||
#define AT_SYSINFO_EHDR 33
|
||||
#define AT_L1I_CACHESHAPE 34
|
||||
#define AT_L1D_CACHESHAPE 35
|
||||
#define AT_L2_CACHESHAPE 36
|
||||
#define AT_L3_CACHESHAPE 37
|
||||
#define AT_ENTRY_COUNT 38
|
||||
|
||||
struct bootdata;
|
||||
struct bootfs_file;
|
||||
|
||||
struct elf_image {
|
||||
mx_handle_t image_vmo, rw_vmo;
|
||||
mx_vaddr_t local_base_addr, remote_base_addr;
|
||||
|
||||
mx_handle_t local_root_vmar, local_exec_vmar;
|
||||
mx_handle_t remote_root_vmar, remote_exec_vmar;
|
||||
size_t exec_vmar_size;
|
||||
|
||||
elf_ehdr_t hdr;
|
||||
uintptr_t dynstr_offset;
|
||||
size_t dynstr_len;
|
||||
|
||||
uintptr_t dynsym_offset;
|
||||
size_t dynsym_len, dynsym_entsz;
|
||||
|
||||
elf_phdr_t dynamic;
|
||||
|
||||
enum { NO_HASH, REG_HASH, GNU_HASH } hash_type;
|
||||
uintptr_t hash_offset;
|
||||
};
|
||||
|
||||
extern void __elf_image_init(mx_handle_t local_vmar, mx_handle_t remote_vmar, struct elf_image *out);
|
||||
extern int __elf_image_load_image(struct elf_image *image, mx_handle_t image_vmo);
|
||||
extern int __elf_get_interp_path(mx_handle_t exec_vmo, char *out, size_t max);
|
||||
extern int __elf_check_dependencies(struct elf_image *image);
|
||||
|
||||
extern mx_vaddr_t __elf_image_get_symbol(struct elf_image *image, const char *name);
|
||||
|
||||
extern int __elf_image_link(struct elf_image *exec, struct elf_image *vdso);
|
||||
extern mx_vaddr_t __elf_image_entry_point(struct elf_image *image);
|
||||
|
||||
extern void __elf_image_cleanup(struct elf_image *image);
|
||||
|
||||
#endif
|
||||
673
photon/libc/sys/horizon/elf.c
Normal file
673
photon/libc/sys/horizon/elf.c
Normal file
@@ -0,0 +1,673 @@
|
||||
#include <magenta/misc.h>
|
||||
#include <magenta/errors.h>
|
||||
#include <magenta/handle.h>
|
||||
#include <magenta/vmo.h>
|
||||
#include <magenta/vmar.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include "__elf.h"
|
||||
|
||||
#define HIDDEN __attribute__((visibility("hidden")))
|
||||
|
||||
#define VDSO_SONAME "mx.dylib"
|
||||
|
||||
#define NEEDS_NOTHING 0
|
||||
#define NEEDS_VDSO 1
|
||||
#define NEEDS_MORE 2
|
||||
|
||||
#define ACL (PF_R | PF_W | PF_X)
|
||||
#define ACCESS(x) ((x) & ACL)
|
||||
|
||||
/* TODO in case we ever support ELF32 images */
|
||||
#define elf_class_bits(x) (64)
|
||||
|
||||
#define PAGE_OFFSET(v) ((v) & (MX_PAGE_SIZE - 1))
|
||||
#define PAGE_ALIGN_DOWN(v) (v) &= ~(MX_PAGE_SIZE - 1)
|
||||
#define PAGE_ALIGN_UP(v) \
|
||||
do { \
|
||||
if ((v) & (MX_PAGE_SIZE - 1)) { \
|
||||
v &= ~(MX_PAGE_SIZE - 1); \
|
||||
v += MX_PAGE_SIZE; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#undef DEBUG_LOG
|
||||
|
||||
HIDDEN void __elf_image_init(mx_handle_t local_vmar, mx_handle_t remote_vmar, struct elf_image *out)
|
||||
{
|
||||
memset(out, 0x0, sizeof(*out));
|
||||
out->local_root_vmar = local_vmar;
|
||||
out->remote_root_vmar = remote_vmar;
|
||||
}
|
||||
|
||||
static int elf_validate_ehdr(elf_ehdr_t *hdr)
|
||||
{
|
||||
if (hdr->e_ident[EI_MAG0] != ELF_MAG0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (hdr->e_ident[EI_MAG1] != ELF_MAG1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (hdr->e_ident[EI_MAG2] != ELF_MAG2) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (hdr->e_ident[EI_MAG3] != ELF_MAG3) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (hdr->e_ident[EI_CLASS] != ELFCLASS64) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (hdr->e_machine != EM_X86_64) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (hdr->e_ident[EI_DATA] != ELFDATA2LSB) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (hdr->e_ident[EI_VERSION] != EV_CURRENT) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int read_header(struct elf_image *image)
|
||||
{
|
||||
mx_status_t err = mx_vmo_read(image->image_vmo, (uint8_t *)&image->hdr, sizeof(image->hdr), 0);
|
||||
if (err != MX_OK) {
|
||||
printf("vmo_read %x error %s\n", image->image_vmo, mx_status_to_string(err));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return elf_validate_ehdr(&image->hdr);
|
||||
}
|
||||
|
||||
static mx_status_t allocate_vmar(struct elf_image *image, size_t size)
|
||||
{
|
||||
mx_status_t err = mx_vmar_allocate(image->local_root_vmar,
|
||||
MX_VM_CAN_MAP_READ | MX_VM_CAN_MAP_WRITE |
|
||||
MX_VM_CAN_MAP_EXEC | MX_VM_CAN_MAP_SPECIFIC,
|
||||
0, size, &image->local_exec_vmar, &image->local_base_addr);
|
||||
|
||||
if (err != MX_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = mx_vmar_allocate(image->remote_root_vmar,
|
||||
MX_VM_CAN_MAP_READ | MX_VM_CAN_MAP_WRITE |
|
||||
MX_VM_CAN_MAP_EXEC | MX_VM_CAN_MAP_SPECIFIC,
|
||||
0, size, &image->remote_exec_vmar, &image->remote_base_addr);
|
||||
image->exec_vmar_size = size;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void deduce_dynsym_count(struct elf_image *image)
|
||||
{
|
||||
if (image->hash_type == REG_HASH) {
|
||||
image->dynsym_len = *(((uint32_t *)image->hash_offset) + 1);
|
||||
} else {
|
||||
/* We don't need to know the symbol count to use DT_GNU_HASH
|
||||
* (which is good because calculating it is a pain) */
|
||||
image->dynsym_len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void read_dynamic_segment(struct elf_image *image)
|
||||
{
|
||||
elf_dyn_t *dyn_array = (elf_dyn_t *)(image->local_base_addr + image->dynamic.p_vaddr);
|
||||
|
||||
for (int i = 0;; i++) {
|
||||
elf_dyn_t *dyn = &dyn_array[i];
|
||||
|
||||
if (dyn->d_tag == DT_NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
switch (dyn->d_tag) {
|
||||
case DT_STRTAB:
|
||||
image->dynstr_offset = dyn->d_un.d_ptr;
|
||||
dyn->d_un.d_ptr += image->remote_base_addr;
|
||||
break;
|
||||
case DT_STRSZ:
|
||||
image->dynstr_len = dyn->d_un.d_val;
|
||||
break;
|
||||
case DT_SYMTAB:
|
||||
image->dynsym_offset = dyn->d_un.d_ptr;
|
||||
dyn->d_un.d_ptr += image->remote_base_addr;
|
||||
break;
|
||||
case DT_SYMENT:
|
||||
image->dynsym_entsz = dyn->d_un.d_val;
|
||||
break;
|
||||
case DT_HASH:
|
||||
/* prefer the GNU hash table */
|
||||
if (image->hash_type == GNU_HASH) {
|
||||
continue;
|
||||
}
|
||||
image->hash_type = REG_HASH;
|
||||
image->hash_offset = dyn->d_un.d_ptr;
|
||||
dyn->d_un.d_ptr += image->remote_base_addr;
|
||||
break;
|
||||
case DT_GNU_HASH:
|
||||
image->hash_type = GNU_HASH;
|
||||
image->hash_offset = dyn->d_un.d_ptr;
|
||||
dyn->d_un.d_ptr += image->remote_base_addr;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void get_memory_requirements(void *phdr_buf, int entsize, int nr_phdr,
|
||||
size_t *out_vmem, size_t *out_rw)
|
||||
{
|
||||
size_t vmem_max = 0;
|
||||
size_t rw_max = 0;
|
||||
|
||||
for (int i = 0; i < nr_phdr; i++) {
|
||||
elf_phdr_t *phdr = (elf_phdr_t *)((char *)phdr_buf + (i * entsize));
|
||||
if (phdr->p_type != PT_LOAD) {
|
||||
continue;
|
||||
}
|
||||
|
||||
size_t foffset = phdr->p_offset;
|
||||
size_t voffset = phdr->p_vaddr;
|
||||
PAGE_ALIGN_DOWN(foffset);
|
||||
PAGE_ALIGN_DOWN(voffset);
|
||||
|
||||
size_t vend = phdr->p_vaddr + phdr->p_memsz;
|
||||
PAGE_ALIGN_UP(vend);
|
||||
|
||||
size_t fsize = phdr->p_filesz;
|
||||
size_t vsize = vend - voffset;
|
||||
PAGE_ALIGN_UP(fsize);
|
||||
|
||||
if (phdr->p_flags & PF_W) {
|
||||
rw_max += vsize;
|
||||
}
|
||||
|
||||
if (vend > vmem_max) {
|
||||
vmem_max = vend;
|
||||
}
|
||||
}
|
||||
|
||||
*out_rw = rw_max;
|
||||
*out_vmem = vmem_max;
|
||||
}
|
||||
|
||||
static mx_status_t map_memory(struct elf_image *image,
|
||||
mx_off_t voffset, mx_off_t foffset, size_t sz, int flags, void **out_buf)
|
||||
{
|
||||
mx_status_t err = MX_OK;
|
||||
mx_flags_t options = MX_VM_SPECIFIC;
|
||||
mx_handle_t vmo = image->image_vmo;
|
||||
|
||||
if (flags & PF_R) {
|
||||
options |= MX_VM_PERM_READ;
|
||||
}
|
||||
|
||||
if (flags & PF_W) {
|
||||
options |= MX_VM_PERM_WRITE;
|
||||
vmo = image->rw_vmo;
|
||||
}
|
||||
|
||||
if (flags & PF_X) {
|
||||
options |= MX_VM_PERM_EXEC;
|
||||
}
|
||||
|
||||
mx_vaddr_t local_addr = 0, remote_addr = 0;
|
||||
*out_buf = NULL;
|
||||
|
||||
err = mx_vmar_map(image->local_exec_vmar, options, voffset, vmo, foffset, sz, &local_addr);
|
||||
if (err != MX_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = mx_vmar_map(image->remote_exec_vmar, options, voffset, vmo, foffset, sz, &remote_addr);
|
||||
if (err != MX_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
*out_buf = (void *)local_addr;
|
||||
return MX_OK;
|
||||
}
|
||||
|
||||
static mx_status_t map_image(struct elf_image *image,
|
||||
void *phdr_buf, int phdr_entsize, int phdr_num)
|
||||
{
|
||||
size_t rw_offset = 0;
|
||||
mx_status_t err = MX_OK;
|
||||
|
||||
for (int i = 0; i < phdr_num; i++) {
|
||||
elf_phdr_t *phdr = (elf_phdr_t *)((char *)phdr_buf + (i * phdr_entsize));
|
||||
if (phdr->p_type == PT_DYNAMIC) {
|
||||
image->dynamic = *phdr;
|
||||
}
|
||||
|
||||
if (phdr->p_type != PT_LOAD) {
|
||||
continue;
|
||||
}
|
||||
|
||||
size_t foffset = phdr->p_offset;
|
||||
size_t voffset = phdr->p_vaddr;
|
||||
PAGE_ALIGN_DOWN(foffset);
|
||||
PAGE_ALIGN_DOWN(voffset);
|
||||
|
||||
size_t vend = phdr->p_vaddr + phdr->p_memsz;
|
||||
PAGE_ALIGN_UP(vend);
|
||||
|
||||
size_t fsize = phdr->p_filesz;
|
||||
size_t vsize = vend - voffset;
|
||||
PAGE_ALIGN_UP(fsize);
|
||||
|
||||
if (phdr->p_flags & PF_W) {
|
||||
size_t rw_vmo_offset = rw_offset;
|
||||
size_t rw_vmo_size = vsize;
|
||||
|
||||
size_t bss_offset = phdr->p_vaddr + phdr->p_filesz;
|
||||
size_t bss_size = phdr->p_memsz - phdr->p_filesz;
|
||||
|
||||
void *segment_buf = NULL;
|
||||
err = map_memory(image, voffset, rw_vmo_offset, vsize, phdr->p_flags, &segment_buf);
|
||||
|
||||
if (err != MX_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
void *file_dest = (char *)image->local_base_addr + phdr->p_vaddr;
|
||||
void *bss_dest = (char *)image->local_base_addr + bss_offset;
|
||||
|
||||
mx_vmo_read(image->image_vmo, file_dest, phdr->p_filesz, phdr->p_offset);
|
||||
|
||||
if (bss_size) {
|
||||
memset(bss_dest, 0x0, bss_size);
|
||||
}
|
||||
|
||||
rw_offset += rw_vmo_size;
|
||||
} else {
|
||||
void *segment_buf = NULL;
|
||||
err = map_memory(image, voffset, foffset, vsize, phdr->p_flags, &segment_buf);
|
||||
|
||||
if (err != MX_OK) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return MX_OK;
|
||||
}
|
||||
|
||||
HIDDEN int __elf_image_load_image(struct elf_image *image, mx_handle_t image_vmo)
|
||||
{
|
||||
image->image_vmo = image_vmo;
|
||||
|
||||
int status = read_header(image);
|
||||
|
||||
if (status != 0) {
|
||||
printf("read_header error\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
size_t phdr_bufsz = image->hdr.e_phentsize * image->hdr.e_phnum;
|
||||
unsigned char phdr_buf[phdr_bufsz];
|
||||
|
||||
mx_vmo_read(image_vmo, phdr_buf, phdr_bufsz, image->hdr.e_phoff);
|
||||
|
||||
size_t rw_size, vmem_size;
|
||||
get_memory_requirements(phdr_buf, image->hdr.e_phentsize, image->hdr.e_phnum, &vmem_size, &rw_size);
|
||||
|
||||
if (allocate_vmar(image, vmem_size) != MX_OK) {
|
||||
printf("allocate_vmar error\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (rw_size) {
|
||||
mx_vmo_create(rw_size, MX_VM_PERM_READ | MX_VM_PERM_WRITE, &image->rw_vmo);
|
||||
}
|
||||
|
||||
mx_status_t err = map_image(image, phdr_buf, image->hdr.e_phentsize, image->hdr.e_phnum);
|
||||
if (err != MX_OK) {
|
||||
printf("map_image error\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
read_dynamic_segment(image);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
HIDDEN int __elf_get_interp_path(mx_handle_t image_vmo, char *out, size_t max)
|
||||
{
|
||||
elf_ehdr_t hdr;
|
||||
mx_vmo_read(image_vmo, (uint8_t *)&hdr, sizeof(hdr), 0);
|
||||
|
||||
if (elf_validate_ehdr(&hdr) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
unsigned char phdr_buf[hdr.e_phentsize * hdr.e_phnum];
|
||||
mx_vmo_read(image_vmo, phdr_buf, hdr.e_phentsize * hdr.e_phnum, hdr.e_phoff);
|
||||
|
||||
uintptr_t dynamic_offset = 0, interp_offset = 0;
|
||||
size_t dynamic_sz = 0, interp_sz = 0;
|
||||
|
||||
for (size_t i = 0; i < hdr.e_phnum; i++) {
|
||||
elf_phdr_t *phdr = (elf_phdr_t *)(phdr_buf + i * hdr.e_phentsize);
|
||||
|
||||
switch (phdr->p_type) {
|
||||
case PT_DYNAMIC:
|
||||
dynamic_offset = phdr->p_offset;
|
||||
dynamic_sz = phdr->p_filesz;
|
||||
break;
|
||||
case PT_INTERP:
|
||||
interp_offset = phdr->p_offset;
|
||||
interp_sz = phdr->p_filesz;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!dynamic_sz || !interp_offset) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (max > interp_sz) {
|
||||
max = interp_sz;
|
||||
}
|
||||
|
||||
mx_vmo_read(image_vmo, (uint8_t *)out, max, interp_offset);
|
||||
return 1;
|
||||
}
|
||||
|
||||
HIDDEN int __elf_check_dependencies(struct elf_image *image)
|
||||
{
|
||||
elf_dyn_t *dyn_array = (elf_dyn_t *)(image->local_base_addr + image->dynamic.p_vaddr);
|
||||
|
||||
for (int i = 0;; i++) {
|
||||
elf_dyn_t *dyn = &dyn_array[i];
|
||||
|
||||
if (dyn->d_tag == DT_NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (dyn->d_tag != DT_NEEDED) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const char *lib_name = (const char *)(image->local_base_addr + image->dynstr_offset + dyn->d_un.d_ptr);
|
||||
if (strcmp(lib_name, VDSO_SONAME) != 0) {
|
||||
/* We can't load executables that link to libraries other than
|
||||
* libmx */
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static elf_sym_t *get_dynsym_entry(struct elf_image *image, unsigned int idx)
|
||||
{
|
||||
return (elf_sym_t *)(image->local_base_addr + image->dynsym_offset + idx * image->dynsym_entsz);
|
||||
}
|
||||
|
||||
static const char *get_dynstr(struct elf_image *image, unsigned int idx)
|
||||
{
|
||||
return (const char *)(image->local_base_addr + image->dynstr_offset + idx);
|
||||
}
|
||||
|
||||
static int do_rela(struct elf_image *image, struct elf_image *lib, uintptr_t ptr, size_t sz, size_t entsz)
|
||||
{
|
||||
size_t entries = sz / entsz;
|
||||
|
||||
for (size_t i = 0; i < entries; i++) {
|
||||
elf_rela_t *rela = (elf_rela_t *)(image->local_base_addr + ptr + i * entsz);
|
||||
int sym_idx = ELF64_R_SYM(rela->r_info);
|
||||
int type = ELF64_R_TYPE(rela->r_info);
|
||||
|
||||
mx_vaddr_t sym_val = 0;
|
||||
if (type != R_X86_64_RELATIVE) {
|
||||
elf_sym_t *dynsym = get_dynsym_entry(image, sym_idx);
|
||||
const char *name = get_dynstr(image, dynsym->st_name);
|
||||
sym_val = __elf_image_get_symbol(image, name);
|
||||
if (!sym_val && lib) {
|
||||
sym_val = __elf_image_get_symbol(lib, name);
|
||||
}
|
||||
|
||||
if (!sym_val) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int ok = 1;
|
||||
mx_status_t status = MX_OK;
|
||||
|
||||
switch (type) {
|
||||
case R_X86_64_GLOB_DAT: {
|
||||
elf_xword_t val = sym_val;
|
||||
elf_xword_t *dest = (elf_xword_t *)((char *)image->local_base_addr + rela->r_offset);
|
||||
*dest = val;
|
||||
break;
|
||||
} case R_X86_64_64: {
|
||||
elf_xword_t val = sym_val + rela->r_addend;
|
||||
elf_xword_t *dest = (elf_xword_t *)((char *)image->local_base_addr + rela->r_offset);
|
||||
*dest = val;
|
||||
break;
|
||||
} case R_X86_64_JUMP_SLOT: {
|
||||
elf_xword_t val = sym_val;
|
||||
elf_xword_t *dest = (elf_xword_t *)((char *)image->local_base_addr + rela->r_offset);
|
||||
*dest = val;
|
||||
break;
|
||||
} case R_X86_64_RELATIVE: {
|
||||
elf_xword_t val = image->remote_base_addr + rela->r_addend;
|
||||
elf_xword_t *dest = (elf_xword_t *)((char *)image->local_base_addr + rela->r_offset);
|
||||
*dest = val;
|
||||
break;
|
||||
} default:
|
||||
ok = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!ok || status != MX_OK) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int relocate(struct elf_image *image, struct elf_image *lib)
|
||||
{
|
||||
elf_dyn_t *dyn_array = (elf_dyn_t *)(image->local_base_addr + image->dynamic.p_vaddr);
|
||||
|
||||
int result = 0;
|
||||
|
||||
uintptr_t rel_addr = 0, rela_addr = 0, plt_addr = 0;
|
||||
size_t rel_sz = 0, rel_entsz = 0;
|
||||
size_t rela_sz = 0, rela_entsz = 0;
|
||||
size_t plt_sz = 0, plt_entsz = 0;
|
||||
int plt_enttype;
|
||||
for (int i = 0;; i++) {
|
||||
elf_dyn_t *dyn = &dyn_array[i];
|
||||
|
||||
if (dyn->d_tag == DT_NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
switch (dyn->d_tag) {
|
||||
case DT_REL:
|
||||
rel_addr = dyn->d_un.d_ptr;
|
||||
break;
|
||||
case DT_RELSZ:
|
||||
rel_sz = dyn->d_un.d_val;
|
||||
break;
|
||||
case DT_RELENT:
|
||||
rel_entsz = dyn->d_un.d_val;
|
||||
break;
|
||||
case DT_RELA:
|
||||
rela_addr = dyn->d_un.d_ptr;
|
||||
break;
|
||||
case DT_RELASZ:
|
||||
rela_sz = dyn->d_un.d_val;
|
||||
break;
|
||||
case DT_RELAENT:
|
||||
rela_entsz = dyn->d_un.d_val;
|
||||
break;
|
||||
case DT_PLTRELSZ:
|
||||
plt_sz = dyn->d_un.d_val;
|
||||
break;
|
||||
case DT_JMPREL:
|
||||
plt_addr = dyn->d_un.d_ptr;
|
||||
break;
|
||||
case DT_PLTREL:
|
||||
plt_enttype = dyn->d_un.d_ptr;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (dyn->d_tag != DT_NEEDED) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (rel_sz) {
|
||||
/* DT_REL is not supported */
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (plt_enttype == DT_RELA) {
|
||||
plt_entsz = rela_entsz ? rela_entsz : sizeof(elf_rela_t);
|
||||
} else if (plt_enttype == DT_REL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int r;
|
||||
if (rela_sz) {
|
||||
r = do_rela(image, lib, rela_addr, rela_sz, rela_entsz);
|
||||
if (r != 0) {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
if (plt_sz) {
|
||||
r = do_rela(image, lib, plt_addr, plt_sz, plt_entsz);
|
||||
if (r != 0) {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
HIDDEN int __elf_image_link(struct elf_image *exec, struct elf_image *vdso)
|
||||
{
|
||||
int status = relocate(vdso, NULL);
|
||||
if (status != 0) {
|
||||
return status;
|
||||
}
|
||||
|
||||
return relocate(exec, vdso);
|
||||
}
|
||||
|
||||
HIDDEN mx_vaddr_t __elf_image_entry_point(struct elf_image *image)
|
||||
{
|
||||
return image->remote_base_addr + image->hdr.e_entry;
|
||||
}
|
||||
|
||||
static uint32_t gnu_hash(const char *name)
|
||||
{
|
||||
uint32_t h = 5381;
|
||||
for (; *name; name++) {
|
||||
h = (h << 5) + h + *name;
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
static mx_vaddr_t sym_gnu_hash_search(struct elf_image *image, const char *name)
|
||||
{
|
||||
uint32_t hash = gnu_hash(name);
|
||||
uint32_t *hashtab = (uint32_t *)(image->local_base_addr + image->hash_offset);
|
||||
|
||||
uint32_t nbuckets = hashtab[0];
|
||||
uint32_t symoffset = hashtab[1];
|
||||
uint32_t bloom_size = hashtab[2];
|
||||
uint32_t bloom_shift = hashtab[3];
|
||||
uint64_t *bloom = (uint64_t *)&hashtab[4];
|
||||
uint32_t *buckets = (uint32_t *)&bloom[bloom_size];
|
||||
uint32_t *chain = &buckets[nbuckets];
|
||||
|
||||
uint64_t bloom_word =
|
||||
bloom[(hash / elf_class_bits(image)) % bloom_size];
|
||||
uint64_t bloom_mask =
|
||||
((uint64_t)1 << (hash % elf_class_bits(image))) |
|
||||
((uint64_t)1 << ((hash >> bloom_shift) % elf_class_bits(image)));
|
||||
|
||||
if ((bloom_word & bloom_mask) != bloom_mask) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t symix = buckets[hash % nbuckets];
|
||||
if (symix < symoffset) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *strtab = (const char *)(image->local_base_addr + image->dynstr_offset);
|
||||
elf_sym_t *symtab = (elf_sym_t *)(image->local_base_addr + image->dynsym_offset);
|
||||
|
||||
while (1) {
|
||||
const char *symname = strtab + symtab[symix].st_name;
|
||||
uint32_t symhash = chain[symix - symoffset];
|
||||
|
||||
if ((symhash | 1) == (hash | 1) && !strcmp(symname, name)) {
|
||||
return image->remote_base_addr + symtab[symix].st_value;
|
||||
}
|
||||
|
||||
if (symhash & 1) {
|
||||
break;
|
||||
}
|
||||
|
||||
symix++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
HIDDEN mx_vaddr_t __elf_image_get_symbol(struct elf_image *image, const char *name)
|
||||
{
|
||||
switch (image->hash_type) {
|
||||
case GNU_HASH:
|
||||
return sym_gnu_hash_search(image, name);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
HIDDEN void __elf_image_cleanup(struct elf_image *image)
|
||||
{
|
||||
if (image->local_exec_vmar) {
|
||||
mx_vmar_unmap(image->local_exec_vmar, 0, image->exec_vmar_size);
|
||||
mx_vmar_destroy(image->local_exec_vmar);
|
||||
mx_handle_close(image->local_exec_vmar);
|
||||
image->local_exec_vmar = MX_NULL_HANDLE;
|
||||
}
|
||||
|
||||
if (image->remote_exec_vmar) {
|
||||
mx_handle_close(image->remote_exec_vmar);
|
||||
image->remote_exec_vmar = MX_NULL_HANDLE;
|
||||
}
|
||||
|
||||
if (image->rw_vmo) {
|
||||
mx_handle_close(image->rw_vmo);
|
||||
image->rw_vmo = MX_NULL_HANDLE;
|
||||
}
|
||||
}
|
||||
@@ -17,8 +17,6 @@
|
||||
#include "__heap.h"
|
||||
#include "__fio.h"
|
||||
|
||||
#define DYLD_PARENT_IMAGE
|
||||
|
||||
/* maximum of 32 handles can be received sent as arguments */
|
||||
#define MAX_HANDLE_ARGS 32
|
||||
|
||||
@@ -258,6 +256,7 @@ static int do_init(mx_handle_t bootstrap, bool enable_fs, bool enable_stdio, int
|
||||
#endif
|
||||
|
||||
dbg_log("extracted %zu handles\n", nr_handles);
|
||||
|
||||
mx_bootstrap_handle_init(arg_handles, nr_handles);
|
||||
|
||||
const char **argv = NULL, **envp = NULL, **namep = NULL;
|
||||
@@ -287,16 +286,19 @@ static int do_init(mx_handle_t bootstrap, bool enable_fs, bool enable_stdio, int
|
||||
|
||||
mio_namespace *ns = mio_namespace_create();
|
||||
|
||||
dbg_log("received %u names/%zu handles\n", msg->names_num, nr_handles);
|
||||
if (msg->names_num > 0) {
|
||||
for (size_t i = 0; i < nr_handles; i++) {
|
||||
int type = MX_B_HND_TYPE(arg_handles[i].info);
|
||||
int arg = MX_B_HND_ARG(arg_handles[i].info);
|
||||
|
||||
if (type != MX_B_NS_DIR && type != MX_B_TUNNEL_CWD) {
|
||||
dbg_log(" * wrong type %x\n", type);
|
||||
continue;
|
||||
}
|
||||
|
||||
const char *path = namep[arg];
|
||||
dbg_log(" * %s = %x\n", path, arg_handles[i].handle);
|
||||
|
||||
if (type == MX_B_TUNNEL_CWD) {
|
||||
mio_set_cwd(arg_handles[i].handle, path);
|
||||
@@ -329,7 +331,7 @@ static int do_load_and_run(mx_handle_t bootstrap)
|
||||
int argc;
|
||||
const char **argv;
|
||||
|
||||
int err = do_init(bootstrap, false, false, &argc, &argv);
|
||||
int err = do_init(bootstrap, false, true, &argc, &argv);
|
||||
if (err != 0) {
|
||||
return err;
|
||||
}
|
||||
|
||||
1224
photon/libc/sys/horizon/launch.c
Normal file
1224
photon/libc/sys/horizon/launch.c
Normal file
File diff suppressed because it is too large
Load Diff
BIN
photon/libc/sys/horizon/launch.tar.xz
Normal file
BIN
photon/libc/sys/horizon/launch.tar.xz
Normal file
Binary file not shown.
52
photon/libc/sys/horizon/sys/launch.h
Normal file
52
photon/libc/sys/horizon/sys/launch.h
Normal file
@@ -0,0 +1,52 @@
|
||||
#ifndef SYS_HORIZON_SYS_LAUNCH_H_
|
||||
#define SYS_HORIZON_SYS_LAUNCH_H_
|
||||
|
||||
#include <magenta/bootstrap.h>
|
||||
|
||||
#define FD_NONE -1
|
||||
#define FD_INHERIT -2
|
||||
|
||||
#define LAUNCH_MAX_FDS 3
|
||||
|
||||
#define NS_ENTRY_FD(p, f) { .path = (p), .src = NULL, .fd = (f), .handle = MX_NULL_HANDLE }
|
||||
#define NS_ENTRY_HANDLE(p, h) { .path = (p), .src = NULL, .fd = -1, .handle = (h) }
|
||||
#define NS_ENTRY_PATH(p, s) { .path = (p), .src = (s), .fd = -1, .handle = MX_NULL_HANDLE }
|
||||
|
||||
enum launch_flags {
|
||||
/* inherit parent task's namespace. if this flag is set,
|
||||
* launch_info.ns must be NULL. */
|
||||
LAUNCH_INHERIT_NS = 0x01u,
|
||||
/* use launch_info.fd as the new task's stdio file descriptors */
|
||||
LAUNCH_SET_FD = 0x02u,
|
||||
};
|
||||
|
||||
struct namespace_entry {
|
||||
const char *path, *src;
|
||||
|
||||
/* if this is not -1, handle must be MX_NULL_HANDLE */
|
||||
int fd;
|
||||
/* if this is not MX_NULL_HANDLE, fd must be -1 */
|
||||
mx_handle_t handle;
|
||||
};
|
||||
|
||||
struct launch_info {
|
||||
enum launch_flags flags;
|
||||
const char *path;
|
||||
|
||||
int argc;
|
||||
const char **argv;
|
||||
|
||||
int fd[LAUNCH_MAX_FDS];
|
||||
|
||||
struct namespace_entry cwd;
|
||||
const struct namespace_entry *ns;
|
||||
size_t ns_count;
|
||||
|
||||
const mx_bootstrap_handle_t *handles;
|
||||
size_t handle_count;
|
||||
};
|
||||
|
||||
extern int launch(const struct launch_info *info, mx_handle_t *out_task);
|
||||
extern const char *launch_error(void);
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user