1 /* $OpenBSD: dl_prebind.c,v 1.1 2006/05/12 23:20:52 deraadt Exp $ */
2
3 /*
4 * Copyright (c) 2006 Dale Rahn <drahn@dalerahn.com>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 #include <sys/types.h>
20 #include <sys/mman.h>
21 #include <sys/exec.h>
22 #include <sys/param.h>
23 #include <sys/sysctl.h>
24 #include <nlist.h>
25 #include <string.h>
26 #include <link.h>
27 #include <dlfcn.h>
28 #include <unistd.h>
29
30 #include "syscall.h"
31 #include "archdep.h"
32 #include "resolve.h"
33 #include "sod.h"
34 #include "stdlib.h"
35 #include "dl_prebind.h"
36
37 void elf_dump_footer(struct prebind_footer *footer);
38 void dump_prelink(Elf_Addr base, u_long size);
39 void prebind_dump_footer(struct prebind_footer *footer, char *file);
40 void prebind_dump_symcache(struct symcachetab *symcachetab, u_int32_t cnt);
41 void prebind_dump_nameidx(struct nameidx *nameidx, u_int32_t numblibs,
42 char *nametab);
43 void prebind_dump_fixup(struct fixup *fixup, u_int32_t numfixups);
44 void prebind_dump_libmap(u_int32_t *libmap, u_int32_t numlibs);
45 struct prebind_footer *_dl_prebind_data_to_footer(void *data);
46
47 void *_dl_prog_prebind_map;
48 struct prebind_footer *prog_footer;
49 extern char *_dl_noprebind;
50 extern char *_dl_prebind_validate;
51
52 int _dl_prebind_match_failed; /* = 0 */
53
54 char *prebind_bind_now = "prebind";
55
56 struct prebind_footer *
_dl_prebind_data_to_footer(void * prebind_data)57 _dl_prebind_data_to_footer(void *prebind_data)
58 {
59 u_int32_t *poffset, offset;
60 struct prebind_footer *footer;
61 char *c;
62
63 poffset = prebind_data;
64 c = prebind_data;
65 offset = *poffset;
66 c += offset;
67 footer = (void *)c;
68 return footer;
69 }
70
71 void
prebind_load_exe(Elf_Phdr * phdp,elf_object_t * exe_obj)72 prebind_load_exe(Elf_Phdr *phdp, elf_object_t *exe_obj)
73 {
74 struct prebind_footer *footer;
75
76 exe_obj->prebind_data = (void *)phdp->p_vaddr;
77 _dl_prog_prebind_map = exe_obj->prebind_data;
78
79 footer = _dl_prebind_data_to_footer(_dl_objects->prebind_data);
80
81 if (footer->bind_id[0] == BIND_ID0 &&
82 footer->bind_id[1] == BIND_ID1 &&
83 footer->bind_id[2] == BIND_ID2 &&
84 footer->bind_id[3] == BIND_ID3 &&
85 footer->prebind_version == PREBIND_VERSION) {
86 prog_footer = footer;
87 if (_dl_bindnow == NULL)
88 _dl_bindnow = prebind_bind_now;
89 } else {
90 DL_DEB(("prebind data missing\n"));
91 _dl_prog_prebind_map = NULL;
92 }
93 if (_dl_noprebind != NULL) {
94 /*prog_footer is valid, we should free it */
95 _dl_prog_prebind_map = NULL;
96 prog_footer = NULL;
97 exe_obj->prebind_data = NULL;
98 if (_dl_bindnow == prebind_bind_now)
99 _dl_bindnow = NULL;
100 }
101 #if 0
102 else if (_dl_debug)
103 dump_prelink((long)_dl_prog_prebind_map,
104 prog_footer->prebind_size);
105 #endif
106 }
107
108 void *
prebind_load_fd(int fd,const char * name)109 prebind_load_fd(int fd, const char *name)
110 {
111 struct prebind_footer footer;
112 struct nameidx *nameidx;
113 void *prebind_data;
114 char *nametab;
115 ssize_t len;
116 int idx;
117
118 if (_dl_prog_prebind_map == NULL || _dl_prebind_match_failed)
119 return 0;
120
121 _dl_lseek(fd, -(off_t)sizeof(struct prebind_footer), SEEK_END);
122 len = _dl_read(fd, (void *)&footer, sizeof(struct prebind_footer));
123
124 if (len != sizeof(struct prebind_footer) ||
125 footer.bind_id[0] != BIND_ID0 ||
126 footer.bind_id[1] != BIND_ID1 ||
127 footer.bind_id[2] != BIND_ID2 ||
128 footer.bind_id[3] != BIND_ID3 ||
129 footer.prebind_version != PREBIND_VERSION) {
130 _dl_prebind_match_failed = 1;
131 DL_DEB(("prebind match failed %s\n", name));
132 return (NULL);
133 }
134
135 prebind_data = _dl_mmap(0, footer.prebind_size, PROT_READ,
136 MAP_FILE, fd, footer.prebind_base);
137 DL_DEB(("prebind_load_fd for lib %s\n", name));
138
139 nameidx = _dl_prog_prebind_map + prog_footer->nameidx_idx;
140 nametab = _dl_prog_prebind_map + prog_footer->nametab_idx;
141
142 /* libraries are loaded in random order, so we just have
143 * to look thru the list to find ourselves
144 */
145 for (idx = 0; idx < prog_footer->numlibs; idx++) {
146 if (_dl_strcmp(nametab + nameidx[idx].name, name) == 0)
147 break;
148 }
149
150 if (idx == prog_footer->numlibs) {
151 _dl_prebind_match_failed = 1; /* not found */
152 } else if (footer.id0 != nameidx[idx].id0 ||
153 footer.id1 != nameidx[idx].id1) {
154 _dl_prebind_match_failed = 1;
155 DL_DEB(("prebind match id0 %d pid0 %d id1 %d pid1 %d\n",
156 footer.id0, nameidx[idx].id0,
157 footer.id1, nameidx[idx].id1));
158 }
159
160 if (_dl_prebind_match_failed == 1) {
161 DL_DEB(("prebind match failed for %s\n", name));
162 }
163
164 return prebind_data;
165 }
166 #define NUM_STATIC_OBJS 10
167 elf_object_t *objarray_static[NUM_STATIC_OBJS];
168 elf_object_t **objarray;
169
170 void
prebind_symcache(elf_object_t * object,int plt)171 prebind_symcache(elf_object_t *object, int plt)
172 {
173 u_int32_t *fixupidx, *fixupcnt, *libmap, *idxtolib;
174 u_int32_t *poffset, offset, symcache_cnt;
175 struct symcachetab *symcachetab;
176 struct prebind_footer *footer;
177 int i = 0, cur_obj = -1, idx;
178 void *prebind_map;
179 struct nameidx *nameidx;
180 char *nametab, *c;
181 struct fixup *fixup;
182 elf_object_t *obj;
183
184 struct symcachetab *s;
185
186 if (object->prebind_data == NULL)
187 return;
188 // DL_DEB(("prebind symcache %s\n", object->load_name));
189
190 obj = _dl_objects;
191 while (obj != NULL) {
192 if (obj == object)
193 cur_obj = i;
194 i++;
195 obj = obj->next;
196 }
197
198 if (cur_obj == -1)
199 return; /* unable to find object ? */
200
201 if (objarray == NULL) {
202 if (i <= NUM_STATIC_OBJS) {
203 objarray = &objarray_static[0];
204 } else {
205 objarray = _dl_malloc(sizeof(elf_object_t *) * i);
206 }
207
208 obj = _dl_objects;
209 i = 0;
210 while (obj != NULL) {
211 objarray[i] = obj;
212 i++;
213 obj = obj->next;
214 }
215 }
216
217 poffset = (u_int32_t *)object->prebind_data;
218 c = object->prebind_data;
219 offset = *poffset;
220 c += offset;
221
222 footer = (void *)c;
223 prebind_map = (void *)object->prebind_data;
224 nameidx = prebind_map + footer->nameidx_idx;;
225 if (plt) {
226 symcachetab = prebind_map + footer->pltsymcache_idx;
227 symcache_cnt = footer->pltsymcache_cnt;
228 // DL_DEB(("loading plt %d\n", symcache_cnt));
229 } else {
230 symcachetab = prebind_map + footer->symcache_idx;
231 symcache_cnt = footer->symcache_cnt;
232 // DL_DEB(("loading got %d\n", symcache_cnt));
233 }
234 nametab = prebind_map + footer->nametab_idx;
235
236 libmap = _dl_prog_prebind_map + prog_footer->libmap_idx;
237 idxtolib = _dl_prog_prebind_map + libmap[cur_obj];
238
239 for (i = 0; i < symcache_cnt; i++) {
240 struct elf_object *tobj;
241 const Elf_Sym *sym;
242 const char *str;
243
244 s = &(symcachetab[i]);
245 if (cur_obj == 0)
246 idx = s->obj_idx;
247 else
248 idx = idxtolib[s->obj_idx];
249
250 if (idx == -1) /* somehow an invalid object ref happend */
251 continue;
252 #if 0
253 DL_DEB(("%s:", object->load_name));
254 DL_DEB(("symidx %d: obj %d %d sym %d flags %x\n",
255 s->idx, s->obj_idx, idx, s->sym_idx,
256 SYM_SEARCH_ALL|SYM_WARNNOTFOUND|plt));
257 #endif
258 tobj = objarray[idx];
259 sym = tobj->dyn.symtab + s->sym_idx;
260 str = tobj->dyn.strtab + sym->st_name;
261 #ifdef DEBUG2
262 DL_DEB(("symidx %d: obj %d %s sym %d %s flags %d %x\n",
263 s->idx, s->obj_idx, tobj->load_name,
264 s->sym_idx, str, SYM_SEARCH_ALL|SYM_WARNNOTFOUND|plt,
265 object->load_addr + sym->st_value));
266 #endif
267 _dl_symcache[s->idx].obj = tobj;
268 _dl_symcache[s->idx].sym = sym;
269 _dl_symcache[s->idx].flags =
270 SYM_SEARCH_ALL|SYM_WARNNOTFOUND|plt;
271 }
272
273 if (!plt) {
274 fixupidx = _dl_prog_prebind_map + prog_footer->fixup_idx;
275 fixup = _dl_prog_prebind_map + fixupidx[2*cur_obj];
276 fixupcnt = _dl_prog_prebind_map + prog_footer->fixupcnt_idx;
277
278 for (i = 0; i < fixupcnt[2*cur_obj]; i++) {
279 struct fixup *f;
280 struct elf_object *tobj;
281 const Elf_Sym *sym;
282 const char *str;
283
284 f = &(fixup[i]);
285 #if 0
286 DL_DEB(("symidx %d: obj %d sym %d flags %x\n",
287 f->sym, f->obj_idx, f->sym_idx, f->flags));
288 #endif
289 tobj = objarray[f->obj_idx];
290 sym = tobj->dyn.symtab + f->sym_idx;
291 str = tobj->dyn.strtab + sym->st_name;
292 #ifdef DEBUG2
293 DL_DEB(("symidx %d: obj %d %s sym %d %s flags %d %x\n",
294 f->sym, f->obj_idx, tobj->load_name,
295 f->sym_idx, str, SYM_SEARCH_ALL|SYM_WARNNOTFOUND|plt,
296 object->load_addr + sym->st_value));
297 #endif
298 _dl_symcache[f->sym].obj = tobj;
299 _dl_symcache[f->sym].sym = sym;
300 _dl_symcache[f->sym].flags =
301 SYM_SEARCH_ALL|SYM_WARNNOTFOUND|plt;
302 }
303 } else {
304
305 fixupidx = _dl_prog_prebind_map + prog_footer->fixup_idx;
306 fixup = _dl_prog_prebind_map + fixupidx[2*cur_obj+1];
307 fixupcnt = _dl_prog_prebind_map + prog_footer->fixupcnt_idx;
308
309 #if 0
310 DL_DEB(("prebind loading symbols fixup plt %s\n",
311 object->load_name));
312 #endif
313 for (i = 0; i < fixupcnt[2*cur_obj+1]; i++) {
314 struct fixup *f;
315 struct elf_object *tobj;
316 const Elf_Sym *sym;
317 const char *str;
318
319 f = &(fixup[i]);
320 #if 0
321 DL_DEB(("symidx %d: obj %d sym %d flags %x\n",
322 f->sym, f->obj_idx, f->sym_idx,
323 SYM_SEARCH_ALL|SYM_WARNNOTFOUND|plt));
324 #endif
325 tobj = objarray[f->obj_idx];
326 sym = tobj->dyn.symtab + f->sym_idx;
327 str = tobj->dyn.strtab + sym->st_name;
328 #ifdef DEBUG2
329 DL_DEB(("symidx %d: obj %d %s sym %d %s flags %d %x\n",
330 f->sym, f->obj_idx, tobj->load_name,
331 f->sym_idx, str, SYM_SEARCH_ALL|SYM_WARNNOTFOUND|plt,
332 object->load_addr + sym->st_value));
333 #endif
334 _dl_symcache[f->sym].obj = tobj;
335 _dl_symcache[f->sym].sym = sym;
336 _dl_symcache[f->sym].flags =
337 SYM_SEARCH_ALL|SYM_WARNNOTFOUND|plt;
338 }
339 }
340 // DL_DEB(("prebind_data loaded\n"));
341 }
342
343 void
prebind_free(elf_object_t * object)344 prebind_free(elf_object_t *object)
345 {
346 struct prebind_footer *footer;
347
348 if (object->prebind_data == NULL)
349 return;
350 #ifdef DEBUG1
351 DL_DEB(("prebind_free for %s %p\n", object->load_name,
352 object->prebind_data));
353 #endif
354 if (object->prebind_data != 0) {
355 footer = _dl_prebind_data_to_footer(object->prebind_data);
356
357 #ifdef DEBUG1
358 DL_DEB(("freeing prebind data sz %x\n", footer->prebind_size));
359 #endif
360
361 _dl_munmap((void *)ELF_TRUNC((long)object->prebind_data, _dl_pagesz),
362 ELF_ROUND((long)object->prebind_data+footer->prebind_size,
363 _dl_pagesz) - ELF_TRUNC((long)object->prebind_data, _dl_pagesz));
364
365 object->prebind_data = NULL;
366 _dl_prog_prebind_map = NULL;
367
368 if (_dl_bindnow == prebind_bind_now)
369 _dl_bindnow = NULL;
370 }
371 }
372
373 int validate_errs;
374
375 struct timeval beforetp;
376
377 void
_dl_prebind_pre_resolve()378 _dl_prebind_pre_resolve()
379 {
380 struct prebind_footer *footer;
381 elf_object_t *object;
382 struct nameidx *nameidx;
383 char *nametab, *name;
384 int idx;
385
386 if (_dl_prog_prebind_map != NULL) {
387 nameidx = _dl_prog_prebind_map + prog_footer->nameidx_idx;
388 nametab = _dl_prog_prebind_map + prog_footer->nametab_idx;
389 for (idx = 1, object = _dl_objects->next; object != NULL;
390 object = object->next, idx++) {
391 if (object->prebind_data == NULL) {
392 /* ld.so doesn't have prebind data */
393 if (object->next == NULL)
394 continue;
395 DL_DEB(("missing prebind data %s\n",
396 object->load_name));
397 _dl_prebind_match_failed = 1;
398 break;
399 }
400 footer = _dl_prebind_data_to_footer(
401 object->prebind_data);
402 if (footer == NULL ||
403 nameidx[idx].id0 != footer->id0 ||
404 nameidx[idx].id1 != footer->id1) {
405 DL_DEB(("invalid prebind data %s\n",
406 object->load_name));
407 _dl_prebind_match_failed = 1;
408 break;
409 }
410 name = object->load_name;
411 if (_dl_strcmp(nametab + nameidx[idx].name, name)
412 != 0) {
413 DL_DEB(("invalid prebind name %s\n",
414 object->load_name));
415 _dl_prebind_match_failed = 1;
416 break;
417 }
418 }
419 }
420
421 if (_dl_prebind_match_failed) {
422 for (object = _dl_objects; object != NULL;
423 object = object->next)
424 prebind_free(object);
425 if (_dl_bindnow == prebind_bind_now)
426 _dl_bindnow = NULL;
427 }
428
429 if (_dl_debug)
430 _dl_gettimeofday(&beforetp, NULL);
431 }
432
433 void
_dl_prebind_post_resolve()434 _dl_prebind_post_resolve()
435 {
436 char buf[7];
437 int i;
438 struct timeval after_tp;
439 struct timeval diff_tp;
440 elf_object_t *object;
441
442 if (_dl_debug) {
443 _dl_gettimeofday(&after_tp, NULL);
444
445 timersub(&after_tp, &beforetp, &diff_tp);
446
447 for (i = 0; i < 6; i++) {
448 buf[5-i] = (diff_tp.tv_usec % 10) + '0';
449 diff_tp.tv_usec /= 10;
450 }
451 buf[6] = '\0';
452
453 _dl_printf("relocation took %d.%s\n", diff_tp.tv_sec, buf);
454 }
455
456 for (object = _dl_objects; object != NULL; object = object->next)
457 prebind_free(object);
458
459 if (_dl_prebind_validate) {
460 if (validate_errs) {
461 _dl_printf("validate_errs %d\n", validate_errs);
462 _dl_exit(20);
463 } else {
464 _dl_exit(0);
465 }
466 }
467 }
468
469 void
prebind_validate(elf_object_t * req_obj,unsigned int symidx,int flags,const Elf_Sym * ref_sym)470 prebind_validate(elf_object_t *req_obj, unsigned int symidx, int flags,
471 const Elf_Sym *ref_sym)
472 {
473 const Elf_Sym *sym, **this;
474 const elf_object_t *sobj;
475 const char *symn;
476 Elf_Addr ret;
477
478 /* Don't verify non-matching flags*/
479
480 sym = req_obj->dyn.symtab;
481 sym += symidx;
482 symn = req_obj->dyn.strtab + sym->st_name;
483 this = &sym;
484
485 //_dl_printf("checking %s\n", symn);
486 ret = _dl_find_symbol(symn, this, flags, ref_sym, req_obj, &sobj);
487
488 if (_dl_symcache[symidx].sym != *this ||
489 _dl_symcache[symidx].obj != sobj) {
490 _dl_printf("symbol %d mismatch on sym %s req_obj %s,\n"
491 "should be obj %s is obj %s\n",
492 symidx, symn, req_obj->load_name, sobj->load_name,
493 _dl_symcache[symidx].obj->load_name);
494 if (req_obj == sobj)
495 _dl_printf("obj %p %p\n", _dl_symcache[symidx].obj, sobj);
496 sym = _dl_symcache[symidx].obj->dyn.symtab;
497 sym += symidx;
498 symn = _dl_symcache[symidx].obj->dyn.strtab + sym->st_name;
499 _dl_printf("obj %s name %s\n",
500 _dl_symcache[symidx].obj->load_name,
501 symn);
502 }
503 }
504
505 #ifdef DEBUG1
506 void
prebind_dump_symcache(struct symcachetab * symcachetab,u_int32_t cnt)507 prebind_dump_symcache(struct symcachetab *symcachetab, u_int32_t cnt)
508 {
509 struct symcachetab *s;
510 int i;
511
512 _dl_printf("cache: cnt %d\n", cnt);
513 for (i = 0; i < cnt; i++) {
514 s = &(symcachetab[i]);
515 _dl_printf("symidx %d: obj %d sym %d\n",
516 s->idx, s->obj_idx, s->sym_idx);
517 }
518 }
519
520 void
prebind_dump_nameidx(struct nameidx * nameidx,u_int32_t numlibs,char * nametab)521 prebind_dump_nameidx(struct nameidx *nameidx, u_int32_t numlibs, char *nametab)
522 {
523 struct nameidx *n;
524 int i;
525
526 _dl_printf("libs:\n");
527 for (i = 0; i < numlibs; i++) {
528 _dl_printf("lib %d offset %d id0 %d, id1 %d\n", i,
529 nameidx[i].name, nameidx[i].id0, nameidx[i].id1);
530 }
531 for (i = 0; i < numlibs; i++) {
532 n = &(nameidx[i]);
533 _dl_printf("nametab %p n %d\n", nametab, n->name);
534 _dl_printf("lib %s %x %x\n", nametab + n->name, n->id0, n->id1);
535 }
536 }
537
538 void
prebind_dump_fixup(struct fixup * fixup,u_int32_t numfixups)539 prebind_dump_fixup(struct fixup *fixup, u_int32_t numfixups)
540 {
541 struct fixup *f;
542 int i;
543
544 _dl_printf("fixup: %d\n", numfixups);
545 for (i = 0; i < numfixups; i++) {
546 f = &(fixup[i]);
547
548 _dl_printf("idx %d obj %d sym idx %d\n",
549 f->sym, f->obj_idx, f->sym_idx);
550
551 }
552 }
553
554 void
prebind_dump_libmap(u_int32_t * libmap,u_int32_t numlibs)555 prebind_dump_libmap(u_int32_t *libmap, u_int32_t numlibs)
556 {
557 int i;
558
559 for (i = 0; i < numlibs; i++) {
560 //_dl_printf("lib%d off %d %s\n", i, libmap[i], strtab+libmap[i]);
561 _dl_printf("lib%d off %d\n", i, libmap[i]);
562 }
563 }
564
565 void
dl_dump_footer(struct prebind_footer * footer)566 dl_dump_footer(struct prebind_footer *footer)
567 {
568 // _dl_printf("base %qd\n", (long long)footer->prebind_base);
569 _dl_printf("nameidx_idx %d\n", footer->nameidx_idx);
570 _dl_printf("symcache_idx %d\n", footer->symcache_idx);
571 _dl_printf("fixupcnt_idx %d\n", footer->fixupcnt_idx);
572 _dl_printf("fixup_cnt %d\n", footer->fixup_cnt);
573 _dl_printf("nametab_idx %d\n", footer->nametab_idx);
574 _dl_printf("symcache_cnt %d\n", footer->symcache_cnt);
575 _dl_printf("fixup_cnt %d\n", footer->fixup_cnt);
576 _dl_printf("numlibs %d\n", footer->numlibs);
577 _dl_printf("id0 %d\n", footer->id0);
578 _dl_printf("id1 %d\n", footer->id1);
579 // _dl_printf("orig_size %lld\n", (long long)footer->orig_size);
580 _dl_printf("version %d\n", footer->prebind_version);
581 _dl_printf("bind_id %c%c%c%c\n", footer->bind_id[0],
582 footer->bind_id[1], footer->bind_id[2], footer->bind_id[3]);
583 }
584 void
dump_prelink(Elf_Addr base,u_long size)585 dump_prelink(Elf_Addr base, u_long size)
586 {
587 u_int32_t *fixupidx, *fixupcnt, *libmap;
588 struct symcachetab *symcachetab;
589 struct prebind_footer *footer;
590 struct nameidx *nameidx;
591 struct fixup *fixup;
592 char *nametab, *id;
593 void *prebind_map;
594 int i;
595
596 id = (char *) (base+size);
597 id -= 4;
598 DL_DEB(("id %c %c %c %c\n", id[0], id[1], id[2], id[3]));
599 footer = (void *) (base+size - sizeof (struct prebind_footer));
600 dl_dump_footer(footer);
601
602 prebind_map = (void *)base;
603 nameidx = prebind_map + footer->nameidx_idx;;
604 symcachetab = prebind_map + footer->symcache_idx;
605 fixupidx = prebind_map + footer->fixup_idx;
606 nametab = prebind_map + footer->nametab_idx;
607 fixupcnt = prebind_map + footer->fixupcnt_idx;
608 libmap = prebind_map + footer->libmap_idx;
609
610 prebind_dump_symcache(symcachetab, footer->symcache_cnt);
611 prebind_dump_nameidx(nameidx, footer->numlibs, nametab);
612 for (i = 0; i < footer->fixup_cnt; i++) {
613 _dl_printf("fixup %d cnt %d idx %d\n", i, fixupcnt[i], fixupidx[i]);
614 fixup = prebind_map + fixupidx[i];
615 prebind_dump_fixup(fixup, fixupcnt[i]);
616 }
617 prebind_dump_libmap(libmap, footer->numlibs);
618 }
619 #endif /* DEBUG1 */
620