2 * Copyright (c) 2003 Matthew N. Dodd <winter@jurai.net>
5 * Redistribution and use in soupe and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of soupe code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * $DragonFly: src/libexec/rtld-elf/Attic/prebind.c,v 1.1 2003/09/18 21:22:56 dillon Exp $
29 #include <sys/types.h>
31 #include <sys/param.h>
44 Elf_Word r_info; /* Relocation type and symbol index. */
45 Elf_Addr r_offset; /* Offset from object Relocation constant */
46 int index; /* Definition Object index */
47 Elf_Addr st_value; /* Definition Symbol value. */
48 Elf_Size st_size; /* Copy relocation size */
52 int index; /* Object index */
53 int type; /* Type of Prebind_Entry objects */
54 int count; /* Number of Prebind_Entry objects */
55 } Prebind_Object_Index;
56 #define TYPE_NONE 0 /* None */
57 #define TYPE_NON_PLT 1 /* Non-PLT relocation. */
58 #define TYPE_PLT 2 /* PLT relocation. */
59 #define TYPE_COPY 3 /* Non-PLT COPY relocation */
62 char name[MAXPATHLEN];/* (obj->path) */
63 u_int32_t uniqid; /* Unique executable ID */
67 int version; /* Version number */
68 char name[MAXPATHLEN];/* basename */
69 u_int32_t uniqid; /* Unique executable ID */
70 int nobjects; /* number of Prebind_Object elements */
73 #define PREBIND_PATH "/var/db/prebind"
74 #define PREBIND_VERSION 2003052500
75 #define PREBIND_MINSIZE (sizeof(Prebind_Header) + \
76 sizeof(Prebind_Object))
78 static char name[MAXPATHLEN];
79 static int valid_args (Obj_Entry *, Obj_Entry *);
80 static int set_filename (Obj_Entry *);
81 static int check_object (Obj_Entry *, Prebind_Object *);
83 /* Non-PLT relocations */
84 static int count_non_plt (Obj_Entry *);
85 static int write_non_plt (int, Obj_Entry *, Obj_Entry **);
86 static int read_non_plt (Obj_Entry *, Obj_Entry **,
87 Prebind_Object_Index *,
88 caddr_t, off_t *, off_t);
90 static int count_plt (Obj_Entry *);
91 static int write_plt (int, Obj_Entry *, Obj_Entry **);
92 static int read_plt (Obj_Entry *, Obj_Entry **,
93 Prebind_Object_Index *,
94 caddr_t, off_t *, off_t);
95 /* Non-PLT COPY relocations */
96 static int count_copy (Obj_Entry *);
97 static int write_copy (int, Obj_Entry *, Obj_Entry **);
98 static int read_copy (Obj_Entry *, Obj_Entry **,
99 Prebind_Object_Index *,
100 caddr_t, off_t *, off_t);
103 static void dump_Elf_Rel (Obj_Entry *, const Elf_Rel *, u_long);
105 static int obj2index (Obj_Entry **, const Obj_Entry *);
108 prebind_cklen(off_t off, off_t size, off_t len)
110 if (off + len > size) {
111 warnx("Prebind file appears truncated.");
119 prebind_load (Obj_Entry *obj_rtld, Obj_Entry *obj0)
122 Obj_Entry **obj_list;
126 Prebind_Object_Index *poi;
138 if ((nobj = valid_args(obj_rtld, obj0)) == -1)
140 if (set_filename(obj0))
144 fd = open(name, O_RDONLY, 0644);
148 error = fstat(fd, &sb);
150 warn("stat(\"%s\", ...)", name);
155 if ((sb.st_uid != 0) || (sb.st_gid != 0) ||
156 ((sb.st_mode & (S_IWGRP|S_IWOTH)) != 0)) {
157 warnx("Prebind file has invalid permissions/ownership.");
161 dbg("Prebind: Reading from \"%s\"\n", name);
163 cache = mmap(0, sb.st_size, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0);
164 if (cache == MAP_FAILED)
167 if (prebind_cklen(off, size, sizeof(Prebind_Header)))
170 ph = (Prebind_Header *)cache;
171 off += sizeof(Prebind_Header);
172 dbg("\tversion %d, name \"%s\", nobjects %d\n",
173 ph->version, ph->name, ph->nobjects);
175 if (ph->version != PREBIND_VERSION) {
176 warnx("Prebind file header version number invalid!");
180 if (nobj != ph->nobjects) {
181 warnx("Number of objects (%d) different from expected (%d).",
186 if (ph->uniqid != obj0->uniqid) {
187 warnx("Executable UNIQID does not match cache file header.");
191 /* Init our object list */
192 obj_list = xmalloc((nobj + 2) * sizeof(obj_list[0]));
193 obj_list[nobj+1] = NULL; /* NULL terminate the list */
195 /* Check ld-elf.so and add it to the list. */
196 if (prebind_cklen(off, size, sizeof(Prebind_Object)))
199 po = (Prebind_Object *)(cache + off);
200 off += sizeof(Prebind_Object);
201 dbg(" object \"%s\", uniqid %d, relocbase %p\n",
202 obj_rtld->path, obj_rtld->uniqid, obj_rtld->relocbase);
203 if (check_object(obj_rtld, po))
205 obj_list[0] = obj_rtld;
207 /* Check each object and add it to the list */
208 for (i = 1, obj = obj0; obj != NULL; i++, obj = obj->next) {
209 if (prebind_cklen(off, size, sizeof(Prebind_Object)))
212 po = (Prebind_Object *)(cache + off);
213 off += sizeof(Prebind_Object);
215 dbg(" object \"%s\", uniqid %d, relocbase %p\n",
216 obj->path, obj->uniqid, obj->relocbase);
218 if (check_object(obj, po))
224 while ((off + sizeof(Prebind_Object_Index)) <= sb.st_size) {
225 if (prebind_cklen(off, size, sizeof(Prebind_Object_Index)))
228 poi = (Prebind_Object_Index *)(cache + off);
229 off += sizeof(Prebind_Object_Index);
230 obj = obj_list[poi->index];
232 dbg("index %d, type %d, count %d\n",
233 poi->index, poi->type, poi->count);
237 if (read_non_plt(obj, obj_list, poi, cache, &off, size) != 0)
241 if (read_plt(obj, obj_list, poi, cache, &off, size) != 0)
245 if (read_copy(obj, obj_list, poi, cache, &off, size) != 0)
254 for (obj = obj0; obj != NULL; obj = obj->next) {
256 * Set up the magic number and version in the Obj_Entry. These
257 * were checked in the crt1.o from the original ElfKit, so we
258 * set them for backward compatibility.
260 obj->magic = RTLD_MAGIC;
261 obj->version = RTLD_VERSION;
263 /* Set the special PLT or GOT entries. */
269 munmap(cache, sb.st_size);
275 warnx("Prebind failed.");
277 dbg("Prebind ok.\n");
282 prebind_save (Obj_Entry *obj_rtld, Obj_Entry *obj0)
284 Obj_Entry **obj_list;
288 Prebind_Object_Index poi;
297 if ((nobj = valid_args(obj_rtld, obj0)) == -1)
299 if (set_filename(obj0))
302 fd = open(name, O_CREAT | O_TRUNC | O_WRONLY, 0644);
304 warn("open(\"%s\", ...)", name);
308 /* Prebinding Cache Header */
309 bzero(&ph, sizeof(Prebind_Header));
310 ph.version = PREBIND_VERSION;
311 strcpy(ph.name, basename(obj0->path));
312 ph.uniqid = obj0->uniqid;
314 len = write(fd, &ph, sizeof(Prebind_Header));
316 warn("write(Prebind_Header)");
319 if (len != sizeof(Prebind_Header)) {
320 warnx("short write.");
324 /* Setup object list for index lookups. */
325 obj_list = xmalloc((nobj + 2) * sizeof(obj_list[0]));
326 obj_list[nobj+1] = NULL;
328 dbg(" object %-30s uniqid %d\n", obj_rtld->path, obj_rtld->uniqid);
330 /* ld-elf.so Prebinding Cache Object */
331 bzero(&po, sizeof(Prebind_Object));
332 strcpy(po.name, obj_rtld->path);
333 po.uniqid = obj_rtld->uniqid;
334 len = write(fd, &po, sizeof(Prebind_Object));
336 warn("write(Prebind_Object)");
339 if (len != sizeof(Prebind_Object)) {
340 warnx("short write.");
343 obj_list[0] = obj_rtld;
345 /* Add entries for each object */
346 for (i = 1, obj = obj0; obj != NULL; i++, obj = obj->next) {
347 printf(" object %-30s uniqid %d\n", obj->path, obj->uniqid);
349 dbg("\timpure text\n");
351 /* Prebinding Cache Object */
352 bzero(&po, sizeof(Prebind_Object));
353 strcpy(po.name, obj->mainprog ? basename(obj->path) : obj->path);
354 po.uniqid = obj->uniqid;
356 len = write(fd, &po, sizeof(Prebind_Object));
358 warn("write(Prebind_Object)");
361 if (len != sizeof(Prebind_Object)) {
362 warnx("short write.");
368 printf("Non-PLT Prebindings:\n");
369 for (i = 1, obj = obj0; obj != NULL; i++, obj = obj->next) {
371 poi.type = TYPE_NON_PLT;
372 poi.count = count_non_plt(obj);
376 printf(" object %-30s count %d\n", obj->path, poi.count);
378 len = write(fd, &poi, sizeof(Prebind_Object_Index));
380 warn("write(Prebind_Object_Index)");
383 if (len != sizeof(Prebind_Object_Index)) {
384 warnx("short write.");
388 len = write_non_plt(fd, obj, obj_list);
393 printf("PLT Prebindings:\n");
394 for (i = 1, obj = obj0; obj != NULL; i++, obj = obj->next) {
397 poi.count = count_plt(obj);
401 printf(" object %-30s count %d\n", obj->path, poi.count);
403 len = write(fd, &poi, sizeof(Prebind_Object_Index));
405 warn("write(Prebind_Object_Index)");
408 if (len != sizeof(Prebind_Object_Index)) {
409 warnx("short write.");
413 len = write_plt(fd, obj, obj_list);
418 printf("Non-PLT COPY Prebindings:\n");
419 for (i = 1, obj = obj0; obj != NULL; i++, obj = obj->next) {
421 poi.type = TYPE_COPY;
422 poi.count = count_copy(obj);
426 printf(" object %-30s count %d\n", obj->path, poi.count);
428 len = write(fd, &poi, sizeof(Prebind_Object_Index));
430 warn("write(Prebind_Object_Index)");
433 if (len != sizeof(Prebind_Object_Index)) {
434 warnx("short write.");
438 len = write_copy(fd, obj, obj_list);
451 valid_args (Obj_Entry *obj_rtld, Obj_Entry *obj0)
456 if (obj_rtld->rtld == 0 || obj0->mainprog == 0)
459 for (nobj = 0, obj = obj0; obj != NULL; ++nobj, obj = obj->next)
466 set_filename (Obj_Entry *obj0)
469 bzero(name, MAXPATHLEN);
470 snprintf(name, MAXPATHLEN, "%s/%08x.%s",
471 PREBIND_PATH, obj0->uniqid, basename(obj0->path));
472 if (strlen(name) < (strlen(PREBIND_PATH) + 10)) {
473 warnx("Invalid or truncated Prebind file name \"%s\".", name);
480 check_object (Obj_Entry *obj, Prebind_Object *po)
482 if (po->uniqid != obj->uniqid) {
483 warnx("Object UNIQID does not match cache file entry.");
484 warnx("\"%s\".", obj->path);
488 if (strcmp(po->name, obj->mainprog ?
489 basename(obj->path) : obj->path) != 0) {
490 warnx("Object name does not match cache file entry.");
498 count_non_plt (Obj_Entry *obj)
501 const Elf_Rel *rellim;
505 rellim = (const Elf_Rel *) ((caddr_t) obj->rel + obj->relsize);
506 for (rel = obj->rel; rel < rellim; rel++) {
507 switch (ELF_R_TYPE(rel->r_info)) {
522 write_non_plt (int fd, Obj_Entry *obj, Obj_Entry **obj_list)
525 const Elf_Rel *rellim;
532 bytes = obj->nchains * sizeof(SymCache);
536 * The dynamic loader may be called from a thread, we have
537 * limited amounts of stack available so we cannot use alloca().
539 cache = mmap(NULL, bytes, PROT_READ|PROT_WRITE, MAP_ANON, -1, 0);
540 if (cache == MAP_FAILED)
543 rellim = (const Elf_Rel *) ((caddr_t) obj->rel + obj->relsize);
544 for (rel = obj->rel; rel < rellim; rel++) {
545 pe.r_info = rel->r_info;
546 pe.r_offset = rel->r_offset;
551 switch (ELF_R_TYPE(rel->r_info)) {
558 case R_386_GLOB_DAT: {
559 const Elf_Sym *defsym;
560 const Obj_Entry *defobj;
562 defsym = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj, false,
567 pe.index = obj2index(obj_list, defobj);
568 pe.st_value = defsym->st_value;
572 if (!obj->mainprog) {
573 warnx("%s: Unexpected R_386_COPY relocation in shared library",
580 warnx("%s: Unsupported relocation type %d.",
581 obj->path, ELF_R_TYPE(rel->r_info));
586 len = write(fd, &pe, sizeof(Prebind_Entry));
588 warn("write(Prebind_Entry)");
591 if (len != sizeof(Prebind_Entry)) {
592 warnx("short write");
597 printf(" \"%s\" r_info %04x, r_offset %#x, idx %d, st_value %#x, st_size %d\n",
599 ((const Elf_Sym *)(obj->symtab + ELF_R_SYM(rel->r_info)))->st_name,
600 pe.r_info, pe.r_offset, pe.index, pe.st_value, pe.st_size);
607 munmap(cache, bytes);
612 read_non_plt (Obj_Entry *obj, Obj_Entry **obj_list, Prebind_Object_Index *poi,
613 caddr_t addr, off_t *poff, off_t size)
617 const Elf_Rel *rellim;
618 Elf_Addr *where, target;
627 /* There are relocations to the write-protected text segment. */
628 if (mprotect(obj->mapbase, obj->textsize,
629 PROT_READ|PROT_WRITE|PROT_EXEC) == -1) {
630 warn("%s: Cannot write-enable text segment", obj->path);
635 for (i = 0; i < poi->count; i++) {
636 if (prebind_cklen(off, size, sizeof(Prebind_Entry)))
639 pe = (Prebind_Entry *)(addr + off);
640 off += sizeof(Prebind_Entry);
642 where = (Elf_Addr *) (obj->relocbase + pe->r_offset);
643 target = (Elf_Addr) (obj_list[pe->index]->relocbase + pe->st_value);
645 switch (ELF_R_TYPE(pe->r_info)) {
650 *where += target - (Elf_Addr) where;
656 warnx("%s: Enexpected relocation type %d", obj->path,
657 ELF_R_TYPE(pe->r_info));
663 /* While we're here, take care of all RELATIVE relocations. */
664 rellim = (const Elf_Rel *) ((caddr_t) obj->rel + obj->relsize);
665 for (rel = obj->rel; rel < rellim; rel++) {
666 if (ELF_R_TYPE(rel->r_info) != R_386_RELATIVE)
668 where = (Elf_Addr *) (obj->relocbase + rel->r_offset);
669 *where += (Elf_Addr) obj->relocbase;
672 if (obj->textrel) { /* Re-protected the text segment. */
673 if (mprotect(obj->mapbase, obj->textsize, PROT_READ|PROT_EXEC) == -1) {
674 warn("%s: Cannot write-protect text segment", obj->path);
686 count_plt (Obj_Entry *obj)
689 const Elf_Rel *rellim;
693 rellim = (const Elf_Rel *)((caddr_t)obj->pltrel + obj->pltrelsize);
694 for (rel = obj->pltrel; rel < rellim; rel++)
695 if (ELF_R_TYPE(rel->r_info) == R_386_JMP_SLOT)
702 write_plt (int fd, Obj_Entry *obj, Obj_Entry **obj_list)
705 const Elf_Rel *rellim;
712 bytes = obj->nchains * sizeof(SymCache);
716 * The dynamic loader may be called from a thread, we have
717 * limited amounts of stack available so we cannot use alloca().
719 cache = mmap(NULL, bytes, PROT_READ|PROT_WRITE, MAP_ANON, -1, 0);
720 if (cache == MAP_FAILED)
723 rellim = (const Elf_Rel *)((caddr_t)obj->pltrel + obj->pltrelsize);
724 for (rel = obj->pltrel; rel < rellim; rel++) {
725 const Elf_Sym *defsym;
726 const Obj_Entry *defobj;
728 assert(ELF_R_TYPE(rel->r_info) == R_386_JMP_SLOT);
730 pe.r_info = rel->r_info;
731 pe.r_offset = rel->r_offset;
736 defsym = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj, true, cache);
740 pe.index = obj2index(obj_list, defobj);
741 pe.st_value = defsym->st_value;
743 len = write(fd, &pe, sizeof(Prebind_Entry));
745 warn("write(Prebind_Entry)");
748 if (len != sizeof(Prebind_Entry)) {
749 warnx("short write");
753 printf(" \"%s\" r_info %04x, r_offset %#x, idx %d, st_value %#x, st_size %d\n",
755 ((const Elf_Sym *)(obj->symtab + ELF_R_SYM(rel->r_info)))->st_name,
756 pe.r_info, pe.r_offset, pe.index, pe.st_value, pe.st_size);
763 munmap(cache, bytes);
768 read_plt (Obj_Entry *obj, Obj_Entry **obj_list, Prebind_Object_Index *poi,
769 caddr_t addr, off_t *poff, off_t size)
772 Elf_Addr *where, target;
780 for (i = 0; i < poi->count; i++) {
781 if (prebind_cklen(off, size, sizeof(Prebind_Entry)))
784 pe = (Prebind_Entry *)(addr + off);
785 off += sizeof(Prebind_Entry);
787 where = (Elf_Addr *) (obj->relocbase + pe->r_offset);
788 target = (Elf_Addr) (obj_list[pe->index]->relocbase + pe->st_value);
789 *where += (Elf_Addr) obj->relocbase;
790 reloc_jmpslot(where, target);
800 count_copy (Obj_Entry *obj)
803 const Elf_Rel *rellim;
807 rellim = (const Elf_Rel *)((caddr_t)obj->rel + obj->relsize);
808 for (rel = obj->rel; rel < rellim; rel++)
809 if (ELF_R_TYPE(rel->r_info) == R_386_COPY)
816 write_copy (int fd, Obj_Entry *obj, Obj_Entry **obj_list)
819 const Elf_Rel *rellim;
826 rellim = (const Elf_Rel *)((caddr_t)obj->rel + obj->relsize);
827 for (rel = obj->rel; rel < rellim; rel++) {
829 const Elf_Sym *defsym;
830 const Obj_Entry *defobj;
834 if (ELF_R_TYPE(rel->r_info) != R_386_COPY)
837 pe.r_info = rel->r_info;
838 pe.r_offset = rel->r_offset;
841 sym = obj->symtab + ELF_R_SYM(rel->r_info);
842 hash = elf_hash(obj->strtab + sym->st_name);
843 name = obj->strtab + sym->st_name;
845 for (defobj = obj->next; defobj != NULL; defobj = defobj->next)
846 if ((defsym = symlook_obj(name, hash, defobj, false)) != NULL)
849 if (defobj == NULL) {
850 printf("Undefined symbol \"%s\" referenced from COPY"
851 " relocation in %s", name, obj->path);
855 pe.index = obj2index(obj_list, defobj);
856 pe.st_value = defsym->st_value;
857 pe.st_size = sym->st_size;
859 len = write(fd, &pe, sizeof(Prebind_Entry));
861 warn("write(Prebind_Entry)");
864 if (len != sizeof(Prebind_Entry)) {
865 warnx("short write");
869 printf(" \"%s\" r_info %04x, r_offset %#x, idx %d, st_value %#x, st_size %d\n",
871 ((const Elf_Sym *)(obj->symtab + ELF_R_SYM(rel->r_info)))->st_name,
872 pe.r_info, pe.r_offset, pe.index, pe.st_value, pe.st_size);
882 read_copy (Obj_Entry *obj, Obj_Entry **obj_list, Prebind_Object_Index *poi,
883 caddr_t addr, off_t *poff, off_t size)
886 Elf_Addr *where, target;
894 for (i = 0; i < poi->count; i++) {
895 if (prebind_cklen(off, size, sizeof(Prebind_Entry)))
898 pe = (Prebind_Entry *)(addr + off);
899 off += sizeof(Prebind_Entry);
901 if (ELF_R_TYPE(pe->r_info) != R_386_COPY) {
902 warnx("Unexpected relocation type %d; expected R_386_COPY.",
903 ELF_R_TYPE(pe->r_info));
907 where = (Elf_Addr *) (obj->relocbase + pe->r_offset);
908 target = (Elf_Addr) (obj_list[pe->index]->relocbase + pe->st_value);
909 memcpy(where, (void *)target, pe->st_size);
920 dump_Elf_Rel (Obj_Entry *obj, const Elf_Rel *rel0, u_long relsize)
923 const Elf_Rel *rellim;
927 rellim = (const Elf_Rel *)((char *)rel0 + relsize);
928 for (rel = rel0; rel < rellim; rel++) {
929 dstaddr = (Elf_Addr *)(obj->relocbase + rel->r_offset);
930 sym = obj->symtab + ELF_R_SYM(rel->r_info);
931 printf("\t\"%s\" offset %p, info %04x, addr %#x, size %d\n",
932 obj->strtab + sym->st_name,
933 dstaddr, rel->r_info, *dstaddr, sym->st_size);
940 obj2index (Obj_Entry **obj_list, const Obj_Entry *obj)
944 for (i = 0; obj_list[i] != NULL; i++)
945 if (obj == obj_list[i])