summaryrefslogtreecommitdiffstats
path: root/tools/soslim/prelink_info.c
blob: 36516b1214b0a903a59fed51f4cc9b3842c2cd4b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#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 {
	uint32_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*/