107 lines
3.2 KiB
C
107 lines
3.2 KiB
C
|
#ifdef SUPPORT_ANDROID_PRELINK_TAGS
|
||
|
|
||
|
#include <sys/types.h>
|
||
|
#include <fcntl.h>
|
||
|
#include <sys/types.h>
|
||
|
#include <unistd.h>
|
||
|
#include <string.h>
|
||
|
#include <errno.h>
|
||
|
|
||
|
#include <prelink_info.h>
|
||
|
#include <debug.h>
|
||
|
#include <common.h>
|
||
|
|
||
|
typedef struct {
|
||
|
int32_t mmap_addr;
|
||
|
char tag[4]; /* 'P', 'R', 'E', ' ' */
|
||
|
} prelink_info_t __attribute__((packed));
|
||
|
|
||
|
static inline void set_prelink(long *prelink_addr,
|
||
|
int elf_little,
|
||
|
prelink_info_t *info)
|
||
|
{
|
||
|
FAILIF(sizeof(prelink_info_t) != 8, "Unexpected sizeof(prelink_info_t) == %d!\n", sizeof(prelink_info_t));
|
||
|
if (prelink_addr) {
|
||
|
if (!(elf_little ^ is_host_little())) {
|
||
|
/* Same endianness */
|
||
|
*prelink_addr = info->mmap_addr;
|
||
|
}
|
||
|
else {
|
||
|
/* Different endianness */
|
||
|
*prelink_addr = switch_endianness(info->mmap_addr);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int check_prelinked(const char *fname, int elf_little, long *prelink_addr)
|
||
|
{
|
||
|
FAILIF(sizeof(prelink_info_t) != 8, "Unexpected sizeof(prelink_info_t) == %d!\n", sizeof(prelink_info_t));
|
||
|
int fd = open(fname, O_RDONLY);
|
||
|
FAILIF(fd < 0, "open(%s, O_RDONLY): %s (%d)!\n",
|
||
|
fname, strerror(errno), errno);
|
||
|
off_t end = lseek(fd, 0, SEEK_END);
|
||
|
|
||
|
int nr = sizeof(prelink_info_t);
|
||
|
|
||
|
off_t sz = lseek(fd, -nr, SEEK_CUR);
|
||
|
ASSERT((long)(end - sz) == (long)nr);
|
||
|
FAILIF(sz == (off_t)-1,
|
||
|
"lseek(%d, 0, SEEK_END): %s (%d)!\n",
|
||
|
fd, strerror(errno), errno);
|
||
|
|
||
|
prelink_info_t info;
|
||
|
int num_read = read(fd, &info, nr);
|
||
|
FAILIF(num_read < 0,
|
||
|
"read(%d, &info, sizeof(prelink_info_t)): %s (%d)!\n",
|
||
|
fd, strerror(errno), errno);
|
||
|
FAILIF(num_read != sizeof(info),
|
||
|
"read(%d, &info, sizeof(prelink_info_t)): did not read %d bytes as "
|
||
|
"expected (read %d)!\n",
|
||
|
fd, sizeof(info), num_read);
|
||
|
|
||
|
int prelinked = 0;
|
||
|
if (!strncmp(info.tag, "PRE ", 4)) {
|
||
|
set_prelink(prelink_addr, elf_little, &info);
|
||
|
prelinked = 1;
|
||
|
}
|
||
|
FAILIF(close(fd) < 0, "close(%d): %s (%d)!\n", fd, strerror(errno), errno);
|
||
|
return prelinked;
|
||
|
}
|
||
|
|
||
|
void setup_prelink_info(const char *fname, int elf_little, long base)
|
||
|
{
|
||
|
FAILIF(sizeof(prelink_info_t) != 8, "Unexpected sizeof(prelink_info_t) == %d!\n", sizeof(prelink_info_t));
|
||
|
int fd = open(fname, O_WRONLY);
|
||
|
FAILIF(fd < 0,
|
||
|
"open(%s, O_WRONLY): %s (%d)\n" ,
|
||
|
fname, strerror(errno), errno);
|
||
|
prelink_info_t info;
|
||
|
off_t sz = lseek(fd, 0, SEEK_END);
|
||
|
FAILIF(sz == (off_t)-1,
|
||
|
"lseek(%d, 0, SEEK_END): %s (%d)!\n",
|
||
|
fd, strerror(errno), errno);
|
||
|
|
||
|
if (!(elf_little ^ is_host_little())) {
|
||
|
/* Same endianness */
|
||
|
INFO("Host and ELF file [%s] have same endianness.\n", fname);
|
||
|
info.mmap_addr = base;
|
||
|
}
|
||
|
else {
|
||
|
/* Different endianness */
|
||
|
INFO("Host and ELF file [%s] have different endianness.\n", fname);
|
||
|
info.mmap_addr = switch_endianness(base);
|
||
|
}
|
||
|
strncpy(info.tag, "PRE ", 4);
|
||
|
|
||
|
int num_written = write(fd, &info, sizeof(info));
|
||
|
FAILIF(num_written < 0,
|
||
|
"write(%d, &info, sizeof(info)): %s (%d)\n",
|
||
|
fd, strerror(errno), errno);
|
||
|
FAILIF(sizeof(info) != num_written,
|
||
|
"Could not write %d bytes (wrote only %d bytes) as expected!\n",
|
||
|
sizeof(info), num_written);
|
||
|
FAILIF(close(fd) < 0, "close(%d): %s (%d)!\n", fd, strerror(errno), errno);
|
||
|
}
|
||
|
|
||
|
#endif /*SUPPORT_ANDROID_PRELINK_TAGS*/
|