| #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*/ |