ld.so: fix build on macOS
This commit is contained in:
parent
33499036e4
commit
b9f0f8cbd1
135
src/loader.c
135
src/loader.c
@ -35,7 +35,11 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <elf.h>
|
#if defined(__APPLE__)
|
||||||
|
# include <mach-o/loader.h>
|
||||||
|
#elif defined(__ELF__)
|
||||||
|
# include <elf.h>
|
||||||
|
#endif
|
||||||
#include "loader.h"
|
#include "loader.h"
|
||||||
|
|
||||||
#ifndef PROGNAME_LOADER
|
#ifndef PROGNAME_LOADER
|
||||||
@ -46,9 +50,9 @@
|
|||||||
/* Loader */
|
/* Loader */
|
||||||
/* private */
|
/* private */
|
||||||
/* prototypes */
|
/* prototypes */
|
||||||
static int _error(int code, char const * format, ...);
|
static int _loader_elf(int fd, char const * filename, int argc, char * argv[]);
|
||||||
|
|
||||||
static int _prot(int flags);
|
static int _error(int code, char const * format, ...);
|
||||||
|
|
||||||
|
|
||||||
/* public */
|
/* public */
|
||||||
@ -58,14 +62,6 @@ extern char ** environ;
|
|||||||
|
|
||||||
/* functions */
|
/* functions */
|
||||||
/* loader */
|
/* loader */
|
||||||
static int _loader_do(int fd, char const * filename, int argc, char * argv[]);
|
|
||||||
static int _do_phdr(int fd, char const * filename, Elf_Ehdr * ehdr,
|
|
||||||
void ** entrypoint);
|
|
||||||
static size_t _do_phdr_align_bits(unsigned long align);
|
|
||||||
static int _do_shdr(int fd, char const * filename, Elf_Ehdr * ehdr);
|
|
||||||
static int _do_shdr_rela(int fd, char const * filename, Elf_Shdr * shdr,
|
|
||||||
size_t entsize);
|
|
||||||
|
|
||||||
int loader(char const * filename, int argc, char * argv[])
|
int loader(char const * filename, int argc, char * argv[])
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
@ -73,12 +69,24 @@ int loader(char const * filename, int argc, char * argv[])
|
|||||||
|
|
||||||
if((fd = open(filename, O_RDONLY)) < 0)
|
if((fd = open(filename, O_RDONLY)) < 0)
|
||||||
return _error(2, "%s: %s", filename, strerror(errno));
|
return _error(2, "%s: %s", filename, strerror(errno));
|
||||||
ret = _loader_do(fd, filename, argc, argv);
|
ret = _loader_elf(fd, filename, argc, argv);
|
||||||
close(fd);
|
close(fd);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _loader_do(int fd, char const * filename, int argc, char * argv[])
|
|
||||||
|
/* private */
|
||||||
|
/* functions */
|
||||||
|
#if defined(__ELF__)
|
||||||
|
static int _elf_phdr(int fd, char const * filename, Elf_Ehdr * ehdr,
|
||||||
|
void ** entrypoint);
|
||||||
|
static size_t _elf_phdr_align_bits(unsigned long align);
|
||||||
|
static int _elf_prot(int flags);
|
||||||
|
static int _elf_shdr(int fd, char const * filename, Elf_Ehdr * ehdr);
|
||||||
|
static int _elf_shdr_rela(int fd, char const * filename, Elf_Shdr * shdr,
|
||||||
|
size_t entsize);
|
||||||
|
|
||||||
|
static int _loader_elf(int fd, char const * filename, int argc, char * argv[])
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
Elf_Ehdr ehdr;
|
Elf_Ehdr ehdr;
|
||||||
@ -95,21 +103,21 @@ static int _loader_do(int fd, char const * filename, int argc, char * argv[])
|
|||||||
if(ehdr.e_ehsize != sizeof(ehdr))
|
if(ehdr.e_ehsize != sizeof(ehdr))
|
||||||
return _error(2, "%s: %s", filename,
|
return _error(2, "%s: %s", filename,
|
||||||
"Invalid or unsupported ELF file");
|
"Invalid or unsupported ELF file");
|
||||||
if((ret = _do_phdr(fd, filename, &ehdr, &entrypoint)) != 0
|
if((ret = _elf_phdr(fd, filename, &ehdr, &entrypoint)) != 0
|
||||||
|| (ret = _do_shdr(fd, filename, &ehdr)) != 0)
|
|| (ret = _elf_shdr(fd, filename, &ehdr)) != 0)
|
||||||
return ret;
|
return ret;
|
||||||
if(entrypoint == NULL)
|
if(entrypoint == NULL)
|
||||||
return _error(2, "%s: %s", filename, "Entrypoint not set");
|
return _error(2, "%s: %s", filename, "Entrypoint not set");
|
||||||
#ifdef DEBUG
|
# ifdef DEBUG
|
||||||
fprintf(stderr, "DEBUG: loader_enter(%d, %p, %p, %p, %p)\n",
|
fprintf(stderr, "DEBUG: loader_enter(%d, %p, %p, %p, %p)\n",
|
||||||
argc, argv, environ, NULL, entrypoint);
|
argc, argv, environ, NULL, entrypoint);
|
||||||
#endif
|
# endif
|
||||||
ret = loader_enter(argc, argv, environ, NULL, entrypoint);
|
ret = loader_enter(argc, argv, environ, NULL, entrypoint);
|
||||||
_exit(ret);
|
_exit(ret);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _do_phdr(int fd, char const * filename, Elf_Ehdr * ehdr,
|
static int _elf_phdr(int fd, char const * filename, Elf_Ehdr * ehdr,
|
||||||
void ** entrypoint)
|
void ** entrypoint)
|
||||||
{
|
{
|
||||||
Elf_Phdr phdr;
|
Elf_Phdr phdr;
|
||||||
@ -130,7 +138,7 @@ static int _do_phdr(int fd, char const * filename, Elf_Ehdr * ehdr,
|
|||||||
if(read(fd, &phdr, sizeof(phdr)) != sizeof(phdr))
|
if(read(fd, &phdr, sizeof(phdr)) != sizeof(phdr))
|
||||||
return _error(2, "%s: %s", filename,
|
return _error(2, "%s: %s", filename,
|
||||||
"Invalid or unsupported ELF file");
|
"Invalid or unsupported ELF file");
|
||||||
#ifdef DEBUG
|
# ifdef DEBUG
|
||||||
fprintf(stderr, "DEBUG: %zu: p_type=%u p_flags=%#x"
|
fprintf(stderr, "DEBUG: %zu: p_type=%u p_flags=%#x"
|
||||||
" p_offset=%#lx p_vaddr=%#lx, p_paddr=%#lx"
|
" p_offset=%#lx p_vaddr=%#lx, p_paddr=%#lx"
|
||||||
" p_filesz=%lu p_memsz=%lu p_align=%lu\n", i,
|
" p_filesz=%lu p_memsz=%lu p_align=%lu\n", i,
|
||||||
@ -141,31 +149,20 @@ static int _do_phdr(int fd, char const * filename, Elf_Ehdr * ehdr,
|
|||||||
(unsigned long)phdr.p_filesz,
|
(unsigned long)phdr.p_filesz,
|
||||||
(unsigned long)phdr.p_memsz,
|
(unsigned long)phdr.p_memsz,
|
||||||
(unsigned long)phdr.p_align);
|
(unsigned long)phdr.p_align);
|
||||||
#endif
|
# endif
|
||||||
if(phdr.p_type != PT_LOAD)
|
if(phdr.p_type != PT_LOAD)
|
||||||
continue;
|
continue;
|
||||||
flags = MAP_ALIGNED(_do_phdr_align_bits(phdr.p_align));
|
flags = MAP_ALIGNED(_elf_phdr_align_bits(phdr.p_align));
|
||||||
if(phdr.p_filesz == 0)
|
if(phdr.p_filesz == 0)
|
||||||
{
|
{
|
||||||
#if 0
|
|
||||||
addr = NULL;
|
|
||||||
#endif
|
|
||||||
flags |= MAP_ANON;
|
flags |= MAP_ANON;
|
||||||
prot = _prot(phdr.p_flags);
|
prot = _elf_prot(phdr.p_flags);
|
||||||
f = -1;
|
f = -1;
|
||||||
offset = 0;
|
offset = 0;
|
||||||
}
|
}
|
||||||
else if(phdr.p_filesz == phdr.p_memsz)
|
else if(phdr.p_filesz == phdr.p_memsz)
|
||||||
{
|
{
|
||||||
#if 0
|
|
||||||
addr = (void *)phdr.p_vaddr;
|
|
||||||
#endif
|
|
||||||
flags |= MAP_FILE;
|
flags |= MAP_FILE;
|
||||||
prot = _prot(phdr.p_flags);
|
|
||||||
#if 0
|
|
||||||
if(phdr.p_vaddr != 0)
|
|
||||||
flags |= MAP_TRYFIXED;
|
|
||||||
#endif
|
|
||||||
if(prot & PROT_WRITE)
|
if(prot & PROT_WRITE)
|
||||||
flags |= MAP_PRIVATE;
|
flags |= MAP_PRIVATE;
|
||||||
f = fd;
|
f = fd;
|
||||||
@ -181,11 +178,11 @@ static int _do_phdr(int fd, char const * filename, Elf_Ehdr * ehdr,
|
|||||||
else
|
else
|
||||||
return _error(2, "%s: %s", filename,
|
return _error(2, "%s: %s", filename,
|
||||||
"Invalid or unsupported ELF file");
|
"Invalid or unsupported ELF file");
|
||||||
#ifdef DEBUG
|
# ifdef DEBUG
|
||||||
fprintf(stderr, "DEBUG: mmap(%p, %lu, %d, %d, %d, %lld)\n",
|
fprintf(stderr, "DEBUG: mmap(%p, %lu, %d, %d, %d, %lld)\n",
|
||||||
NULL, (unsigned long)phdr.p_memsz, prot, flags,
|
NULL, (unsigned long)phdr.p_memsz, prot, flags,
|
||||||
f, (long long)offset);
|
f, (long long)offset);
|
||||||
#endif
|
# endif
|
||||||
if((addr = mmap(NULL, phdr.p_memsz, prot, flags, f, offset))
|
if((addr = mmap(NULL, phdr.p_memsz, prot, flags, f, offset))
|
||||||
== MAP_FAILED)
|
== MAP_FAILED)
|
||||||
return _error(2, "%s: %s", filename, strerror(errno));
|
return _error(2, "%s: %s", filename, strerror(errno));
|
||||||
@ -199,11 +196,11 @@ static int _do_phdr(int fd, char const * filename, Elf_Ehdr * ehdr,
|
|||||||
strerror(errno));
|
strerror(errno));
|
||||||
memset(&addr[phdr.p_filesz], 0,
|
memset(&addr[phdr.p_filesz], 0,
|
||||||
phdr.p_memsz - phdr.p_filesz);
|
phdr.p_memsz - phdr.p_filesz);
|
||||||
prot = _prot(phdr.p_flags);
|
prot = _elf_prot(phdr.p_flags);
|
||||||
#ifdef DEBUG
|
# ifdef DEBUG
|
||||||
fprintf(stderr, "DEBUG: mprotect(%p, %lu, %d)\n",
|
fprintf(stderr, "DEBUG: mprotect(%p, %lu, %d)\n",
|
||||||
addr, (unsigned long)phdr.p_memsz, prot);
|
addr, (unsigned long)phdr.p_memsz, prot);
|
||||||
#endif
|
# endif
|
||||||
if(prot != (PROT_READ | PROT_WRITE)
|
if(prot != (PROT_READ | PROT_WRITE)
|
||||||
&& mprotect(addr, phdr.p_memsz,
|
&& mprotect(addr, phdr.p_memsz,
|
||||||
prot) != 0)
|
prot) != 0)
|
||||||
@ -218,19 +215,19 @@ static int _do_phdr(int fd, char const * filename, Elf_Ehdr * ehdr,
|
|||||||
{
|
{
|
||||||
*entrypoint = (char *)(ehdr->e_entry - phdr.p_vaddr
|
*entrypoint = (char *)(ehdr->e_entry - phdr.p_vaddr
|
||||||
+ (intptr_t)addr);
|
+ (intptr_t)addr);
|
||||||
#ifdef DEBUG
|
# ifdef DEBUG
|
||||||
fprintf(stderr, "DEBUG: e_entry=%#lx p_vaddr=%#lx"
|
fprintf(stderr, "DEBUG: e_entry=%#lx p_vaddr=%#lx"
|
||||||
" addr=%p => %p\n",
|
" addr=%p => %p\n",
|
||||||
(unsigned long)ehdr->e_entry,
|
(unsigned long)ehdr->e_entry,
|
||||||
(unsigned long)phdr.p_vaddr,
|
(unsigned long)phdr.p_vaddr,
|
||||||
addr, *entrypoint);
|
addr, *entrypoint);
|
||||||
#endif
|
# endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t _do_phdr_align_bits(unsigned long align)
|
static size_t _elf_phdr_align_bits(unsigned long align)
|
||||||
{
|
{
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
|
|
||||||
@ -239,16 +236,26 @@ static size_t _do_phdr_align_bits(unsigned long align)
|
|||||||
for(i = 0; i < sizeof(align) * 8; i++)
|
for(i = 0; i < sizeof(align) * 8; i++)
|
||||||
if(align & (1 << i))
|
if(align & (1 << i))
|
||||||
{
|
{
|
||||||
#ifdef DEBUG
|
# ifdef DEBUG
|
||||||
fprintf(stderr, "DEBUG: %s(0x%lx) => %zu\n", __func__,
|
fprintf(stderr, "DEBUG: %s(0x%lx) => %zu\n", __func__,
|
||||||
align, i);
|
align, i);
|
||||||
#endif
|
# endif
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _do_shdr(int fd, char const * filename, Elf_Ehdr * ehdr)
|
static int _elf_prot(int flags)
|
||||||
|
{
|
||||||
|
int ret = PROT_NONE;
|
||||||
|
|
||||||
|
ret |= (flags & PF_R) ? PROT_READ : 0;
|
||||||
|
ret |= (flags & PF_W) ? PROT_WRITE : 0;
|
||||||
|
ret |= (flags & PF_X) ? PROT_EXEC : 0;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _elf_shdr(int fd, char const * filename, Elf_Ehdr * ehdr)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
Elf_Shdr shdr;
|
Elf_Shdr shdr;
|
||||||
@ -265,7 +272,7 @@ static int _do_shdr(int fd, char const * filename, Elf_Ehdr * ehdr)
|
|||||||
if(read(fd, &shdr, sizeof(shdr)) != sizeof(shdr))
|
if(read(fd, &shdr, sizeof(shdr)) != sizeof(shdr))
|
||||||
return _error(2, "%s: %s", filename,
|
return _error(2, "%s: %s", filename,
|
||||||
"Invalid or unsupported ELF file");
|
"Invalid or unsupported ELF file");
|
||||||
#ifdef DEBUG
|
# ifdef DEBUG
|
||||||
fprintf(stderr, "DEBUG: %zu: sh_name=%u sh_type=%u"
|
fprintf(stderr, "DEBUG: %zu: sh_name=%u sh_type=%u"
|
||||||
" sh_flags=%#lx sh_addr=%#lx sh_offset=%#lx"
|
" sh_flags=%#lx sh_addr=%#lx sh_offset=%#lx"
|
||||||
" sh_size=%lu sh_link=%u sh_info=%u"
|
" sh_size=%lu sh_link=%u sh_info=%u"
|
||||||
@ -278,10 +285,10 @@ static int _do_shdr(int fd, char const * filename, Elf_Ehdr * ehdr)
|
|||||||
shdr.sh_link, shdr.sh_info,
|
shdr.sh_link, shdr.sh_info,
|
||||||
(unsigned long)shdr.sh_addralign,
|
(unsigned long)shdr.sh_addralign,
|
||||||
(unsigned long)shdr.sh_entsize);
|
(unsigned long)shdr.sh_entsize);
|
||||||
#endif
|
# endif
|
||||||
if(shdr.sh_type == SHT_REL
|
if(shdr.sh_type == SHT_REL
|
||||||
|| shdr.sh_type == SHT_RELA)
|
|| shdr.sh_type == SHT_RELA)
|
||||||
ret = _do_shdr_rela(fd, filename, &shdr,
|
ret = _elf_shdr_rela(fd, filename, &shdr,
|
||||||
shdr.sh_entsize);
|
shdr.sh_entsize);
|
||||||
else
|
else
|
||||||
continue;
|
continue;
|
||||||
@ -294,7 +301,7 @@ static int _do_shdr(int fd, char const * filename, Elf_Ehdr * ehdr)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _do_shdr_rela(int fd, char const * filename, Elf_Shdr * shdr,
|
static int _elf_shdr_rela(int fd, char const * filename, Elf_Shdr * shdr,
|
||||||
size_t entsize)
|
size_t entsize)
|
||||||
{
|
{
|
||||||
Elf_Rela rela;
|
Elf_Rela rela;
|
||||||
@ -312,16 +319,16 @@ static int _do_shdr_rela(int fd, char const * filename, Elf_Shdr * shdr,
|
|||||||
if(read(fd, &rela, entsize) != (ssize_t)entsize)
|
if(read(fd, &rela, entsize) != (ssize_t)entsize)
|
||||||
return _error(2, "%s: %s", filename,
|
return _error(2, "%s: %s", filename,
|
||||||
"Invalid or unsupported ELF file");
|
"Invalid or unsupported ELF file");
|
||||||
#ifdef DEBUG
|
# ifdef DEBUG
|
||||||
fprintf(stderr, "DEBUG: %zu: r_offset=%#lx r_type=%lu"
|
fprintf(stderr, "DEBUG: %zu: r_offset=%#lx r_type=%lu"
|
||||||
" r_addend=%ld\n", i,
|
" r_addend=%ld\n", i,
|
||||||
(unsigned long)rela.r_offset,
|
(unsigned long)rela.r_offset,
|
||||||
(unsigned long)ELF_R_TYPE(rela.r_info),
|
(unsigned long)ELF_R_TYPE(rela.r_info),
|
||||||
(long)rela.r_addend);
|
(long)rela.r_addend);
|
||||||
#endif
|
# endif
|
||||||
switch(ELF_R_TYPE(rela.r_info))
|
switch(ELF_R_TYPE(rela.r_info))
|
||||||
{
|
{
|
||||||
#if defined(__amd64__)
|
# if defined(__amd64__)
|
||||||
case R_X86_64_NONE:
|
case R_X86_64_NONE:
|
||||||
break;
|
break;
|
||||||
case R_X86_64_GLOB_DAT:
|
case R_X86_64_GLOB_DAT:
|
||||||
@ -329,7 +336,7 @@ static int _do_shdr_rela(int fd, char const * filename, Elf_Shdr * shdr,
|
|||||||
case R_X86_64_RELATIVE:
|
case R_X86_64_RELATIVE:
|
||||||
/* FIXME implement */
|
/* FIXME implement */
|
||||||
break;
|
break;
|
||||||
#endif
|
# endif
|
||||||
default:
|
default:
|
||||||
return _error(2, "%s: %lu:"
|
return _error(2, "%s: %lu:"
|
||||||
" Unsupported relocation\n",
|
" Unsupported relocation\n",
|
||||||
@ -339,10 +346,18 @@ static int _do_shdr_rela(int fd, char const * filename, Elf_Shdr * shdr,
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
static int _loader_elf(int fd, char const * filename, int argc, char * argv[])
|
||||||
|
{
|
||||||
|
(void) fd;
|
||||||
|
(void) argc;
|
||||||
|
(void) argv;
|
||||||
|
|
||||||
|
return _error(1, "%s: %s", filename, "Unsupported file format");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* private */
|
|
||||||
/* functions */
|
|
||||||
/* error */
|
/* error */
|
||||||
static int _error(int code, char const * format, ...)
|
static int _error(int code, char const * format, ...)
|
||||||
{
|
{
|
||||||
@ -355,15 +370,3 @@ static int _error(int code, char const * format, ...)
|
|||||||
fputs("\n", stderr);
|
fputs("\n", stderr);
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* prot */
|
|
||||||
static int _prot(int flags)
|
|
||||||
{
|
|
||||||
int ret = PROT_NONE;
|
|
||||||
|
|
||||||
ret |= (flags & PF_R) ? PROT_READ : 0;
|
|
||||||
ret |= (flags & PF_W) ? PROT_WRITE : 0;
|
|
||||||
ret |= (flags & PF_X) ? PROT_EXEC : 0;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
@ -6,8 +6,8 @@ asflags=$(CPPFLAGS) $(CFLAGS)
|
|||||||
cppflags_force=
|
cppflags_force=
|
||||||
cflags_force=-g
|
cflags_force=-g
|
||||||
cflags=-W -Wall -O2 -fPIE -D_FORTIFY_SOURCE=2 -fstack-protector
|
cflags=-W -Wall -O2 -fPIE -D_FORTIFY_SOURCE=2 -fstack-protector
|
||||||
ldflags_force=-static
|
ldflags_force=
|
||||||
ldflags=-pie -Wl,-z,relro -Wl,-z,now
|
ldflags=-static -pie -Wl,-z,relro -Wl,-z,now
|
||||||
dist=Makefile,loader.h
|
dist=Makefile,loader.h
|
||||||
mode=amd64-debug
|
mode=amd64-debug
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user