ld.so: fix build on macOS

This commit is contained in:
Pierre Pronchery 2021-10-10 19:37:46 +02:00
parent 33499036e4
commit b9f0f8cbd1
2 changed files with 71 additions and 68 deletions

View File

@ -35,7 +35,11 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <errno.h> #include <errno.h>
#if defined(__APPLE__)
# include <mach-o/loader.h>
#elif defined(__ELF__)
# include <elf.h> # 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,8 +103,8 @@ 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");
@ -109,7 +117,7 @@ static int _loader_do(int fd, char const * filename, int argc, char * argv[])
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;
@ -144,28 +152,17 @@ static int _do_phdr(int fd, char const * filename, Elf_Ehdr * ehdr,
# 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;
@ -199,7 +196,7 @@ 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);
@ -230,7 +227,7 @@ static int _do_phdr(int fd, char const * filename, Elf_Ehdr * ehdr,
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;
@ -248,7 +245,17 @@ static size_t _do_phdr_align_bits(unsigned long align)
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;
@ -281,7 +288,7 @@ static int _do_shdr(int fd, char const * filename, Elf_Ehdr * ehdr)
# 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;
@ -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;
}

View File

@ -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