Ben Gamari pushed to branch wip/T130103 at Glasgow Haskell Compiler / GHC

Commits:

1 changed file:

Changes:

  • rts/linker/LoadArchive.c
    ... ... @@ -33,6 +33,7 @@
    33 33
     
    
    34 34
     #define DEBUG_LOG(...) IF_DEBUG(linker, debugBelch("loadArchive: " __VA_ARGS__))
    
    35 35
     
    
    36
    +
    
    36 37
     #if defined(darwin_HOST_OS) || defined(ios_HOST_OS)
    
    37 38
     /* Read 4 bytes and convert to host byte order */
    
    38 39
     static uint32_t read4Bytes(const char buf[static 4])
    
    ... ... @@ -40,7 +41,7 @@ static uint32_t read4Bytes(const char buf[static 4])
    40 41
         return ntohl(*(uint32_t*)buf);
    
    41 42
     }
    
    42 43
     
    
    43
    -static bool loadFatArchive(char tmp[static 20], FILE* f, pathchar* path)
    
    44
    +static bool loadFatArchive(char input[static 20], FILE* f, pathchar* path)
    
    44 45
     {
    
    45 46
         uint32_t nfat_arch, nfat_offset, cputype, cpusubtype;
    
    46 47
     #if defined(i386_HOST_ARCH)
    
    ... ... @@ -58,8 +59,9 @@ static bool loadFatArchive(char tmp[static 20], FILE* f, pathchar* path)
    58 59
     #error Unknown Darwin architecture
    
    59 60
     #endif
    
    60 61
     
    
    61
    -    nfat_arch = read4Bytes(tmp + 4);
    
    62
    +    nfat_arch = read4Bytes(input + 4);
    
    62 63
         DEBUG_LOG("found a fat archive containing %d architectures\n", nfat_arch);
    
    64
    +    char tmp[20];
    
    63 65
         nfat_offset = 0;
    
    64 66
         for (uint32_t i = 0; i < nfat_arch; i++) {
    
    65 67
             /* search for the right arch */
    
    ... ... @@ -108,7 +110,40 @@ static bool loadFatArchive(char tmp[static 20], FILE* f, pathchar* path)
    108 110
     }
    
    109 111
     #endif
    
    110 112
     
    
    111
    -static StgBool readThinArchiveMember(int n, int memberSize, pathchar* path,
    
    113
    +enum ObjectFileFormat {
    
    114
    +    NotObject,
    
    115
    +    PortableExecutable,
    
    116
    +    ELF,
    
    117
    +    MachO32,
    
    118
    +    MachO64,
    
    119
    +};
    
    120
    +
    
    121
    +static enum ObjectFileFormat identifyObjectFile_(char* buf, size_t sz)
    
    122
    +{
    
    123
    +    if (sz > 2 && ((uint16_t*)buf)[0] == 0x5a4d) {
    
    124
    +        return PortableExecutable;
    
    125
    +    }
    
    126
    +    if (sz > 4 && memcmp(buf, "\x7f" "ELF", 4) == 0) {
    
    127
    +        return ELF;
    
    128
    +    }
    
    129
    +    if (sz > 4 && ((uint32_t*)buf)[0] == 0xfeedface) {
    
    130
    +        return MachO32;
    
    131
    +    }
    
    132
    +    if (sz > 4 && ((uint32_t*)buf)[0] == 0xfeedfacf) {
    
    133
    +        return MachO64;
    
    134
    +    }
    
    135
    +    return NotObject;
    
    136
    +}
    
    137
    +
    
    138
    +static enum ObjectFileFormat identifyObjectFile(FILE *f)
    
    139
    +{
    
    140
    +    char buf[32];
    
    141
    +    ssize_t sz = fread(buf, 1, 32, f);
    
    142
    +    CHECK(fseek(f, -sz, SEEK_CUR) == 0);
    
    143
    +    return identifyObjectFile_(buf, sz);
    
    144
    +}
    
    145
    +
    
    146
    +static bool readThinArchiveMember(int n, int memberSize, pathchar* path,
    
    112 147
             char* fileName, char* image)
    
    113 148
     {
    
    114 149
         bool has_succeeded = false;
    
    ... ... @@ -149,7 +184,7 @@ inner_fail:
    149 184
         return has_succeeded;
    
    150 185
     }
    
    151 186
     
    
    152
    -static bool checkFatArchive(char magic[static 20], FILE* f, pathchar* path)
    
    187
    +static bool checkFatArchive(char magic[static 4], FILE* f, pathchar* path)
    
    153 188
     {
    
    154 189
         bool success = false;
    
    155 190
     #if defined(darwin_HOST_OS) || defined(ios_HOST_OS)
    
    ... ... @@ -241,46 +276,21 @@ lookupGNUArchiveIndex(int gnuFileIndexSize, char **fileName_,
    241 276
         return true;
    
    242 277
     }
    
    243 278
     
    
    244
    -HsInt loadArchive_ (pathchar *path)
    
    245
    -{
    
    246
    -    char *image = NULL;
    
    247
    -    HsInt retcode = 0;
    
    248
    -    int memberSize;
    
    249
    -    int memberIdx = 0;
    
    250
    -    FILE *f = NULL;
    
    251
    -    int n;
    
    252
    -    size_t thisFileNameSize = (size_t)-1; /* shut up bogus GCC warning */
    
    253
    -    char *fileName;
    
    254
    -    size_t fileNameSize;
    
    255
    -    bool isGnuIndex, isThin, isImportLib;
    
    256
    -    char *gnuFileIndex;
    
    257
    -    int gnuFileIndexSize;
    
    258
    -    int misalignment = 0;
    
    259
    -
    
    260
    -    DEBUG_LOG("start\n");
    
    261
    -    DEBUG_LOG("Loading archive `%" PATH_FMT "'\n", path);
    
    279
    +enum ArchiveFormat {
    
    280
    +    StandardArchive,
    
    281
    +    ThinArchive,
    
    282
    +    FatArchive,
    
    283
    +};
    
    262 284
     
    
    263
    -    /* Check that we haven't already loaded this archive.
    
    264
    -       Ignore requests to load multiple times */
    
    265
    -    if (isAlreadyLoaded(path)) {
    
    266
    -        IF_DEBUG(linker,
    
    267
    -                 debugBelch("ignoring repeated load of %" PATH_FMT "\n", path));
    
    268
    -        return 1; /* success */
    
    285
    +static bool identifyArchiveFormat(FILE *f, pathchar *path, enum ArchiveFormat *out)
    
    286
    +{
    
    287
    +    char tmp[8];
    
    288
    +    size_t n = fread(tmp, 1, 8, f);
    
    289
    +    if (n != 8) {
    
    290
    +        errorBelch("loadArchive: Failed reading header from `%" PATH_FMT "'", path); \
    
    291
    +        return false;
    
    269 292
         }
    
    270 293
     
    
    271
    -    gnuFileIndex = NULL;
    
    272
    -    gnuFileIndexSize = 0;
    
    273
    -
    
    274
    -    fileNameSize = 32;
    
    275
    -    fileName = stgMallocBytes(fileNameSize, "loadArchive(fileName)");
    
    276
    -
    
    277
    -    isThin = false;
    
    278
    -    isImportLib = false;
    
    279
    -
    
    280
    -    f = pathopen(path, WSTR("rb"));
    
    281
    -    if (!f)
    
    282
    -        FAIL("loadObj: can't read `%" PATH_FMT "'", path);
    
    283
    -
    
    284 294
         /* Check if this is an archive by looking for the magic "!<arch>\n"
    
    285 295
          * string.  Usually, if this fails, we belch an error and return.  On
    
    286 296
          * Darwin however, we may have a fat archive, which contains archives for
    
    ... ... @@ -299,12 +309,10 @@ HsInt loadArchive_ (pathchar *path)
    299 309
          * its magic "!<arch>\n" string and continue processing just as if
    
    300 310
          * we had a single architecture archive.
    
    301 311
          */
    
    302
    -
    
    303
    -    n = fread ( tmp, 1, 8, f );
    
    304
    -    if (n != 8) {
    
    305
    -        FAIL("Failed reading header from `%" PATH_FMT "'", path);
    
    312
    +    if (strncmp(tmp, "!<arch>\n", 8) == 0) {
    
    313
    +        *out = StandardArchive;
    
    314
    +        return true;
    
    306 315
         }
    
    307
    -    if (strncmp(tmp, "!<arch>\n", 8) == 0) {}
    
    308 316
         /* Check if this is a thin archive by looking for the magic string "!<thin>\n"
    
    309 317
          *
    
    310 318
          * ar thin libraries have the exact same format as normal archives except they
    
    ... ... @@ -321,16 +329,59 @@ HsInt loadArchive_ (pathchar *path)
    321 329
          *
    
    322 330
          */
    
    323 331
         else if (strncmp(tmp, "!<thin>\n", 8) == 0) {
    
    324
    -        isThin = true;
    
    332
    +        *out = ThinArchive;
    
    333
    +        return true;
    
    325 334
         }
    
    326 335
         else {
    
    327 336
             bool success = checkFatArchive(tmp, f, path);
    
    328
    -        if (!success)
    
    329
    -            goto fail;
    
    337
    +        if (!success) {
    
    338
    +            return false;
    
    339
    +        }
    
    340
    +        *out = FatArchive;
    
    341
    +        return true;
    
    330 342
         }
    
    343
    +}
    
    344
    +
    
    345
    +HsInt loadArchive_ (pathchar *path)
    
    346
    +{
    
    347
    +    char *image = NULL;
    
    348
    +    HsInt retcode = 0;
    
    349
    +    int memberIdx = 0;
    
    350
    +    FILE *f = NULL;
    
    351
    +    size_t thisFileNameSize = (size_t) -1; /* shut up bogus GCC warning */
    
    352
    +    int misalignment = 0;
    
    353
    +
    
    354
    +    DEBUG_LOG("start\n");
    
    355
    +    DEBUG_LOG("Loading archive `%" PATH_FMT "'\n", path);
    
    356
    +
    
    357
    +    /* Check that we haven't already loaded this archive.
    
    358
    +       Ignore requests to load multiple times */
    
    359
    +    if (isAlreadyLoaded(path)) {
    
    360
    +        IF_DEBUG(linker,
    
    361
    +                 debugBelch("ignoring repeated load of %" PATH_FMT "\n", path));
    
    362
    +        return 1; /* success */
    
    363
    +    }
    
    364
    +
    
    365
    +    char *gnuFileIndex = NULL;
    
    366
    +    int gnuFileIndexSize = 0;
    
    367
    +
    
    368
    +    size_t fileNameSize = 32;
    
    369
    +    char *fileName = stgMallocBytes(fileNameSize, "loadArchive(fileName)");
    
    370
    +
    
    371
    +    f = pathopen(path, WSTR("rb"));
    
    372
    +    if (!f)
    
    373
    +        FAIL("loadObj: can't read `%" PATH_FMT "'", path);
    
    374
    +
    
    375
    +    enum ArchiveFormat archive_fmt;
    
    376
    +    if (!identifyArchiveFormat(f, path, &archive_fmt)) {
    
    377
    +        FAIL("failed to identify archive format of %" PATH_FMT ".", path);
    
    378
    +    }
    
    379
    +    bool isThin = archive_fmt == ThinArchive;
    
    380
    +
    
    331 381
         DEBUG_LOG("loading archive contents\n");
    
    332 382
     
    
    333 383
         while (1) {
    
    384
    +        size_t n;
    
    334 385
             DEBUG_LOG("reading at %ld\n", ftell(f));
    
    335 386
             n = fread ( fileName, 1, 16, f );
    
    336 387
             if (n != 16) {
    
    ... ... @@ -350,6 +401,7 @@ HsInt loadArchive_ (pathchar *path)
    350 401
             }
    
    351 402
     #endif
    
    352 403
     
    
    404
    +        char tmp[32];
    
    353 405
             n = fread ( tmp, 1, 12, f );
    
    354 406
             if (n != 12)
    
    355 407
                 FAIL("Failed reading mod time from `%" PATH_FMT "'", path);
    
    ... ... @@ -368,9 +420,16 @@ HsInt loadArchive_ (pathchar *path)
    368 420
             tmp[10] = '\0';
    
    369 421
             for (n = 0; isdigit(tmp[n]); n++);
    
    370 422
             tmp[n] = '\0';
    
    371
    -        memberSize = atoi(tmp);
    
    423
    +        size_t memberSize;
    
    424
    +        {
    
    425
    +            char *end;
    
    426
    +            memberSize = strtol(tmp, &end, 10);
    
    427
    +            if (tmp == end) {
    
    428
    +                FAIL("Failed to decode member size");
    
    429
    +            }
    
    430
    +        }
    
    372 431
     
    
    373
    -        DEBUG_LOG("size of this archive member is %d\n", memberSize);
    
    432
    +        DEBUG_LOG("size of this archive member is %zd\n", memberSize);
    
    374 433
             n = fread ( tmp, 1, 2, f );
    
    375 434
             if (n != 2)
    
    376 435
                 FAIL("Failed reading magic from `%" PATH_FMT "'", path);
    
    ... ... @@ -378,7 +437,7 @@ HsInt loadArchive_ (pathchar *path)
    378 437
                 FAIL("Failed reading magic from `%" PATH_FMT "' at %ld. Got %c%c",
    
    379 438
                      path, ftell(f), tmp[0], tmp[1]);
    
    380 439
     
    
    381
    -        isGnuIndex = false;
    
    440
    +        bool isGnuIndex = false;
    
    382 441
             /* Check for BSD-variant large filenames */
    
    383 442
             if (0 == strncmp(fileName, "#1/", 3)) {
    
    384 443
                 size_t n = 0;
    
    ... ... @@ -459,12 +518,7 @@ HsInt loadArchive_ (pathchar *path)
    459 518
     
    
    460 519
             DEBUG_LOG("Found member file `%s'\n", fileName);
    
    461 520
     
    
    462
    -        /* TODO: Stop relying on file extensions to determine input formats.
    
    463
    -                 Instead try to match file headers. See #13103.  */
    
    464
    -        isObject = (thisFileNameSize >= 2 && strncmp(fileName + thisFileNameSize - 2, ".o"  , 2) == 0)
    
    465
    -                || (thisFileNameSize >= 3 && strncmp(fileName + thisFileNameSize - 3, ".lo" , 3) == 0)
    
    466
    -                || (thisFileNameSize >= 4 && strncmp(fileName + thisFileNameSize - 4, ".p_o", 4) == 0)
    
    467
    -                || (thisFileNameSize >= 4 && strncmp(fileName + thisFileNameSize - 4, ".obj", 4) == 0);
    
    521
    +        enum ObjectFileFormat object_fmt = identifyObjectFile(f);
    
    468 522
     
    
    469 523
     #if defined(OBJFORMAT_PEi386)
    
    470 524
             /*
    
    ... ... @@ -478,13 +532,15 @@ HsInt loadArchive_ (pathchar *path)
    478 532
             *
    
    479 533
             * Linker members (e.g. filename / are skipped since they are not needed)
    
    480 534
             */
    
    481
    -        isImportLib = thisFileNameSize >= 4 && strncmp(fileName + thisFileNameSize - 4, ".dll", 4) == 0;
    
    535
    +        bool isImportLib = thisFileNameSize >= 4 && strncmp(fileName + thisFileNameSize - 4, ".dll", 4) == 0;
    
    536
    +#else
    
    537
    +        bool isImportLib = false;
    
    482 538
     #endif // windows
    
    483 539
     
    
    484 540
             DEBUG_LOG("\tthisFileNameSize = %d\n", (int)thisFileNameSize);
    
    485
    -        DEBUG_LOG("\tisObject = %d\n", isObject);
    
    541
    +        DEBUG_LOG("\tisObject = %d\n", object_fmt);
    
    486 542
     
    
    487
    -        if (isObject) {
    
    543
    +        if (object_fmt != NotObject) {
    
    488 544
                 DEBUG_LOG("Member is an object file...loading...\n");
    
    489 545
     
    
    490 546
     #if defined(darwin_HOST_OS) || defined(ios_HOST_OS)
    
    ... ... @@ -509,7 +565,7 @@ HsInt loadArchive_ (pathchar *path)
    509 565
                 }
    
    510 566
                 else
    
    511 567
                 {
    
    512
    -                n = fread ( image, 1, memberSize, f );
    
    568
    +                size_t n = fread ( image, 1, memberSize, f );
    
    513 569
                     if (n != memberSize) {
    
    514 570
                         FAIL("error whilst reading `%" PATH_FMT "'", path);
    
    515 571
                     }
    
    ... ... @@ -527,9 +583,11 @@ HsInt loadArchive_ (pathchar *path)
    527 583
                 ObjectCode *oc = mkOc(STATIC_OBJECT, path, image, memberSize, false, archiveMemberName,
    
    528 584
                                       misalignment);
    
    529 585
     #if defined(OBJFORMAT_MACHO)
    
    586
    +            ASSERT(object_fmt == MachO32 || object_fmt == MachO64);
    
    530 587
                 ocInit_MachO( oc );
    
    531 588
     #endif
    
    532 589
     #if defined(OBJFORMAT_ELF)
    
    590
    +            ASSERT(object_fmt == ELF);
    
    533 591
                 ocInit_ELF( oc );
    
    534 592
     #endif
    
    535 593
     
    
    ... ... @@ -574,7 +632,7 @@ while reading filename from `%" PATH_FMT "'", path);
    574 632
                               "Skipping...\n");
    
    575 633
                     n = fseek(f, memberSize, SEEK_CUR);
    
    576 634
                     if (n != 0)
    
    577
    -                    FAIL("error whilst seeking by %d in `%" PATH_FMT "'",
    
    635
    +                    FAIL("error whilst seeking by %zd in `%" PATH_FMT "'",
    
    578 636
                         memberSize, path);
    
    579 637
                 }
    
    580 638
     #endif
    
    ... ... @@ -585,7 +643,7 @@ while reading filename from `%" PATH_FMT "'", path);
    585 643
                 if (!isThin || thisFileNameSize == 0) {
    
    586 644
                     n = fseek(f, memberSize, SEEK_CUR);
    
    587 645
                     if (n != 0)
    
    588
    -                    FAIL("error whilst seeking by %d in `%" PATH_FMT "'",
    
    646
    +                    FAIL("error whilst seeking by %zd in `%" PATH_FMT "'",
    
    589 647
                              memberSize, path);
    
    590 648
                 }
    
    591 649
             }