[25] | 1 | /* |
---|
| 2 | * tclLoadAix.c -- |
---|
| 3 | * |
---|
| 4 | * This file implements the dlopen and dlsym APIs under the AIX operating |
---|
| 5 | * system, to enable the Tcl "load" command to work. This code was |
---|
| 6 | * provided by Jens-Uwe Mager. |
---|
| 7 | * |
---|
| 8 | * This file is subject to the following copyright notice, which is |
---|
| 9 | * different from the notice used elsewhere in Tcl. The file has been |
---|
| 10 | * modified to incorporate the file dlfcn.h in-line. |
---|
| 11 | * |
---|
| 12 | * Copyright (c) 1992,1993,1995,1996, Jens-Uwe Mager, Helios Software GmbH |
---|
| 13 | * Not derived from licensed software. |
---|
| 14 | * |
---|
| 15 | * Permission is granted to freely use, copy, modify, and redistribute |
---|
| 16 | * this software, provided that the author is not construed to be liable |
---|
| 17 | * for any results of using the software, alterations are clearly marked |
---|
| 18 | * as such, and this notice is not modified. |
---|
| 19 | * |
---|
| 20 | * RCS: @(#) $Id: tclLoadAix.c,v 1.6 2007/04/16 13:36:36 dkf Exp $ |
---|
| 21 | * |
---|
| 22 | * Note: this file has been altered from the original in a few ways in order |
---|
| 23 | * to work properly with Tcl. |
---|
| 24 | */ |
---|
| 25 | |
---|
| 26 | /* |
---|
| 27 | * @(#)dlfcn.c 1.7 revision of 95/08/14 19:08:38 |
---|
| 28 | * This is an unpublished work copyright (c) 1992 HELIOS Software GmbH |
---|
| 29 | * 30159 Hannover, Germany |
---|
| 30 | */ |
---|
| 31 | |
---|
| 32 | #include <stdio.h> |
---|
| 33 | #include <errno.h> |
---|
| 34 | #include <string.h> |
---|
| 35 | #include <stdlib.h> |
---|
| 36 | #include <sys/types.h> |
---|
| 37 | #include <sys/ldr.h> |
---|
| 38 | #include <a.out.h> |
---|
| 39 | #include <ldfcn.h> |
---|
| 40 | #include "../compat/dlfcn.h" |
---|
| 41 | |
---|
| 42 | /* |
---|
| 43 | * We simulate dlopen() et al. through a call to load. Because AIX has no call |
---|
| 44 | * to find an exported symbol we read the loader section of the loaded module |
---|
| 45 | * and build a list of exported symbols and their virtual address. |
---|
| 46 | */ |
---|
| 47 | |
---|
| 48 | typedef struct { |
---|
| 49 | char *name; /* The symbols's name. */ |
---|
| 50 | void *addr; /* Its relocated virtual address. */ |
---|
| 51 | } Export, *ExportPtr; |
---|
| 52 | |
---|
| 53 | /* |
---|
| 54 | * xlC uses the following structure to list its constructors and destructors. |
---|
| 55 | * This is gleaned from the output of munch. |
---|
| 56 | */ |
---|
| 57 | |
---|
| 58 | typedef struct { |
---|
| 59 | void (*init)(void); /* call static constructors */ |
---|
| 60 | void (*term)(void); /* call static destructors */ |
---|
| 61 | } Cdtor, *CdtorPtr; |
---|
| 62 | |
---|
| 63 | /* |
---|
| 64 | * The void * handle returned from dlopen is actually a ModulePtr. |
---|
| 65 | */ |
---|
| 66 | |
---|
| 67 | typedef struct Module { |
---|
| 68 | struct Module *next; |
---|
| 69 | char *name; /* module name for refcounting */ |
---|
| 70 | int refCnt; /* the number of references */ |
---|
| 71 | void *entry; /* entry point from load */ |
---|
| 72 | struct dl_info *info; /* optional init/terminate functions */ |
---|
| 73 | CdtorPtr cdtors; /* optional C++ constructors */ |
---|
| 74 | int nExports; /* the number of exports found */ |
---|
| 75 | ExportPtr exports; /* the array of exports */ |
---|
| 76 | } Module, *ModulePtr; |
---|
| 77 | |
---|
| 78 | /* |
---|
| 79 | * We keep a list of all loaded modules to be able to call the fini handlers |
---|
| 80 | * and destructors at atexit() time. |
---|
| 81 | */ |
---|
| 82 | |
---|
| 83 | static ModulePtr modList; |
---|
| 84 | |
---|
| 85 | /* |
---|
| 86 | * The last error from one of the dl* routines is kept in static variables |
---|
| 87 | * here. Each error is returned only once to the caller. |
---|
| 88 | */ |
---|
| 89 | |
---|
| 90 | static char errbuf[BUFSIZ]; |
---|
| 91 | static int errvalid; |
---|
| 92 | |
---|
| 93 | static void caterr(char *); |
---|
| 94 | static int readExports(ModulePtr); |
---|
| 95 | static void terminate(void); |
---|
| 96 | static void *findMain(void); |
---|
| 97 | |
---|
| 98 | void * |
---|
| 99 | dlopen( |
---|
| 100 | const char *path, |
---|
| 101 | int mode) |
---|
| 102 | { |
---|
| 103 | register ModulePtr mp; |
---|
| 104 | static void *mainModule; |
---|
| 105 | |
---|
| 106 | /* |
---|
| 107 | * Upon the first call register a terminate handler that will close all |
---|
| 108 | * libraries. Also get a reference to the main module for use with |
---|
| 109 | * loadbind. |
---|
| 110 | */ |
---|
| 111 | |
---|
| 112 | if (!mainModule) { |
---|
| 113 | mainModule = findMain(); |
---|
| 114 | if (mainModule == NULL) { |
---|
| 115 | return NULL; |
---|
| 116 | } |
---|
| 117 | atexit(terminate); |
---|
| 118 | } |
---|
| 119 | |
---|
| 120 | /* |
---|
| 121 | * Scan the list of modules if we have the module already loaded. |
---|
| 122 | */ |
---|
| 123 | |
---|
| 124 | for (mp = modList; mp; mp = mp->next) { |
---|
| 125 | if (strcmp(mp->name, path) == 0) { |
---|
| 126 | mp->refCnt++; |
---|
| 127 | return (void *) mp; |
---|
| 128 | } |
---|
| 129 | } |
---|
| 130 | |
---|
| 131 | mp = (ModulePtr) calloc(1, sizeof(*mp)); |
---|
| 132 | if (mp == NULL) { |
---|
| 133 | errvalid++; |
---|
| 134 | strcpy(errbuf, "calloc: "); |
---|
| 135 | strcat(errbuf, strerror(errno)); |
---|
| 136 | return NULL; |
---|
| 137 | } |
---|
| 138 | |
---|
| 139 | mp->name = malloc((unsigned) (strlen(path) + 1)); |
---|
| 140 | strcpy(mp->name, path); |
---|
| 141 | |
---|
| 142 | /* |
---|
| 143 | * load should be declared load(const char *...). Thus we cast the path to |
---|
| 144 | * a normal char *. Ugly. |
---|
| 145 | */ |
---|
| 146 | |
---|
| 147 | mp->entry = (void *) load((char *)path, L_NOAUTODEFER, NULL); |
---|
| 148 | if (mp->entry == NULL) { |
---|
| 149 | free(mp->name); |
---|
| 150 | free(mp); |
---|
| 151 | errvalid++; |
---|
| 152 | strcpy(errbuf, "dlopen: "); |
---|
| 153 | strcat(errbuf, path); |
---|
| 154 | strcat(errbuf, ": "); |
---|
| 155 | |
---|
| 156 | /* |
---|
| 157 | * If AIX says the file is not executable, the error can be further |
---|
| 158 | * described by querying the loader about the last error. |
---|
| 159 | */ |
---|
| 160 | |
---|
| 161 | if (errno == ENOEXEC) { |
---|
| 162 | char *tmp[BUFSIZ/sizeof(char *)], **p; |
---|
| 163 | |
---|
| 164 | if (loadquery(L_GETMESSAGES, tmp, sizeof(tmp)) == -1) { |
---|
| 165 | strcpy(errbuf, strerror(errno)); |
---|
| 166 | } else { |
---|
| 167 | for (p=tmp ; *p ; p++) { |
---|
| 168 | caterr(*p); |
---|
| 169 | } |
---|
| 170 | } |
---|
| 171 | } else { |
---|
| 172 | strcat(errbuf, strerror(errno)); |
---|
| 173 | } |
---|
| 174 | return NULL; |
---|
| 175 | } |
---|
| 176 | |
---|
| 177 | mp->refCnt = 1; |
---|
| 178 | mp->next = modList; |
---|
| 179 | modList = mp; |
---|
| 180 | |
---|
| 181 | if (loadbind(0, mainModule, mp->entry) == -1) { |
---|
| 182 | loadbindFailure: |
---|
| 183 | dlclose(mp); |
---|
| 184 | errvalid++; |
---|
| 185 | strcpy(errbuf, "loadbind: "); |
---|
| 186 | strcat(errbuf, strerror(errno)); |
---|
| 187 | return NULL; |
---|
| 188 | } |
---|
| 189 | |
---|
| 190 | /* |
---|
| 191 | * If the user wants global binding, loadbind against all other loaded |
---|
| 192 | * modules. |
---|
| 193 | */ |
---|
| 194 | |
---|
| 195 | if (mode & RTLD_GLOBAL) { |
---|
| 196 | register ModulePtr mp1; |
---|
| 197 | |
---|
| 198 | for (mp1 = mp->next; mp1; mp1 = mp1->next) { |
---|
| 199 | if (loadbind(0, mp1->entry, mp->entry) == -1) { |
---|
| 200 | goto loadbindFailure; |
---|
| 201 | } |
---|
| 202 | } |
---|
| 203 | } |
---|
| 204 | |
---|
| 205 | if (readExports(mp) == -1) { |
---|
| 206 | dlclose(mp); |
---|
| 207 | return NULL; |
---|
| 208 | } |
---|
| 209 | |
---|
| 210 | /* |
---|
| 211 | * If there is a dl_info structure, call the init function. |
---|
| 212 | */ |
---|
| 213 | |
---|
| 214 | if (mp->info = (struct dl_info *)dlsym(mp, "dl_info")) { |
---|
| 215 | if (mp->info->init) { |
---|
| 216 | (*mp->info->init)(); |
---|
| 217 | } |
---|
| 218 | } else { |
---|
| 219 | errvalid = 0; |
---|
| 220 | } |
---|
| 221 | |
---|
| 222 | /* |
---|
| 223 | * If the shared object was compiled using xlC we will need to call static |
---|
| 224 | * constructors (and later on dlclose destructors). |
---|
| 225 | */ |
---|
| 226 | |
---|
| 227 | if (mp->cdtors = (CdtorPtr) dlsym(mp, "__cdtors")) { |
---|
| 228 | while (mp->cdtors->init) { |
---|
| 229 | (*mp->cdtors->init)(); |
---|
| 230 | mp->cdtors++; |
---|
| 231 | } |
---|
| 232 | } else { |
---|
| 233 | errvalid = 0; |
---|
| 234 | } |
---|
| 235 | |
---|
| 236 | return (void *) mp; |
---|
| 237 | } |
---|
| 238 | |
---|
| 239 | /* |
---|
| 240 | * Attempt to decipher an AIX loader error message and append it to our static |
---|
| 241 | * error message buffer. |
---|
| 242 | */ |
---|
| 243 | |
---|
| 244 | static void |
---|
| 245 | caterr( |
---|
| 246 | char *s) |
---|
| 247 | { |
---|
| 248 | register char *p = s; |
---|
| 249 | |
---|
| 250 | while (*p >= '0' && *p <= '9') { |
---|
| 251 | p++; |
---|
| 252 | } |
---|
| 253 | switch (atoi(s)) { /* INTL: "C", UTF safe. */ |
---|
| 254 | case L_ERROR_TOOMANY: |
---|
| 255 | strcat(errbuf, "to many errors"); |
---|
| 256 | break; |
---|
| 257 | case L_ERROR_NOLIB: |
---|
| 258 | strcat(errbuf, "can't load library"); |
---|
| 259 | strcat(errbuf, p); |
---|
| 260 | break; |
---|
| 261 | case L_ERROR_UNDEF: |
---|
| 262 | strcat(errbuf, "can't find symbol"); |
---|
| 263 | strcat(errbuf, p); |
---|
| 264 | break; |
---|
| 265 | case L_ERROR_RLDBAD: |
---|
| 266 | strcat(errbuf, "bad RLD"); |
---|
| 267 | strcat(errbuf, p); |
---|
| 268 | break; |
---|
| 269 | case L_ERROR_FORMAT: |
---|
| 270 | strcat(errbuf, "bad exec format in"); |
---|
| 271 | strcat(errbuf, p); |
---|
| 272 | break; |
---|
| 273 | case L_ERROR_ERRNO: |
---|
| 274 | strcat(errbuf, strerror(atoi(++p))); /* INTL: "C", UTF safe. */ |
---|
| 275 | break; |
---|
| 276 | default: |
---|
| 277 | strcat(errbuf, s); |
---|
| 278 | break; |
---|
| 279 | } |
---|
| 280 | } |
---|
| 281 | |
---|
| 282 | void * |
---|
| 283 | dlsym( |
---|
| 284 | void *handle, |
---|
| 285 | const char *symbol) |
---|
| 286 | { |
---|
| 287 | register ModulePtr mp = (ModulePtr)handle; |
---|
| 288 | register ExportPtr ep; |
---|
| 289 | register int i; |
---|
| 290 | |
---|
| 291 | /* |
---|
| 292 | * Could speed up the search, but I assume that one assigns the result to |
---|
| 293 | * function pointers anyways. |
---|
| 294 | */ |
---|
| 295 | |
---|
| 296 | for (ep = mp->exports, i = mp->nExports; i; i--, ep++) { |
---|
| 297 | if (strcmp(ep->name, symbol) == 0) { |
---|
| 298 | return ep->addr; |
---|
| 299 | } |
---|
| 300 | } |
---|
| 301 | |
---|
| 302 | errvalid++; |
---|
| 303 | strcpy(errbuf, "dlsym: undefined symbol "); |
---|
| 304 | strcat(errbuf, symbol); |
---|
| 305 | return NULL; |
---|
| 306 | } |
---|
| 307 | |
---|
| 308 | char * |
---|
| 309 | dlerror(void) |
---|
| 310 | { |
---|
| 311 | if (errvalid) { |
---|
| 312 | errvalid = 0; |
---|
| 313 | return errbuf; |
---|
| 314 | } |
---|
| 315 | return NULL; |
---|
| 316 | } |
---|
| 317 | |
---|
| 318 | int |
---|
| 319 | dlclose( |
---|
| 320 | void *handle) |
---|
| 321 | { |
---|
| 322 | register ModulePtr mp = (ModulePtr)handle; |
---|
| 323 | int result; |
---|
| 324 | register ModulePtr mp1; |
---|
| 325 | |
---|
| 326 | if (--mp->refCnt > 0) { |
---|
| 327 | return 0; |
---|
| 328 | } |
---|
| 329 | |
---|
| 330 | if (mp->info && mp->info->fini) { |
---|
| 331 | (*mp->info->fini)(); |
---|
| 332 | } |
---|
| 333 | |
---|
| 334 | if (mp->cdtors) { |
---|
| 335 | while (mp->cdtors->term) { |
---|
| 336 | (*mp->cdtors->term)(); |
---|
| 337 | mp->cdtors++; |
---|
| 338 | } |
---|
| 339 | } |
---|
| 340 | |
---|
| 341 | result = unload(mp->entry); |
---|
| 342 | if (result == -1) { |
---|
| 343 | errvalid++; |
---|
| 344 | strcpy(errbuf, strerror(errno)); |
---|
| 345 | } |
---|
| 346 | |
---|
| 347 | if (mp->exports) { |
---|
| 348 | register ExportPtr ep; |
---|
| 349 | register int i; |
---|
| 350 | for (ep = mp->exports, i = mp->nExports; i; i--, ep++) { |
---|
| 351 | if (ep->name) { |
---|
| 352 | free(ep->name); |
---|
| 353 | } |
---|
| 354 | } |
---|
| 355 | free(mp->exports); |
---|
| 356 | } |
---|
| 357 | |
---|
| 358 | if (mp == modList) { |
---|
| 359 | modList = mp->next; |
---|
| 360 | } else { |
---|
| 361 | for (mp1 = modList; mp1; mp1 = mp1->next) { |
---|
| 362 | if (mp1->next == mp) { |
---|
| 363 | mp1->next = mp->next; |
---|
| 364 | break; |
---|
| 365 | } |
---|
| 366 | } |
---|
| 367 | } |
---|
| 368 | |
---|
| 369 | free(mp->name); |
---|
| 370 | free(mp); |
---|
| 371 | return result; |
---|
| 372 | } |
---|
| 373 | |
---|
| 374 | static void |
---|
| 375 | terminate(void) |
---|
| 376 | { |
---|
| 377 | while (modList) { |
---|
| 378 | dlclose(modList); |
---|
| 379 | } |
---|
| 380 | } |
---|
| 381 | |
---|
| 382 | /* |
---|
| 383 | * Build the export table from the XCOFF .loader section. |
---|
| 384 | */ |
---|
| 385 | |
---|
| 386 | static int |
---|
| 387 | readExports( |
---|
| 388 | ModulePtr mp) |
---|
| 389 | { |
---|
| 390 | LDFILE *ldp = NULL; |
---|
| 391 | SCNHDR sh, shdata; |
---|
| 392 | LDHDR *lhp; |
---|
| 393 | char *ldbuf; |
---|
| 394 | LDSYM *ls; |
---|
| 395 | int i; |
---|
| 396 | ExportPtr ep; |
---|
| 397 | const char *errMsg; |
---|
| 398 | |
---|
| 399 | #define Error(msg) do{errMsg=(msg);goto error;}while(0) |
---|
| 400 | #define SysErr() Error(strerror(errno)) |
---|
| 401 | |
---|
| 402 | ldp = ldopen(mp->name, ldp); |
---|
| 403 | if (ldp == NULL) { |
---|
| 404 | struct ld_info *lp; |
---|
| 405 | char *buf; |
---|
| 406 | int size = 0; |
---|
| 407 | |
---|
| 408 | if (errno != ENOENT) { |
---|
| 409 | SysErr(); |
---|
| 410 | } |
---|
| 411 | |
---|
| 412 | /* |
---|
| 413 | * The module might be loaded due to the LIBPATH environment variable. |
---|
| 414 | * Search for the loaded module using L_GETINFO. |
---|
| 415 | */ |
---|
| 416 | |
---|
| 417 | while (1) { |
---|
| 418 | size += 4 * 1024; |
---|
| 419 | buf = malloc(size); |
---|
| 420 | if (buf == NULL) { |
---|
| 421 | SysErr(); |
---|
| 422 | } |
---|
| 423 | |
---|
| 424 | i = loadquery(L_GETINFO, buf, size); |
---|
| 425 | |
---|
| 426 | if (i != -1) { |
---|
| 427 | break; |
---|
| 428 | } |
---|
| 429 | free(buf); |
---|
| 430 | if (errno != ENOMEM) { |
---|
| 431 | SysErr(); |
---|
| 432 | } |
---|
| 433 | } |
---|
| 434 | |
---|
| 435 | /* |
---|
| 436 | * Traverse the list of loaded modules. The entry point returned by |
---|
| 437 | * load() does actually point to the data segment origin. |
---|
| 438 | */ |
---|
| 439 | |
---|
| 440 | lp = (struct ld_info *) buf; |
---|
| 441 | while (lp) { |
---|
| 442 | if (lp->ldinfo_dataorg == mp->entry) { |
---|
| 443 | ldp = ldopen(lp->ldinfo_filename, ldp); |
---|
| 444 | break; |
---|
| 445 | } |
---|
| 446 | if (lp->ldinfo_next == 0) { |
---|
| 447 | lp = NULL; |
---|
| 448 | } else { |
---|
| 449 | lp = (struct ld_info *)((char *)lp + lp->ldinfo_next); |
---|
| 450 | } |
---|
| 451 | } |
---|
| 452 | |
---|
| 453 | free(buf); |
---|
| 454 | |
---|
| 455 | if (!ldp) { |
---|
| 456 | SysErr(); |
---|
| 457 | } |
---|
| 458 | } |
---|
| 459 | |
---|
| 460 | if (TYPE(ldp) != U802TOCMAGIC) { |
---|
| 461 | Error("bad magic"); |
---|
| 462 | } |
---|
| 463 | |
---|
| 464 | /* |
---|
| 465 | * Get the padding for the data section. This is needed for AIX 4.1 |
---|
| 466 | * compilers. This is used when building the final function pointer to the |
---|
| 467 | * exported symbol. |
---|
| 468 | */ |
---|
| 469 | |
---|
| 470 | if (ldnshread(ldp, _DATA, &shdata) != SUCCESS) { |
---|
| 471 | Error("cannot read data section header"); |
---|
| 472 | } |
---|
| 473 | |
---|
| 474 | if (ldnshread(ldp, _LOADER, &sh) != SUCCESS) { |
---|
| 475 | Error("cannot read loader section header"); |
---|
| 476 | } |
---|
| 477 | |
---|
| 478 | /* |
---|
| 479 | * We read the complete loader section in one chunk, this makes finding |
---|
| 480 | * long symbol names residing in the string table easier. |
---|
| 481 | */ |
---|
| 482 | |
---|
| 483 | ldbuf = (char *) malloc(sh.s_size); |
---|
| 484 | if (ldbuf == NULL) { |
---|
| 485 | SysErr(); |
---|
| 486 | } |
---|
| 487 | |
---|
| 488 | if (FSEEK(ldp, sh.s_scnptr, BEGINNING) != OKFSEEK) { |
---|
| 489 | free(ldbuf); |
---|
| 490 | Error("cannot seek to loader section"); |
---|
| 491 | } |
---|
| 492 | |
---|
| 493 | if (FREAD(ldbuf, sh.s_size, 1, ldp) != 1) { |
---|
| 494 | free(ldbuf); |
---|
| 495 | Error("cannot read loader section"); |
---|
| 496 | } |
---|
| 497 | |
---|
| 498 | lhp = (LDHDR *) ldbuf; |
---|
| 499 | ls = (LDSYM *)(ldbuf + LDHDRSZ); |
---|
| 500 | |
---|
| 501 | /* |
---|
| 502 | * Count the number of exports to include in our export table. |
---|
| 503 | */ |
---|
| 504 | |
---|
| 505 | for (i = lhp->l_nsyms; i; i--, ls++) { |
---|
| 506 | if (!LDR_EXPORT(*ls)) { |
---|
| 507 | continue; |
---|
| 508 | } |
---|
| 509 | mp->nExports++; |
---|
| 510 | } |
---|
| 511 | |
---|
| 512 | mp->exports = (ExportPtr) calloc(mp->nExports, sizeof(*mp->exports)); |
---|
| 513 | if (mp->exports == NULL) { |
---|
| 514 | free(ldbuf); |
---|
| 515 | SysErr(); |
---|
| 516 | } |
---|
| 517 | |
---|
| 518 | /* |
---|
| 519 | * Fill in the export table. All entries are relative to the entry point |
---|
| 520 | * we got from load. |
---|
| 521 | */ |
---|
| 522 | |
---|
| 523 | ep = mp->exports; |
---|
| 524 | ls = (LDSYM *)(ldbuf + LDHDRSZ); |
---|
| 525 | for (i=lhp->l_nsyms ; i!=0 ; i--,ls++) { |
---|
| 526 | char *symname; |
---|
| 527 | char tmpsym[SYMNMLEN+1]; |
---|
| 528 | |
---|
| 529 | if (!LDR_EXPORT(*ls)) { |
---|
| 530 | continue; |
---|
| 531 | } |
---|
| 532 | |
---|
| 533 | if (ls->l_zeroes == 0) { |
---|
| 534 | symname = ls->l_offset + lhp->l_stoff + ldbuf; |
---|
| 535 | } else { |
---|
| 536 | /* |
---|
| 537 | * The l_name member is not zero terminated, we must copy the |
---|
| 538 | * first SYMNMLEN chars and make sure we have a zero byte at the |
---|
| 539 | * end. |
---|
| 540 | */ |
---|
| 541 | |
---|
| 542 | strncpy(tmpsym, ls->l_name, SYMNMLEN); |
---|
| 543 | tmpsym[SYMNMLEN] = '\0'; |
---|
| 544 | symname = tmpsym; |
---|
| 545 | } |
---|
| 546 | ep->name = malloc((unsigned) (strlen(symname) + 1)); |
---|
| 547 | strcpy(ep->name, symname); |
---|
| 548 | ep->addr = (void *)((unsigned long) |
---|
| 549 | mp->entry + ls->l_value - shdata.s_vaddr); |
---|
| 550 | ep++; |
---|
| 551 | } |
---|
| 552 | free(ldbuf); |
---|
| 553 | while (ldclose(ldp) == FAILURE) { |
---|
| 554 | /* Empty body */ |
---|
| 555 | } |
---|
| 556 | return 0; |
---|
| 557 | |
---|
| 558 | /* |
---|
| 559 | * This is a factoring out of the error-handling code to make the rest of |
---|
| 560 | * the function much simpler to read. |
---|
| 561 | */ |
---|
| 562 | |
---|
| 563 | error: |
---|
| 564 | errvalid++; |
---|
| 565 | strcpy(errbuf, "readExports: "); |
---|
| 566 | strcat(errbuf, errMsg); |
---|
| 567 | |
---|
| 568 | if (ldp != NULL) { |
---|
| 569 | while (ldclose(ldp) == FAILURE) { |
---|
| 570 | /* Empty body */ |
---|
| 571 | } |
---|
| 572 | } |
---|
| 573 | return -1; |
---|
| 574 | } |
---|
| 575 | |
---|
| 576 | /* |
---|
| 577 | * Find the main modules entry point. This is used as export pointer for |
---|
| 578 | * loadbind() to be able to resolve references to the main part. |
---|
| 579 | */ |
---|
| 580 | |
---|
| 581 | static void * |
---|
| 582 | findMain(void) |
---|
| 583 | { |
---|
| 584 | struct ld_info *lp; |
---|
| 585 | char *buf; |
---|
| 586 | int size = 4*1024; |
---|
| 587 | int i; |
---|
| 588 | void *ret; |
---|
| 589 | |
---|
| 590 | buf = malloc(size); |
---|
| 591 | if (buf == NULL) { |
---|
| 592 | goto error; |
---|
| 593 | } |
---|
| 594 | |
---|
| 595 | while ((i = loadquery(L_GETINFO, buf, size)) == -1 && errno == ENOMEM) { |
---|
| 596 | free(buf); |
---|
| 597 | size += 4*1024; |
---|
| 598 | buf = malloc(size); |
---|
| 599 | if (buf == NULL) { |
---|
| 600 | goto error; |
---|
| 601 | } |
---|
| 602 | } |
---|
| 603 | |
---|
| 604 | if (i == -1) { |
---|
| 605 | free(buf); |
---|
| 606 | goto error; |
---|
| 607 | } |
---|
| 608 | |
---|
| 609 | /* |
---|
| 610 | * The first entry is the main module. The entry point returned by load() |
---|
| 611 | * does actually point to the data segment origin. |
---|
| 612 | */ |
---|
| 613 | |
---|
| 614 | lp = (struct ld_info *) buf; |
---|
| 615 | ret = lp->ldinfo_dataorg; |
---|
| 616 | free(buf); |
---|
| 617 | return ret; |
---|
| 618 | |
---|
| 619 | error: |
---|
| 620 | errvalid++; |
---|
| 621 | strcpy(errbuf, "findMain: "); |
---|
| 622 | strcat(errbuf, strerror(errno)); |
---|
| 623 | return NULL; |
---|
| 624 | } |
---|
| 625 | |
---|
| 626 | /* |
---|
| 627 | * Local Variables: |
---|
| 628 | * mode: c |
---|
| 629 | * c-basic-offset: 4 |
---|
| 630 | * fill-column: 78 |
---|
| 631 | * End: |
---|
| 632 | */ |
---|