The Android Open Source Project | 88b6079 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 1 | #ifdef SUPPORT_ANDROID_PRELINK_TAGS |
| 2 | |
| 3 | #include <sys/types.h> |
| 4 | #include <fcntl.h> |
| 5 | #include <sys/types.h> |
| 6 | #include <unistd.h> |
| 7 | #include <string.h> |
| 8 | #include <errno.h> |
| 9 | |
| 10 | #include <prelink_info.h> |
| 11 | #include <debug.h> |
| 12 | #include <common.h> |
| 13 | |
| 14 | typedef struct { |
| 15 | int32_t mmap_addr; |
| 16 | char tag[4]; /* 'P', 'R', 'E', ' ' */ |
| 17 | } prelink_info_t __attribute__((packed)); |
| 18 | |
| 19 | static inline void set_prelink(long *prelink_addr, |
| 20 | int elf_little, |
| 21 | prelink_info_t *info) |
| 22 | { |
| 23 | FAILIF(sizeof(prelink_info_t) != 8, "Unexpected sizeof(prelink_info_t) == %d!\n", sizeof(prelink_info_t)); |
| 24 | if (prelink_addr) { |
| 25 | if (!(elf_little ^ is_host_little())) { |
| 26 | /* Same endianness */ |
| 27 | *prelink_addr = info->mmap_addr; |
| 28 | } |
| 29 | else { |
| 30 | /* Different endianness */ |
| 31 | *prelink_addr = switch_endianness(info->mmap_addr); |
| 32 | } |
| 33 | } |
| 34 | } |
| 35 | |
| 36 | int check_prelinked(const char *fname, int elf_little, long *prelink_addr) |
| 37 | { |
| 38 | FAILIF(sizeof(prelink_info_t) != 8, "Unexpected sizeof(prelink_info_t) == %d!\n", sizeof(prelink_info_t)); |
| 39 | int fd = open(fname, O_RDONLY); |
| 40 | FAILIF(fd < 0, "open(%s, O_RDONLY): %s (%d)!\n", |
| 41 | fname, strerror(errno), errno); |
| 42 | off_t end = lseek(fd, 0, SEEK_END); |
| 43 | |
| 44 | int nr = sizeof(prelink_info_t); |
| 45 | |
| 46 | off_t sz = lseek(fd, -nr, SEEK_CUR); |
| 47 | ASSERT((long)(end - sz) == (long)nr); |
| 48 | FAILIF(sz == (off_t)-1, |
| 49 | "lseek(%d, 0, SEEK_END): %s (%d)!\n", |
| 50 | fd, strerror(errno), errno); |
| 51 | |
| 52 | prelink_info_t info; |
| 53 | int num_read = read(fd, &info, nr); |
| 54 | FAILIF(num_read < 0, |
| 55 | "read(%d, &info, sizeof(prelink_info_t)): %s (%d)!\n", |
| 56 | fd, strerror(errno), errno); |
| 57 | FAILIF(num_read != sizeof(info), |
| 58 | "read(%d, &info, sizeof(prelink_info_t)): did not read %d bytes as " |
| 59 | "expected (read %d)!\n", |
| 60 | fd, sizeof(info), num_read); |
| 61 | |
| 62 | int prelinked = 0; |
| 63 | if (!strncmp(info.tag, "PRE ", 4)) { |
| 64 | set_prelink(prelink_addr, elf_little, &info); |
| 65 | prelinked = 1; |
| 66 | } |
| 67 | FAILIF(close(fd) < 0, "close(%d): %s (%d)!\n", fd, strerror(errno), errno); |
| 68 | return prelinked; |
| 69 | } |
| 70 | |
| 71 | void setup_prelink_info(const char *fname, int elf_little, long base) |
| 72 | { |
| 73 | FAILIF(sizeof(prelink_info_t) != 8, "Unexpected sizeof(prelink_info_t) == %d!\n", sizeof(prelink_info_t)); |
| 74 | int fd = open(fname, O_WRONLY); |
| 75 | FAILIF(fd < 0, |
| 76 | "open(%s, O_WRONLY): %s (%d)\n" , |
| 77 | fname, strerror(errno), errno); |
| 78 | prelink_info_t info; |
| 79 | off_t sz = lseek(fd, 0, SEEK_END); |
| 80 | FAILIF(sz == (off_t)-1, |
| 81 | "lseek(%d, 0, SEEK_END): %s (%d)!\n", |
| 82 | fd, strerror(errno), errno); |
| 83 | |
| 84 | if (!(elf_little ^ is_host_little())) { |
| 85 | /* Same endianness */ |
| 86 | INFO("Host and ELF file [%s] have same endianness.\n", fname); |
| 87 | info.mmap_addr = base; |
| 88 | } |
| 89 | else { |
| 90 | /* Different endianness */ |
| 91 | INFO("Host and ELF file [%s] have different endianness.\n", fname); |
| 92 | info.mmap_addr = switch_endianness(base); |
| 93 | } |
| 94 | strncpy(info.tag, "PRE ", 4); |
| 95 | |
| 96 | int num_written = write(fd, &info, sizeof(info)); |
| 97 | FAILIF(num_written < 0, |
| 98 | "write(%d, &info, sizeof(info)): %s (%d)\n", |
| 99 | fd, strerror(errno), errno); |
| 100 | FAILIF(sizeof(info) != num_written, |
| 101 | "Could not write %d bytes (wrote only %d bytes) as expected!\n", |
| 102 | sizeof(info), num_written); |
| 103 | FAILIF(close(fd) < 0, "close(%d): %s (%d)!\n", fd, strerror(errno), errno); |
| 104 | } |
| 105 | |
| 106 | #endif /*SUPPORT_ANDROID_PRELINK_TAGS*/ |