The CMOV family of instructions do not work across all cpu families. In
[dragonfly.git] / libexec / rtld-elf / prebind.c
1 /*-
2  * Copyright (c) 2003 Matthew N. Dodd <winter@jurai.net>
3  * All rights reserved.
4  *
5  * Redistribution and use in soupe and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
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.
13  *
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
24  * SUCH DAMAGE.
25  *
26  * $DragonFly: src/libexec/rtld-elf/Attic/prebind.c,v 1.1 2003/09/18 21:22:56 dillon Exp $
27  */
28
29 #include <sys/types.h>
30 #include <sys/mman.h>
31 #include <sys/param.h>
32 #include <sys/stat.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <time.h>
36 #include <err.h>
37 #include <errno.h>
38 #include <fcntl.h>
39
40 #include "debug.h"
41 #include "rtld.h"
42
43 typedef struct {
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 */
49 } Prebind_Entry;
50
51 typedef struct {
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 */
60
61 typedef struct {
62     char        name[MAXPATHLEN];/* (obj->path) */
63     u_int32_t   uniqid;         /* Unique executable ID */
64 } Prebind_Object;
65
66 typedef struct {
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 */
71 } Prebind_Header;
72
73 #define PREBIND_PATH            "/var/db/prebind"
74 #define PREBIND_VERSION 2003052500
75 #define PREBIND_MINSIZE         (sizeof(Prebind_Header) + \
76                                  sizeof(Prebind_Object))
77
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 *);
82
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);
89 /* PLT relocations */
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);
101
102 #if 0
103 static void     dump_Elf_Rel    (Obj_Entry *, const Elf_Rel *, u_long);
104 #endif
105 static int      obj2index       (Obj_Entry **, const Obj_Entry *);
106
107 static inline int
108 prebind_cklen(off_t off, off_t size, off_t len)
109 {
110     if (off + len > size) {
111         warnx("Prebind file appears truncated.");
112         return -1;
113     }
114     
115     return 0;
116 }
117
118 int
119 prebind_load (Obj_Entry *obj_rtld, Obj_Entry *obj0)
120 {
121     struct stat sb;
122     Obj_Entry **obj_list;
123     Obj_Entry *obj;
124     Prebind_Header *ph;
125     Prebind_Object *po;
126     Prebind_Object_Index *poi;
127     caddr_t cache;
128     off_t off, size;
129     int fd;
130     int nobj;
131     int i;
132     int error;
133     int retval;
134
135     obj_list = NULL;
136     retval = -1;
137
138     if ((nobj = valid_args(obj_rtld, obj0)) == -1)
139         return (1);
140     if (set_filename(obj0))
141         return (1);
142
143     off = 0;
144     fd = open(name, O_RDONLY, 0644);
145     if (fd == -1)
146         return (1);
147
148     error = fstat(fd, &sb);
149     if (error == -1) {
150         warn("stat(\"%s\", ...)", name);
151         goto out;
152     }
153     size = sb.st_size;
154
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.");
158         goto out;
159     }
160
161     dbg("Prebind: Reading from \"%s\"\n", name);
162
163     cache = mmap(0, sb.st_size, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0);
164     if (cache == MAP_FAILED)
165         goto out;
166
167     if (prebind_cklen(off, size, sizeof(Prebind_Header)))
168         goto error;
169
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);
174
175     if (ph->version != PREBIND_VERSION) {
176         warnx("Prebind file header version number invalid!");
177         goto error;
178     }
179
180     if (nobj != ph->nobjects) {
181         warnx("Number of objects (%d) different from expected (%d).",
182             nobj, ph->nobjects);
183         goto error;
184     }
185
186     if (ph->uniqid != obj0->uniqid) {
187         warnx("Executable UNIQID does not match cache file header.");
188         goto error;
189     }
190
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 */
194
195     /* Check ld-elf.so and add it to the list. */
196     if (prebind_cklen(off, size, sizeof(Prebind_Object)))
197         goto error;
198
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))
204         goto error;
205     obj_list[0] = obj_rtld;
206
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)))
210             goto error;
211
212         po = (Prebind_Object *)(cache + off);
213         off += sizeof(Prebind_Object);
214
215         dbg("  object \"%s\", uniqid %d, relocbase %p\n",
216             obj->path, obj->uniqid, obj->relocbase);
217
218         if (check_object(obj, po))
219             goto error;
220
221          obj_list[i] = obj;
222     }
223
224     while ((off + sizeof(Prebind_Object_Index)) <= sb.st_size) {
225         if (prebind_cklen(off, size, sizeof(Prebind_Object_Index)))
226             goto error;
227
228         poi = (Prebind_Object_Index *)(cache + off);
229         off += sizeof(Prebind_Object_Index);
230         obj = obj_list[poi->index];
231
232         dbg("index %d, type %d, count %d\n",
233             poi->index, poi->type, poi->count);
234
235         switch (poi->type) {
236         case TYPE_NON_PLT:
237             if (read_non_plt(obj, obj_list, poi, cache, &off, size) != 0)
238                 goto error;
239             break;
240         case TYPE_PLT:
241             if (read_plt(obj, obj_list, poi, cache, &off, size) != 0)
242                 goto error;
243             break;
244         case TYPE_COPY:
245             if (read_copy(obj, obj_list, poi, cache, &off, size) != 0)
246                 goto error;
247             break;
248         default:
249             break;
250         }
251     }
252
253     /* Finish up. */
254     for (obj = obj0; obj != NULL; obj = obj->next) {
255         /*
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.
259          */
260         obj->magic = RTLD_MAGIC;
261         obj->version = RTLD_VERSION;
262
263         /* Set the special PLT or GOT entries. */
264         init_pltgot(obj);
265     }
266
267     retval = 0;
268 error:
269     munmap(cache, sb.st_size);
270 out:
271     close(fd);
272     if (obj_list)
273         free(obj_list);
274     if (retval == -1)
275         warnx("Prebind failed.");
276     else
277         dbg("Prebind ok.\n");
278     return (retval);
279 }
280
281 int
282 prebind_save (Obj_Entry *obj_rtld, Obj_Entry *obj0)
283 {
284     Obj_Entry **obj_list;
285     Obj_Entry *obj;
286     Prebind_Header ph;
287     Prebind_Object po;
288     Prebind_Object_Index poi;
289     int nobj;
290     int i;
291     int fd;
292     ssize_t len;
293
294     obj_list = NULL;
295     i = 0;
296
297     if ((nobj = valid_args(obj_rtld, obj0)) == -1)
298         return (1);
299     if (set_filename(obj0))
300         return (1);
301
302     fd = open(name, O_CREAT | O_TRUNC | O_WRONLY, 0644);
303     if (fd == -1) {
304         warn("open(\"%s\", ...)", name);
305         return (1);
306     }
307
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;
313     ph.nobjects = nobj;
314     len = write(fd, &ph, sizeof(Prebind_Header));
315     if (len == -1) {
316         warn("write(Prebind_Header)");
317         goto error;
318     }
319     if (len != sizeof(Prebind_Header)) {
320         warnx("short write.");
321         goto error;
322     }
323
324     /* Setup object list for index lookups. */
325     obj_list = xmalloc((nobj + 2) * sizeof(obj_list[0]));
326     obj_list[nobj+1] = NULL;
327
328     dbg("  object %-30s uniqid %d\n", obj_rtld->path, obj_rtld->uniqid);
329
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));
335     if (len == -1) {
336         warn("write(Prebind_Object)");
337         goto error;
338     }
339     if (len != sizeof(Prebind_Object)) {
340         warnx("short write.");
341         goto error;
342     }
343     obj_list[0] = obj_rtld;
344
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);
348         if (obj->textrel)
349             dbg("\timpure text\n");
350
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;
355         
356         len = write(fd, &po, sizeof(Prebind_Object));
357         if (len == -1) {
358             warn("write(Prebind_Object)");
359             goto error;
360         }
361         if (len != sizeof(Prebind_Object)) {
362             warnx("short write.");
363             goto error;
364         }
365         obj_list[i] = obj;
366     }
367
368     printf("Non-PLT Prebindings:\n");
369     for (i = 1, obj = obj0; obj != NULL; i++, obj = obj->next) {
370         poi.index = i;
371         poi.type = TYPE_NON_PLT;
372         poi.count = count_non_plt(obj);
373
374         if (poi.count == 0)
375             continue;
376         printf("  object %-30s count %d\n", obj->path, poi.count);
377
378         len = write(fd, &poi, sizeof(Prebind_Object_Index));
379         if (len == -1) {
380             warn("write(Prebind_Object_Index)");
381             goto error;
382         }
383         if (len != sizeof(Prebind_Object_Index)) {
384             warnx("short write.");
385             goto error;
386         }
387
388         len = write_non_plt(fd, obj, obj_list);
389         if (len == -1)
390             goto error;
391     }
392
393     printf("PLT Prebindings:\n");
394     for (i = 1, obj = obj0; obj != NULL; i++, obj = obj->next) {
395         poi.index = i;
396         poi.type = TYPE_PLT;
397         poi.count = count_plt(obj);
398
399         if (poi.count == 0)
400             continue;
401         printf("  object %-30s count %d\n", obj->path, poi.count);
402
403         len = write(fd, &poi, sizeof(Prebind_Object_Index));
404         if (len == -1) {
405             warn("write(Prebind_Object_Index)");
406             goto error;
407         }
408         if (len != sizeof(Prebind_Object_Index)) {
409             warnx("short write.");
410             goto error;
411         }
412
413         len = write_plt(fd, obj, obj_list);
414         if (len == -1)
415             goto error;
416     }
417
418     printf("Non-PLT COPY Prebindings:\n");
419     for (i = 1, obj = obj0; obj != NULL; i++, obj = obj->next) {
420         poi.index = i;
421         poi.type = TYPE_COPY;
422         poi.count = count_copy(obj);
423
424         if (poi.count == 0)
425             continue;
426         printf("  object %-30s count %d\n", obj->path, poi.count);
427
428         len = write(fd, &poi, sizeof(Prebind_Object_Index));
429         if (len == -1) {
430             warn("write(Prebind_Object_Index)");
431             goto error;
432         }
433         if (len != sizeof(Prebind_Object_Index)) {
434             warnx("short write.");
435             goto error;
436         }
437
438         len = write_copy(fd, obj, obj_list);
439         if (len == -1)
440             goto error;
441     }
442
443 error:
444     if (obj_list)
445         free(obj_list);
446     close(fd);
447     return (0);
448 }
449
450 static int
451 valid_args (Obj_Entry *obj_rtld, Obj_Entry *obj0)
452 {
453     Obj_Entry *obj;
454     int nobj;
455
456     if (obj_rtld->rtld == 0 || obj0->mainprog == 0)
457         return (-1);
458
459     for (nobj = 0, obj = obj0; obj != NULL; ++nobj, obj = obj->next)
460         ;   /* loop */
461
462     return (nobj);
463 }
464
465 static int
466 set_filename (Obj_Entry *obj0)
467 {
468
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);
474         return (1);
475     }
476     return (0);
477 }
478
479 static int
480 check_object (Obj_Entry *obj, Prebind_Object *po)
481 {
482     if (po->uniqid != obj->uniqid) {
483         warnx("Object UNIQID does not match cache file entry.");
484         warnx("\"%s\".", obj->path);
485         return (1);
486     }
487
488     if (strcmp(po->name, obj->mainprog ?
489            basename(obj->path) : obj->path) != 0) {
490         warnx("Object name does not match cache file entry.");
491         return (1);
492     }
493
494     return (0);
495 }
496
497 static int
498 count_non_plt (Obj_Entry *obj)
499 {
500     const Elf_Rel *rel;
501     const Elf_Rel *rellim;
502     int count;
503
504     count = 0;
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)) {
508         case R_386_32:
509         case R_386_PC32:
510         case R_386_GLOB_DAT:
511                 count++;
512                 break;
513         default:
514                 break;
515         }
516     }
517
518     return (count);
519 }
520
521 static int
522 write_non_plt (int fd, Obj_Entry *obj, Obj_Entry **obj_list)
523 {
524     const Elf_Rel *rel;
525     const Elf_Rel *rellim;
526     SymCache *cache;
527     Prebind_Entry pe;
528     ssize_t len;
529     int bytes;
530     int error;
531
532     bytes = obj->nchains * sizeof(SymCache);
533     error = -1;
534
535     /*
536      * The dynamic loader may be called from a thread, we have
537      * limited amounts of stack available so we cannot use alloca().
538      */
539     cache = mmap(NULL, bytes, PROT_READ|PROT_WRITE, MAP_ANON, -1, 0);
540     if (cache == MAP_FAILED)
541         cache = NULL;
542
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;
547         pe.index = -1;
548         pe.st_value = 0;
549         pe.st_size = 0;
550
551         switch (ELF_R_TYPE(rel->r_info)) {
552         case R_386_NONE:
553         case R_386_RELATIVE:
554             continue;
555             break;
556         case R_386_32:
557         case R_386_PC32:
558         case R_386_GLOB_DAT: {
559             const Elf_Sym *defsym;
560             const Obj_Entry *defobj;
561
562             defsym = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj, false,
563                                  cache);
564             if (defsym == NULL)
565                 goto error;
566
567             pe.index = obj2index(obj_list, defobj);
568             pe.st_value = defsym->st_value;
569             break;
570         }
571         case R_386_COPY:
572             if (!obj->mainprog) {
573                 warnx("%s: Unexpected R_386_COPY relocation in shared library",
574                       obj->path);
575                 goto error;
576             }
577             continue;
578             break;
579         default:
580             warnx("%s: Unsupported relocation type %d.",
581                   obj->path, ELF_R_TYPE(rel->r_info));
582             goto error;
583             break;
584         }
585
586         len = write(fd, &pe, sizeof(Prebind_Entry));
587         if (len == -1) {
588             warn("write(Prebind_Entry)");
589             goto error;
590         }
591         if (len != sizeof(Prebind_Entry)) {
592             warnx("short write");
593             goto error;
594         }
595
596 #if 0
597         printf("    \"%s\" r_info %04x, r_offset %#x, idx %d, st_value %#x, st_size %d\n",
598             obj->strtab +
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);
601 #endif
602     }
603
604     error = 0;
605 error:
606     if (cache)
607         munmap(cache, bytes);
608     return (error);
609 }
610
611 static int
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)
614 {
615     Prebind_Entry *pe;
616     const Elf_Rel *rel;
617     const Elf_Rel *rellim;
618     Elf_Addr *where, target;
619     int i;
620     int retval;
621     off_t off; 
622
623     retval = -1;
624     off = *poff;
625
626     if (obj->textrel) {
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);
631             goto error;
632         }
633     }
634
635     for (i = 0; i < poi->count; i++) {
636         if (prebind_cklen(off, size, sizeof(Prebind_Entry)))
637             goto error;
638
639         pe = (Prebind_Entry *)(addr + off);
640         off += sizeof(Prebind_Entry);
641
642         where = (Elf_Addr *) (obj->relocbase + pe->r_offset);
643         target = (Elf_Addr) (obj_list[pe->index]->relocbase + pe->st_value);
644
645         switch (ELF_R_TYPE(pe->r_info)) {
646         case R_386_32:
647              *where += target;
648              break;
649         case R_386_PC32:
650              *where += target - (Elf_Addr) where;
651              break;
652         case R_386_GLOB_DAT:
653              *where = target;
654              break;
655         default:
656              warnx("%s: Enexpected relocation type %d", obj->path,
657                    ELF_R_TYPE(pe->r_info));
658              goto error;
659              break;
660         }
661     }
662
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)
667             continue;
668         where = (Elf_Addr *) (obj->relocbase + rel->r_offset);
669         *where += (Elf_Addr) obj->relocbase;
670     }
671
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);
675             goto error;
676         }
677     }
678
679     retval = 0;
680 error:
681     *poff = off;
682     return (retval);
683 }
684
685 static int
686 count_plt (Obj_Entry *obj)
687 {
688     const Elf_Rel *rel;
689     const Elf_Rel *rellim;
690     int count;
691
692     count = 0;
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)
696                 count++;
697
698     return (count);
699 }
700
701 static int
702 write_plt (int fd, Obj_Entry *obj, Obj_Entry **obj_list)
703 {
704     const Elf_Rel *rel;
705     const Elf_Rel *rellim;
706     SymCache *cache;
707     Prebind_Entry pe;
708     ssize_t len;
709     int bytes;
710     int error;
711
712     bytes = obj->nchains * sizeof(SymCache);
713     error = -1;
714
715     /*
716      * The dynamic loader may be called from a thread, we have
717      * limited amounts of stack available so we cannot use alloca().
718      */
719     cache = mmap(NULL, bytes, PROT_READ|PROT_WRITE, MAP_ANON, -1, 0);
720     if (cache == MAP_FAILED)
721         cache = NULL;
722
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;
727
728         assert(ELF_R_TYPE(rel->r_info) == R_386_JMP_SLOT);
729
730         pe.r_info = rel->r_info;
731         pe.r_offset = rel->r_offset;
732         pe.index = -1;
733         pe.st_value = 0;
734         pe.st_size = 0;
735
736         defsym = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj, true, cache);
737         if (defsym == NULL)
738             goto error;
739
740         pe.index = obj2index(obj_list, defobj);
741         pe.st_value = defsym->st_value;
742
743         len = write(fd, &pe, sizeof(Prebind_Entry));
744         if (len == -1) {
745             warn("write(Prebind_Entry)");
746             goto error;
747         }
748         if (len != sizeof(Prebind_Entry)) {
749             warnx("short write");
750             goto error;
751         }
752 #if 0
753         printf("    \"%s\" r_info %04x, r_offset %#x, idx %d, st_value %#x, st_size %d\n",
754             obj->strtab +
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);
757 #endif
758     }
759
760     error = 0;
761 error:
762     if (cache)
763         munmap(cache, bytes);
764     return (error);
765 }
766
767 static int
768 read_plt (Obj_Entry *obj, Obj_Entry **obj_list, Prebind_Object_Index *poi,
769           caddr_t addr, off_t *poff, off_t size)
770 {
771     Prebind_Entry *pe;
772     Elf_Addr *where, target;
773     int i;
774     int retval;
775     off_t off; 
776
777     retval = -1;
778     off = *poff;
779
780     for (i = 0; i < poi->count; i++) {
781         if (prebind_cklen(off, size, sizeof(Prebind_Entry)))
782             goto error;
783
784         pe = (Prebind_Entry *)(addr + off);
785         off += sizeof(Prebind_Entry);
786
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);
791     }
792
793     retval = 0;
794 error:
795     *poff = off;
796     return (retval);
797 }
798
799 static int
800 count_copy (Obj_Entry *obj)
801 {
802     const Elf_Rel *rel;
803     const Elf_Rel *rellim;
804     int count;
805
806     count = 0;
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)
810                 count++;
811
812     return (count);
813 }
814
815 static int
816 write_copy (int fd, Obj_Entry *obj, Obj_Entry **obj_list)
817 {
818     const Elf_Rel *rel;
819     const Elf_Rel *rellim;
820     Prebind_Entry pe;
821     ssize_t len;
822     int error;
823
824     error = -1;
825
826     rellim = (const Elf_Rel *)((caddr_t)obj->rel + obj->relsize);
827     for (rel = obj->rel; rel < rellim; rel++) {
828         const Elf_Sym *sym;
829         const Elf_Sym *defsym;
830         const Obj_Entry *defobj;
831         const char *name;
832         unsigned long hash;
833
834         if (ELF_R_TYPE(rel->r_info) != R_386_COPY)
835                 continue;
836
837         pe.r_info = rel->r_info;
838         pe.r_offset = rel->r_offset;
839         pe.index = -1;
840
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;
844
845         for (defobj = obj->next; defobj != NULL; defobj = defobj->next)     
846             if ((defsym = symlook_obj(name, hash, defobj, false)) != NULL)
847                 break;
848
849         if (defobj == NULL) {
850              printf("Undefined symbol \"%s\" referenced from COPY"
851                     " relocation in %s", name, obj->path);
852              goto error;
853         }
854
855         pe.index = obj2index(obj_list, defobj);
856         pe.st_value = defsym->st_value;
857         pe.st_size = sym->st_size;
858
859         len = write(fd, &pe, sizeof(Prebind_Entry));
860         if (len == -1) {
861             warn("write(Prebind_Entry)");
862             goto error;
863         }
864         if (len != sizeof(Prebind_Entry)) {
865             warnx("short write");
866             goto error;
867         }
868 #if 0
869         printf("    \"%s\" r_info %04x, r_offset %#x, idx %d, st_value %#x, st_size %d\n",
870             obj->strtab +
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);
873 #endif
874     }
875
876     error = 0;
877 error:
878     return (error);
879 }
880
881 static int
882 read_copy (Obj_Entry *obj, Obj_Entry **obj_list, Prebind_Object_Index *poi,
883            caddr_t addr, off_t *poff, off_t size)
884 {
885     Prebind_Entry *pe;
886     Elf_Addr *where, target;
887     int i;
888     int retval;
889     off_t off; 
890
891     retval = -1;
892     off = *poff;
893
894     for (i = 0; i < poi->count; i++) {
895         if (prebind_cklen(off, size, sizeof(Prebind_Entry)))
896             goto error;
897
898         pe = (Prebind_Entry *)(addr + off);
899         off += sizeof(Prebind_Entry);
900
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));
904             goto error;
905         }
906
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);
910     }
911
912     retval = 0;
913 error:
914     *poff = off;
915     return (retval);
916 }
917
918 #if 0
919 static void
920 dump_Elf_Rel (Obj_Entry *obj, const Elf_Rel *rel0, u_long relsize)
921 {
922     const Elf_Rel *rel;
923     const Elf_Rel *rellim;
924     const Elf_Sym *sym;
925     Elf_Addr *dstaddr;
926
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);
934     }
935     return;
936 }
937 #endif
938
939 static int
940 obj2index (Obj_Entry **obj_list, const Obj_Entry *obj)
941 {
942     int i;
943
944     for (i = 0; obj_list[i] != NULL; i++)
945         if (obj == obj_list[i])
946             return (i);
947
948     return (-1);
949 }