auto import from //depot/cupcake/@135843
diff --git a/tools/apriori/prelink_info.c b/tools/apriori/prelink_info.c
new file mode 100644
index 0000000..da7ca05
--- /dev/null
+++ b/tools/apriori/prelink_info.c
@@ -0,0 +1,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 {
+	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*/