Home | History | Annotate | Download | only in nanoapp_postprocess
      1 /*
      2  * Copyright (C) 2016 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include <assert.h>
     18 #include <fcntl.h>
     19 #include <gelf.h>
     20 #include <libelf.h>
     21 #include <sys/types.h>
     22 #include <stdbool.h>
     23 #include <unistd.h>
     24 #include <stdlib.h>
     25 #include <string.h>
     26 #include <stdint.h>
     27 #include <stdio.h>
     28 #include <stddef.h>
     29 #include <errno.h>
     30 
     31 #include <nanohub/nanohub.h>
     32 #include <nanohub/nanoapp.h>
     33 #include <nanohub/appRelocFormat.h>
     34 
     35 //This code assumes it is run on a LE CPU with unaligned access abilities. Sorry.
     36 
     37 #define FLASH_BASE  0x10000000
     38 #define RAM_BASE    0x80000000
     39 
     40 #define FLASH_SIZE  0x10000000  //256MB ought to be enough for everyone
     41 #define RAM_SIZE    0x10000000  //256MB ought to be enough for everyone
     42 
     43 //caution: double evaluation
     44 #define IS_IN_RANGE_E(_val, _rstart, _rend) (((_val) >= (_rstart)) && ((_val) < (_rend)))
     45 #define IS_IN_RANGE(_val, _rstart, _rsz)    IS_IN_RANGE_E((_val), (_rstart), ((_rstart) + (_rsz)))
     46 #define IS_IN_RAM(_val)              IS_IN_RANGE(_val, RAM_BASE, RAM_SIZE)
     47 #define IS_IN_FLASH(_val)            IS_IN_RANGE(_val, FLASH_BASE, FLASH_SIZE)
     48 
     49 
     50 #define NANO_RELOC_TYPE_RAM    0
     51 #define NANO_RELOC_TYPE_FLASH  1
     52 #define NANO_RELOC_LAST        2 //must be <= (RELOC_TYPE_MASK >> RELOC_TYPE_SHIFT)
     53 
     54 struct RelocEntry {
     55     uint32_t where;
     56     uint32_t info;  //bottom 8 bits is type, top 24 is sym idx
     57 };
     58 
     59 #define RELOC_TYPE_ABS_S    2
     60 #define RELOC_TYPE_ABS_D    21
     61 #define RELOC_TYPE_SECT     23
     62 
     63 
     64 struct SymtabEntry {
     65     uint32_t a;
     66     uint32_t addr;
     67     uint32_t b, c;
     68 };
     69 
     70 struct NanoRelocEntry {
     71     uint32_t ofstInRam;
     72     uint8_t type;
     73 };
     74 
     75 #ifndef ARRAY_SIZE
     76 #define ARRAY_SIZE(ary) (sizeof(ary) / sizeof((ary)[0]))
     77 #endif
     78 
     79 #define DBG(fmt, ...) printf(fmt "\n", ##__VA_ARGS__)
     80 #define ERR(fmt, ...) fprintf(stderr, fmt "\n", ##__VA_ARGS__)
     81 
     82 // Prints the given message followed by the most recent libelf error
     83 #define ELF_ERR(fmt, ...) ERR(fmt ": %s\n", ##__VA_ARGS__, elf_errmsg(-1))
     84 
     85 struct ElfAppSection {
     86     void  *data;
     87     size_t size;
     88 };
     89 
     90 struct ElfNanoApp {
     91     struct ElfAppSection flash;
     92     struct ElfAppSection data;
     93     struct ElfAppSection relocs;
     94     struct ElfAppSection symtab;
     95 
     96     // Not parsed from file, but constructed via genElfNanoRelocs
     97     struct ElfAppSection packedNanoRelocs;
     98 };
     99 
    100 static void fatalUsage(const char *name, const char *msg, const char *arg)
    101 {
    102     if (msg && arg)
    103         fprintf(stderr, "Error: %s: %s\n\n", msg, arg);
    104     else if (msg)
    105         fprintf(stderr, "Error: %s\n\n", msg);
    106 
    107     fprintf(stderr, "USAGE: %s [-v] [-k <key id>] [-a <app id>] [-r] [-n <layout name>] [-i <layout id>] <input file> [<output file>]\n"
    108                     "       -v               : be verbose\n"
    109                     "       -n <layout name> : app, os, key\n"
    110                     "       -i <layout id>   : 1 (app), 2 (key), 3 (os)\n"
    111                     "       -f <layout flags>: 16-bit hex value, stored as layout-specific flags\n"
    112                     "       -a <app ID>      : 64-bit hex number != 0\n"
    113                     "       -k <key ID>      : 64-bit hex number != 0\n"
    114                     "       -r               : bare (no AOSP header); used only for inner OS image generation\n"
    115                     "       -s               : treat input as statically linked ELF (app layout only)\n"
    116                     "       layout ID and layout name control the same parameter, so only one of them needs to be used\n"
    117                     , name);
    118     exit(1);
    119 }
    120 
    121 static uint8_t *packNanoRelocs(struct NanoRelocEntry *nanoRelocs, uint32_t outNumRelocs, uint32_t *finalPackedNanoRelocSz, bool verbose)
    122 {
    123     uint32_t i, j, k;
    124     uint8_t *packedNanoRelocs;
    125     uint32_t packedNanoRelocSz;
    126     uint32_t lastOutType = 0, origin = 0;
    127 
    128     //sort by type and then offset
    129     for (i = 0; i < outNumRelocs; i++) {
    130         struct NanoRelocEntry t;
    131 
    132         for (k = i, j = k + 1; j < outNumRelocs; j++) {
    133             if (nanoRelocs[j].type > nanoRelocs[k].type)
    134                 continue;
    135             if ((nanoRelocs[j].type < nanoRelocs[k].type) || (nanoRelocs[j].ofstInRam < nanoRelocs[k].ofstInRam))
    136                 k = j;
    137         }
    138         memcpy(&t, nanoRelocs + i, sizeof(struct NanoRelocEntry));
    139         memcpy(nanoRelocs + i, nanoRelocs + k, sizeof(struct NanoRelocEntry));
    140         memcpy(nanoRelocs + k, &t, sizeof(struct NanoRelocEntry));
    141 
    142         if (verbose)
    143             fprintf(stderr, "SortedReloc[%3" PRIu32 "] = {0x%08" PRIX32 ",0x%02" PRIX8 "}\n", i, nanoRelocs[i].ofstInRam, nanoRelocs[i].type);
    144     }
    145 
    146     //produce output nanorelocs in packed format
    147     packedNanoRelocs = malloc(outNumRelocs * 6); //definitely big enough
    148     packedNanoRelocSz = 0;
    149     for (i = 0; i < outNumRelocs; i++) {
    150         uint32_t displacement;
    151 
    152         if (lastOutType != nanoRelocs[i].type) {  //output type if ti changed
    153             if (nanoRelocs[i].type - lastOutType == 1) {
    154                 packedNanoRelocs[packedNanoRelocSz++] = TOKEN_RELOC_TYPE_NEXT;
    155                 if (verbose)
    156                     fprintf(stderr, "Out: RelocTC (1) // to 0x%02" PRIX8 "\n", nanoRelocs[i].type);
    157             }
    158             else {
    159                 packedNanoRelocs[packedNanoRelocSz++] = TOKEN_RELOC_TYPE_CHG;
    160                 packedNanoRelocs[packedNanoRelocSz++] = nanoRelocs[i].type - lastOutType - 1;
    161                 if (verbose)
    162                     fprintf(stderr, "Out: RelocTC (0x%02" PRIX8 ")  // to 0x%02" PRIX8 "\n", (uint8_t)(nanoRelocs[i].type - lastOutType - 1), nanoRelocs[i].type);
    163             }
    164             lastOutType = nanoRelocs[i].type;
    165             origin = 0;
    166         }
    167         displacement = nanoRelocs[i].ofstInRam - origin;
    168         origin = nanoRelocs[i].ofstInRam + 4;
    169         if (displacement & 3) {
    170             fprintf(stderr, "Unaligned relocs are not possible!\n");
    171             exit(-5);
    172         }
    173         displacement /= 4;
    174 
    175         //might be start of a run. look into that
    176         if (!displacement) {
    177             for (j = 1; j + i < outNumRelocs && j < MAX_RUN_LEN && nanoRelocs[j + i].type == lastOutType && nanoRelocs[j + i].ofstInRam - nanoRelocs[j + i - 1].ofstInRam == 4; j++);
    178             if (j >= MIN_RUN_LEN) {
    179                 if (verbose)
    180                     fprintf(stderr, "Out: Reloc0  x%" PRIX32 "\n", j);
    181                 packedNanoRelocs[packedNanoRelocSz++] = TOKEN_CONSECUTIVE;
    182                 packedNanoRelocs[packedNanoRelocSz++] = j - MIN_RUN_LEN;
    183                 origin = nanoRelocs[j + i - 1].ofstInRam + 4;  //reset origin to last one
    184                 i += j - 1;  //loop will increment anyways, hence +1
    185                 continue;
    186             }
    187         }
    188 
    189         //produce output
    190         if (displacement <= MAX_8_BIT_NUM) {
    191             if (verbose)
    192                 fprintf(stderr, "Out: Reloc8  0x%02" PRIX32 "\n", displacement);
    193             packedNanoRelocs[packedNanoRelocSz++] = displacement;
    194         }
    195         else if (displacement <= MAX_16_BIT_NUM) {
    196             if (verbose)
    197                 fprintf(stderr, "Out: Reloc16 0x%06" PRIX32 "\n", displacement);
    198                         displacement -= MAX_8_BIT_NUM;
    199             packedNanoRelocs[packedNanoRelocSz++] = TOKEN_16BIT_OFST;
    200             packedNanoRelocs[packedNanoRelocSz++] = displacement;
    201             packedNanoRelocs[packedNanoRelocSz++] = displacement >> 8;
    202         }
    203         else if (displacement <= MAX_24_BIT_NUM) {
    204             if (verbose)
    205                 fprintf(stderr, "Out: Reloc24 0x%08" PRIX32 "\n", displacement);
    206                         displacement -= MAX_16_BIT_NUM;
    207             packedNanoRelocs[packedNanoRelocSz++] = TOKEN_24BIT_OFST;
    208             packedNanoRelocs[packedNanoRelocSz++] = displacement;
    209             packedNanoRelocs[packedNanoRelocSz++] = displacement >> 8;
    210             packedNanoRelocs[packedNanoRelocSz++] = displacement >> 16;
    211         }
    212         else  {
    213             if (verbose)
    214                 fprintf(stderr, "Out: Reloc32 0x%08" PRIX32 "\n", displacement);
    215             packedNanoRelocs[packedNanoRelocSz++] = TOKEN_32BIT_OFST;
    216             packedNanoRelocs[packedNanoRelocSz++] = displacement;
    217             packedNanoRelocs[packedNanoRelocSz++] = displacement >> 8;
    218             packedNanoRelocs[packedNanoRelocSz++] = displacement >> 16;
    219             packedNanoRelocs[packedNanoRelocSz++] = displacement >> 24;
    220         }
    221     }
    222 
    223     *finalPackedNanoRelocSz = packedNanoRelocSz;
    224     return packedNanoRelocs;
    225 }
    226 
    227 static int finalizeAndWrite(uint8_t *buf, uint32_t bufUsed, uint32_t bufSz, FILE *out, uint32_t layoutFlags, uint64_t appId)
    228 {
    229     int ret;
    230     struct AppInfo app;
    231     struct SectInfo *sect;
    232     struct BinHdr *bin = (struct BinHdr *) buf;
    233     struct ImageHeader outHeader = {
    234         .aosp = (struct nano_app_binary_t) {
    235             .header_version = 1,
    236             .magic = NANOAPP_AOSP_MAGIC,
    237             .app_id = appId,
    238             .app_version = bin->hdr.appVer,
    239             .flags       = 0, // encrypted (1), signed (2) (will be set by other tools)
    240         },
    241         .layout = (struct ImageLayout) {
    242             .magic = GOOGLE_LAYOUT_MAGIC,
    243             .version = 1,
    244             .payload = LAYOUT_APP,
    245             .flags = layoutFlags,
    246         },
    247     };
    248     uint32_t dataOffset = sizeof(outHeader) + sizeof(app);
    249     uint32_t hdrDiff = dataOffset - sizeof(*bin);
    250     app.sect = bin->sect;
    251     app.vec  = bin->vec;
    252 
    253     assertMem(bufUsed + hdrDiff, bufSz);
    254 
    255     memmove(buf + dataOffset, buf + sizeof(*bin), bufUsed - sizeof(*bin));
    256     bufUsed += hdrDiff;
    257     memcpy(buf, &outHeader, sizeof(outHeader));
    258     memcpy(buf + sizeof(outHeader), &app, sizeof(app));
    259     sect = &app.sect;
    260 
    261     //if we have any bytes to output, show stats
    262     if (bufUsed) {
    263         uint32_t codeAndRoDataSz = sect->data_data;
    264         uint32_t relocsSz = sect->rel_end - sect->rel_start;
    265         uint32_t gotSz = sect->got_end - sect->data_start;
    266         uint32_t bssSz = sect->bss_end - sect->bss_start;
    267 
    268         fprintf(stderr,"Final binary size %" PRIu32 " bytes\n", bufUsed);
    269         fprintf(stderr, "\n");
    270         fprintf(stderr, "       FW header size (flash):      %6zu bytes\n", FLASH_RELOC_OFFSET);
    271         fprintf(stderr, "       Code + RO data (flash):      %6" PRIu32 " bytes\n", codeAndRoDataSz);
    272         fprintf(stderr, "       Relocs (flash):              %6" PRIu32 " bytes\n", relocsSz);
    273         fprintf(stderr, "       GOT + RW data (flash & RAM): %6" PRIu32 " bytes\n", gotSz);
    274         fprintf(stderr, "       BSS (RAM):                   %6" PRIu32 " bytes\n", bssSz);
    275         fprintf(stderr, "\n");
    276         fprintf(stderr,"Runtime flash use: %" PRIu32 " bytes\n", (uint32_t)(codeAndRoDataSz + relocsSz + gotSz + FLASH_RELOC_OFFSET));
    277         fprintf(stderr,"Runtime RAM use: %" PRIu32 " bytes\n", gotSz + bssSz);
    278     }
    279 
    280     ret = fwrite(buf, bufUsed, 1, out) == 1 ? 0 : 2;
    281     if (ret)
    282         fprintf(stderr, "Failed to write output file: %s\n", strerror(errno));
    283 
    284     return ret;
    285 }
    286 
    287 static int handleApp(uint8_t **pbuf, uint32_t bufUsed, FILE *out, uint32_t layoutFlags, uint64_t appId, bool verbose)
    288 {
    289     uint32_t i, numRelocs, numSyms, outNumRelocs = 0, packedNanoRelocSz;
    290     struct NanoRelocEntry *nanoRelocs = NULL;
    291     struct RelocEntry *relocs;
    292     struct SymtabEntry *syms;
    293     uint8_t *packedNanoRelocs;
    294     uint32_t t;
    295     struct BinHdr *bin;
    296     int ret = -1;
    297     struct SectInfo *sect;
    298     uint8_t *buf = *pbuf;
    299     uint32_t bufSz = bufUsed * 3 /2;
    300 
    301     //make buffer 50% bigger than bufUsed in case relocs grow out of hand
    302     buf = reallocOrDie(buf, bufSz);
    303     *pbuf = buf;
    304 
    305     //sanity checks
    306     bin = (struct BinHdr*)buf;
    307     if (bufUsed < sizeof(*bin)) {
    308         fprintf(stderr, "File size too small\n");
    309         goto out;
    310     }
    311 
    312     if (bin->hdr.magic != NANOAPP_FW_MAGIC) {
    313         fprintf(stderr, "Magic value is wrong: found %08" PRIX32
    314                         "; expected %08" PRIX32 "\n",
    315                         bin->hdr.magic, NANOAPP_FW_MAGIC);
    316         goto out;
    317     }
    318 
    319     sect = &bin->sect;
    320 
    321     //do some math
    322     relocs = (struct RelocEntry*)(buf + sect->rel_start - FLASH_BASE);
    323     syms = (struct SymtabEntry*)(buf + sect->rel_end - FLASH_BASE);
    324     numRelocs = (sect->rel_end - sect->rel_start) / sizeof(struct RelocEntry);
    325     numSyms = (bufUsed + FLASH_BASE - sect->rel_end) / sizeof(struct SymtabEntry);
    326 
    327     //sanity
    328     if (numRelocs * sizeof(struct RelocEntry) + sect->rel_start != sect->rel_end) {
    329         fprintf(stderr, "Relocs of nonstandard size\n");
    330         goto out;
    331     }
    332     if (numSyms * sizeof(struct SymtabEntry) + sect->rel_end != bufUsed + FLASH_BASE) {
    333         fprintf(stderr, "Syms of nonstandard size\n");
    334         goto out;
    335     }
    336 
    337     //show some info
    338     fprintf(stderr, "\nRead %" PRIu32 " bytes of binary.\n", bufUsed);
    339 
    340     if (verbose)
    341         fprintf(stderr, "Found %" PRIu32 " relocs and a %" PRIu32 "-entry symbol table\n", numRelocs, numSyms);
    342 
    343     //handle relocs
    344     nanoRelocs = malloc(sizeof(struct NanoRelocEntry[numRelocs]));
    345     if (!nanoRelocs) {
    346         fprintf(stderr, "Failed to allocate a nano-reloc table\n");
    347         goto out;
    348     }
    349 
    350     for (i = 0; i < numRelocs; i++) {
    351         uint32_t relocType = relocs[i].info & 0xff;
    352         uint32_t whichSym = relocs[i].info >> 8;
    353         uint32_t *valThereP;
    354 
    355         if (whichSym >= numSyms) {
    356             fprintf(stderr, "Reloc %" PRIu32 " references a nonexistent symbol!\n"
    357                             "INFO:\n"
    358                             "        Where: 0x%08" PRIX32 "\n"
    359                             "        type: %" PRIu32 "\n"
    360                             "        sym: %" PRIu32 "\n",
    361                 i, relocs[i].where, relocs[i].info & 0xff, whichSym);
    362             goto out;
    363         }
    364 
    365         if (verbose) {
    366             const char *seg;
    367 
    368             fprintf(stderr, "Reloc[%3" PRIu32 "]:\n {@0x%08" PRIX32 ", type %3" PRIu32 ", -> sym[%3" PRIu32 "]: {@0x%08" PRIX32 "}, ",
    369                 i, relocs[i].where, relocs[i].info & 0xff, whichSym, syms[whichSym].addr);
    370 
    371             if (IS_IN_RANGE_E(relocs[i].where, sect->bss_start, sect->bss_end))
    372                 seg = ".bss";
    373             else if (IS_IN_RANGE_E(relocs[i].where, sect->data_start, sect->data_end))
    374                 seg = ".data";
    375             else if (IS_IN_RANGE_E(relocs[i].where, sect->got_start, sect->got_end))
    376                 seg = ".got";
    377             else if (IS_IN_RANGE_E(relocs[i].where, FLASH_BASE, FLASH_BASE + sizeof(struct BinHdr)))
    378                 seg = "APPHDR";
    379             else
    380                 seg = "???";
    381 
    382             fprintf(stderr, "in   %s}\n", seg);
    383         }
    384         /* handle relocs inside the header */
    385         if (IS_IN_FLASH(relocs[i].where) && relocs[i].where - FLASH_BASE < sizeof(struct BinHdr) && relocType == RELOC_TYPE_SECT) {
    386             /* relocs in header are special - runtime corrects for them */
    387             if (syms[whichSym].addr) {
    388                 fprintf(stderr, "Weird in-header sect reloc %" PRIu32 " to symbol %" PRIu32 " with nonzero addr 0x%08" PRIX32 "\n",
    389                         i, whichSym, syms[whichSym].addr);
    390                 goto out;
    391             }
    392 
    393             valThereP = (uint32_t*)(buf + relocs[i].where - FLASH_BASE);
    394             if (!IS_IN_FLASH(*valThereP)) {
    395                 fprintf(stderr, "In-header reloc %" PRIu32 " of location 0x%08" PRIX32 " is outside of FLASH!\n"
    396                                 "INFO:\n"
    397                                 "        type: %" PRIu32 "\n"
    398                                 "        sym: %" PRIu32 "\n"
    399                                 "        Sym Addr: 0x%08" PRIX32 "\n",
    400                                 i, relocs[i].where, relocType, whichSym, syms[whichSym].addr);
    401                 goto out;
    402             }
    403 
    404             // binary header generated by objcopy, .napp header and final FW header in flash are of different size.
    405             // we subtract binary header offset here, so all the entry points are relative to beginning of "sect".
    406             // FW will use &sect as a base to call these vectors; no more problems with different header sizes;
    407             // Assumption: offsets between sect & vec, vec & code are the same in all images (or, in a simpler words, { sect, vec, code }
    408             // must go together). this is enforced by linker script, and maintained by all tools and FW download code in the OS.
    409             *valThereP -= FLASH_BASE + BINARY_RELOC_OFFSET;
    410 
    411             if (verbose)
    412                 fprintf(stderr, "  -> Nano reloc skipped for in-header reloc\n");
    413 
    414             continue; /* do not produce an output reloc */
    415         }
    416 
    417         if (!IS_IN_RAM(relocs[i].where)) {
    418             fprintf(stderr, "In-header reloc %" PRIu32 " of location 0x%08" PRIX32 " is outside of RAM!\n"
    419                             "INFO:\n"
    420                             "        type: %" PRIu32 "\n"
    421                             "        sym: %" PRIu32 "\n"
    422                             "        Sym Addr: 0x%08" PRIX32 "\n",
    423                             i, relocs[i].where, relocType, whichSym, syms[whichSym].addr);
    424             goto out;
    425         }
    426 
    427         valThereP = (uint32_t*)(buf + relocs[i].where + sect->data_data - RAM_BASE - FLASH_BASE);
    428 
    429         nanoRelocs[outNumRelocs].ofstInRam = relocs[i].where - RAM_BASE;
    430 
    431         switch (relocType) {
    432             case RELOC_TYPE_ABS_S:
    433             case RELOC_TYPE_ABS_D:
    434                 t = *valThereP;
    435 
    436                 (*valThereP) += syms[whichSym].addr;
    437 
    438                 if (IS_IN_FLASH(syms[whichSym].addr)) {
    439                     (*valThereP) -= FLASH_BASE + BINARY_RELOC_OFFSET;
    440                     nanoRelocs[outNumRelocs].type = NANO_RELOC_TYPE_FLASH;
    441                 }
    442                 else if (IS_IN_RAM(syms[whichSym].addr)) {
    443                     (*valThereP) -= RAM_BASE;
    444                     nanoRelocs[outNumRelocs].type = NANO_RELOC_TYPE_RAM;
    445                 }
    446                 else {
    447                     fprintf(stderr, "Weird reloc %" PRIu32 " to symbol %" PRIu32 " in unknown memory space (addr 0x%08" PRIX32 ")\n",
    448                             i, whichSym, syms[whichSym].addr);
    449                     goto out;
    450                 }
    451                 if (verbose)
    452                     fprintf(stderr, "  -> Abs reference fixed up 0x%08" PRIX32 " -> 0x%08" PRIX32 "\n", t, *valThereP);
    453                 break;
    454 
    455             case RELOC_TYPE_SECT:
    456                 if (syms[whichSym].addr) {
    457                     fprintf(stderr, "Weird sect reloc %" PRIu32 " to symbol %" PRIu32 " with nonzero addr 0x%08" PRIX32 "\n",
    458                             i, whichSym, syms[whichSym].addr);
    459                     goto out;
    460                 }
    461 
    462                 t = *valThereP;
    463 
    464                 if (IS_IN_FLASH(*valThereP)) {
    465                     nanoRelocs[outNumRelocs].type = NANO_RELOC_TYPE_FLASH;
    466                     *valThereP -= FLASH_BASE + BINARY_RELOC_OFFSET;
    467                 }
    468                 else if (IS_IN_RAM(*valThereP)) {
    469                     nanoRelocs[outNumRelocs].type = NANO_RELOC_TYPE_RAM;
    470                     *valThereP -= RAM_BASE;
    471                 }
    472                 else {
    473                     fprintf(stderr, "Weird sec reloc %" PRIu32 " to symbol %" PRIu32
    474                                     " in unknown memory space (addr 0x%08" PRIX32 ")\n",
    475                                     i, whichSym, *valThereP);
    476                     goto out;
    477                 }
    478                 if (verbose)
    479                     fprintf(stderr, "  -> Sect reference fixed up 0x%08" PRIX32 " -> 0x%08" PRIX32 "\n", t, *valThereP);
    480                 break;
    481 
    482             default:
    483                 fprintf(stderr, "Weird reloc %" PRIX32 " type %" PRIX32 " to symbol %" PRIX32 "\n", i, relocType, whichSym);
    484                 goto out;
    485         }
    486 
    487         if (verbose)
    488             fprintf(stderr, "  -> Nano reloc calculated as 0x%08" PRIX32 ",0x%02" PRIX8 "\n", nanoRelocs[i].ofstInRam, nanoRelocs[i].type);
    489         outNumRelocs++;
    490     }
    491 
    492     packedNanoRelocs = packNanoRelocs(nanoRelocs, outNumRelocs, &packedNanoRelocSz, verbose);
    493 
    494     //overwrite original relocs and symtab with nanorelocs and adjust sizes
    495     memcpy(relocs, packedNanoRelocs, packedNanoRelocSz);
    496     bufUsed -= sizeof(struct RelocEntry[numRelocs]);
    497     bufUsed -= sizeof(struct SymtabEntry[numSyms]);
    498     bufUsed += packedNanoRelocSz;
    499     assertMem(bufUsed, bufSz);
    500     sect->rel_end = sect->rel_start + packedNanoRelocSz;
    501 
    502     //sanity
    503     if (sect->rel_end - FLASH_BASE != bufUsed) {
    504         fprintf(stderr, "Relocs end and file end not coincident\n");
    505         goto out;
    506     }
    507 
    508     //adjust headers for easy access (RAM)
    509     if (!IS_IN_RAM(sect->data_start) || !IS_IN_RAM(sect->data_end) || !IS_IN_RAM(sect->bss_start) ||
    510         !IS_IN_RAM(sect->bss_end) || !IS_IN_RAM(sect->got_start) || !IS_IN_RAM(sect->got_end)) {
    511         fprintf(stderr, "data, bss, or got not in ram\n");
    512         goto out;
    513     }
    514     sect->data_start -= RAM_BASE;
    515     sect->data_end -= RAM_BASE;
    516     sect->bss_start -= RAM_BASE;
    517     sect->bss_end -= RAM_BASE;
    518     sect->got_start -= RAM_BASE;
    519     sect->got_end -= RAM_BASE;
    520 
    521     //adjust headers for easy access (FLASH)
    522     if (!IS_IN_FLASH(sect->data_data) || !IS_IN_FLASH(sect->rel_start) || !IS_IN_FLASH(sect->rel_end)) {
    523         fprintf(stderr, "data.data, or rel not in flash\n");
    524         goto out;
    525     }
    526     sect->data_data -= FLASH_BASE + BINARY_RELOC_OFFSET;
    527     sect->rel_start -= FLASH_BASE + BINARY_RELOC_OFFSET;
    528     sect->rel_end -= FLASH_BASE + BINARY_RELOC_OFFSET;
    529 
    530     ret = finalizeAndWrite(buf, bufUsed, bufSz, out, layoutFlags, appId);
    531 out:
    532     free(nanoRelocs);
    533     return ret;
    534 }
    535 
    536 static void elfExtractSectionPointer(const Elf_Data *data, const char *name, struct ElfNanoApp *app)
    537 {
    538     // Maps section names to their byte offset in struct ElfNanoApp. Note that
    539     // this assumes that the linker script puts text/code in the .flash section,
    540     // RW data in .data, that relocs for .data are included in .rel.data, and
    541     // the symbol table is emitted in .symtab
    542     const struct SectionMap {
    543         const char *name;
    544         size_t offset;
    545     } sectionMap[] = {
    546         {
    547             .name = ".flash",
    548             .offset = offsetof(struct ElfNanoApp, flash),
    549         },
    550         {
    551             .name = ".data",
    552             .offset = offsetof(struct ElfNanoApp, data),
    553         },
    554         {
    555             .name = ".rel.data",
    556             .offset = offsetof(struct ElfNanoApp, relocs),
    557         },
    558         {
    559             .name = ".symtab",
    560             .offset = offsetof(struct ElfNanoApp, symtab),
    561         },
    562     };
    563     struct ElfAppSection *appSection;
    564     uint8_t *appBytes = (uint8_t *) app;
    565 
    566     for (size_t i = 0; i < ARRAY_SIZE(sectionMap); i++) {
    567         if (strcmp(name, sectionMap[i].name) != 0) {
    568             continue;
    569         }
    570         appSection = (struct ElfAppSection *) &appBytes[sectionMap[i].offset];
    571 
    572         appSection->data = data->d_buf;
    573         appSection->size = data->d_size;
    574 
    575         DBG("Found section %s with size %zu", name, appSection->size);
    576         break;
    577     }
    578 }
    579 
    580 // Populates a struct ElfNanoApp with data parsed from the ELF
    581 static bool elfParse(Elf *elf, struct ElfNanoApp *app)
    582 {
    583     size_t shdrstrndx;
    584     Elf_Scn *scn = NULL;
    585     GElf_Shdr shdr;
    586     char *sectionName;
    587     Elf_Data *elf_data;
    588 
    589     memset(app, 0, sizeof(*app));
    590     if (elf_getshdrstrndx(elf, &shdrstrndx) != 0) {
    591         ELF_ERR("Couldn't get section name string table index");
    592         return false;
    593     }
    594 
    595     while ((scn = elf_nextscn(elf, scn)) != NULL) {
    596         if (gelf_getshdr(scn, &shdr) != &shdr) {
    597             ELF_ERR("Error getting section header");
    598             return false;
    599         }
    600         sectionName = elf_strptr(elf, shdrstrndx, shdr.sh_name);
    601 
    602         elf_data = elf_getdata(scn, NULL);
    603         if (!elf_data) {
    604             ELF_ERR("Error getting data for section %s", sectionName);
    605             return false;
    606         }
    607 
    608         elfExtractSectionPointer(elf_data, sectionName, app);
    609     }
    610 
    611     return true;
    612 }
    613 
    614 static bool loadNanoappElfFile(const char *fileName, struct ElfNanoApp *app)
    615 {
    616     int fd;
    617     Elf *elf;
    618 
    619     if (elf_version(EV_CURRENT) == EV_NONE) {
    620         ELF_ERR("Failed to initialize ELF library");
    621         return false;
    622     }
    623 
    624     fd = open(fileName, O_RDONLY, 0);
    625     if (fd < 0) {
    626         ERR("Failed to open file %s for reading: %s", fileName, strerror(errno));
    627         return false;
    628     }
    629 
    630     elf = elf_begin(fd, ELF_C_READ, NULL);
    631     if (elf == NULL) {
    632         ELF_ERR("Failed to open ELF");
    633         return false;
    634     }
    635 
    636     if (!elfParse(elf, app)) {
    637         ERR("Failed to parse ELF file");
    638         return false;
    639     }
    640 
    641     return true;
    642 }
    643 
    644 // Subtracts the fixed memory region offset from an absolute address and returns
    645 // the associated NANO_RELOC_* value, or NANO_RELOC_LAST if the address is not
    646 // in the expected range.
    647 // Not strictly tied to ELF usage, but handled slightly differently.
    648 static uint8_t fixupAddrElf(uint32_t *addr)
    649 {
    650     uint8_t type;
    651 
    652     // TODO: this assumes that the host running this tool has the same
    653     // endianness as the image file/target processor
    654     if (IS_IN_FLASH(*addr)) {
    655         DBG("Fixup addr 0x%08" PRIX32 " (flash) --> 0x%08" PRIX32, *addr,
    656             (uint32_t) (*addr - (FLASH_BASE + BINARY_RELOC_OFFSET)));
    657         *addr -= FLASH_BASE + BINARY_RELOC_OFFSET;
    658         type = NANO_RELOC_TYPE_FLASH;
    659     } else if (IS_IN_RAM(*addr)) {
    660         DBG("Fixup addr 0x%08" PRIX32 " (ram)   --> 0x%08" PRIX32, *addr,
    661             *addr - RAM_BASE);
    662         *addr -= RAM_BASE;
    663         type = NANO_RELOC_TYPE_RAM;
    664     } else {
    665         DBG("Error: invalid address 0x%08" PRIX32, *addr);
    666         type = NANO_RELOC_LAST;
    667     }
    668 
    669     return type;
    670 }
    671 
    672 // Fixup addresses in the header to be relative. Not strictly tied to the ELF
    673 // format, but used only in that program flow in the current implementation.
    674 static bool fixupHeaderElf(const struct ElfNanoApp *app)
    675 {
    676     struct BinHdr *hdr = (struct BinHdr *) app->flash.data;
    677 
    678     DBG("Appyling fixups to header");
    679     if (fixupAddrElf(&hdr->sect.data_start) != NANO_RELOC_TYPE_RAM ||
    680         fixupAddrElf(&hdr->sect.data_end)   != NANO_RELOC_TYPE_RAM ||
    681         fixupAddrElf(&hdr->sect.bss_start)  != NANO_RELOC_TYPE_RAM ||
    682         fixupAddrElf(&hdr->sect.bss_end)    != NANO_RELOC_TYPE_RAM ||
    683         fixupAddrElf(&hdr->sect.got_start)  != NANO_RELOC_TYPE_RAM ||
    684         fixupAddrElf(&hdr->sect.got_end)    != NANO_RELOC_TYPE_RAM) {
    685         ERR(".data, .bss, or .got not in RAM address space!");
    686         return false;
    687     }
    688 
    689     if (fixupAddrElf(&hdr->sect.rel_start) != NANO_RELOC_TYPE_FLASH ||
    690         fixupAddrElf(&hdr->sect.rel_end)   != NANO_RELOC_TYPE_FLASH ||
    691         fixupAddrElf(&hdr->sect.data_data) != NANO_RELOC_TYPE_FLASH) {
    692         ERR(".data loadaddr, or .relocs not in flash address space!");
    693         return false;
    694     }
    695 
    696     if (fixupAddrElf(&hdr->vec.init)   != NANO_RELOC_TYPE_FLASH ||
    697         fixupAddrElf(&hdr->vec.end)    != NANO_RELOC_TYPE_FLASH ||
    698         fixupAddrElf(&hdr->vec.handle) != NANO_RELOC_TYPE_FLASH) {
    699         ERR("Entry point(s) not in flash address space!");
    700         return false;
    701     }
    702 
    703     return true;
    704 }
    705 
    706 // Fixup addresses in .data, .init_array/.fini_array, and .got, and generates
    707 // packed array of nano reloc entries. The app header must have already been
    708 // fixed up.
    709 static bool genElfNanoRelocs(struct ElfNanoApp *app, bool verbose)
    710 {
    711     const struct BinHdr *hdr = (const struct BinHdr *) app->flash.data;
    712     const struct SectInfo *sect = &hdr->sect;
    713     bool success = false;
    714 
    715     size_t numDataRelocs = app->relocs.size / sizeof(Elf32_Rel);
    716     size_t gotCount = (sect->got_end - sect->got_start) / sizeof(uint32_t);
    717     size_t numInitFuncs  = (sect->bss_start - sect->data_end) / sizeof(uint32_t);
    718 
    719     size_t totalRelocCount = (numDataRelocs + numInitFuncs + gotCount);
    720     struct NanoRelocEntry *nanoRelocs = malloc(
    721         totalRelocCount * sizeof(struct NanoRelocEntry));
    722     if (!nanoRelocs) {
    723         ERR("Couldn't allocate memory for nano relocs! Needed %zu bytes",
    724             totalRelocCount * sizeof(struct NanoRelocEntry));
    725         return false;
    726     }
    727 
    728     uint8_t *data = app->data.data;
    729     const Elf32_Rel *relocs = (const Elf32_Rel *) app->relocs.data;
    730     const Elf32_Sym *syms   = (const Elf32_Sym *) app->symtab.data;
    731     size_t numRelocs = 0;
    732 
    733     DBG("Parsing relocs for .data (%zu):", numDataRelocs);
    734     for (size_t i = 0; i < numDataRelocs; i++) {
    735         uint32_t type = ELF32_R_TYPE(relocs[i].r_info);
    736         uint32_t sym = ELF32_R_SYM(relocs[i].r_info);
    737 
    738         DBG(" [%3zu] 0x%08" PRIx32 " type %2" PRIu32 " symIdx %3" PRIu32
    739             " --> 0x%08" PRIx32, i, relocs[i].r_offset, type, sym,
    740             syms[sym].st_value);
    741         // Note that R_ARM_TARGET1 is used for .init_array/.fini_array support,
    742         // and can be interpreted either as ABS32 or REL32, depending on the
    743         // runtime; we expect it to be ABS32.
    744         if (type == R_ARM_ABS32 || type == R_ARM_TARGET1) {
    745             if (!IS_IN_RAM(relocs[i].r_offset)) {
    746                 ERR("Reloc for .data not in RAM address range!");
    747                 goto out;
    748             }
    749             uint32_t offset = relocs[i].r_offset - RAM_BASE;
    750             uint32_t *addr = (uint32_t *) &data[offset];
    751 
    752             nanoRelocs[numRelocs].type = fixupAddrElf(addr);
    753             nanoRelocs[numRelocs].ofstInRam = offset;
    754             numRelocs++;
    755         } else {
    756             // TODO: Assuming that the ELF only contains absolute addresses in
    757             // the .data section; may need to handle other relocation types in
    758             // the future
    759             ERR("Error: Unexpected reloc type %" PRIu32 " at index %zu",
    760                 type, i);
    761             goto out;
    762         }
    763     }
    764 
    765     DBG("Updating GOT entries (%zu):", gotCount);
    766     for (uint32_t offset = sect->got_start; offset < sect->got_end;
    767             offset += sizeof(uint32_t)) {
    768         uint32_t *addr = (uint32_t *) &data[offset];
    769         // Skip values that are set to 0, these seem to be padding (?)
    770         if (*addr) {
    771             nanoRelocs[numRelocs].type = fixupAddrElf(addr);
    772             nanoRelocs[numRelocs].ofstInRam = offset;
    773             numRelocs++;
    774         }
    775     }
    776 
    777     uint32_t packedNanoRelocSz = 0;
    778     app->packedNanoRelocs.data = packNanoRelocs(
    779         nanoRelocs, numRelocs, &packedNanoRelocSz, verbose);
    780     app->packedNanoRelocs.size = packedNanoRelocSz;
    781     success = true;
    782 out:
    783     free(nanoRelocs);
    784     return success;
    785 }
    786 
    787 static int handleAppStatic(const char *fileName, FILE *out, uint32_t layoutFlags, uint64_t appId, bool verbose)
    788 {
    789     struct ElfNanoApp app;
    790 
    791     if (!loadNanoappElfFile(fileName, &app)
    792             || !fixupHeaderElf(&app)
    793             || !genElfNanoRelocs(&app, verbose)) {
    794         exit(2);
    795     }
    796 
    797     // Construct a single contiguous buffer, with extra room to fit the
    798     // ImageHeader that will be prepended by finalizeAndWrite(). Note that this
    799     // will allocate a bit more space than is needed, because some of the data
    800     // from BinHdr will get discarded.
    801     // TODO: this should be refactored to just write the binary components in
    802     // order rather than allocating a big buffer, and moving data around
    803     size_t bufSize = app.flash.size + app.data.size + app.packedNanoRelocs.size
    804         + sizeof(struct ImageHeader);
    805     uint8_t *buf = malloc(bufSize);
    806     if (!buf) {
    807         ERR("Failed to allocate %zu bytes for final app", bufSize);
    808         exit(2);
    809     }
    810 
    811     size_t offset = 0;
    812     memcpy(buf, app.flash.data, app.flash.size);
    813     offset += app.flash.size;
    814     memcpy(&buf[offset], app.data.data, app.data.size);
    815     offset += app.data.size;
    816     memcpy(&buf[offset], app.packedNanoRelocs.data, app.packedNanoRelocs.size);
    817     offset += app.packedNanoRelocs.size;
    818 
    819     // Update rel_end in the header to reflect the packed reloc size
    820     struct BinHdr *hdr = (struct BinHdr *) buf;
    821     hdr->sect.rel_end = hdr->sect.rel_start + app.packedNanoRelocs.size;
    822 
    823     return finalizeAndWrite(buf, offset, bufSize, out, layoutFlags, appId);
    824     // TODO: should free all memory we allocated... just letting the OS handle
    825     // it for now
    826 }
    827 
    828 static int handleKey(uint8_t **pbuf, uint32_t bufUsed, FILE *out, uint32_t layoutFlags, uint64_t appId, uint64_t keyId)
    829 {
    830     uint8_t *buf = *pbuf;
    831     struct KeyInfo ki = { .data = keyId };
    832     bool good = true;
    833 
    834     struct ImageHeader outHeader = {
    835         .aosp = (struct nano_app_binary_t) {
    836             .header_version = 1,
    837             .magic = NANOAPP_AOSP_MAGIC,
    838             .app_id = appId,
    839         },
    840         .layout = (struct ImageLayout) {
    841             .magic = GOOGLE_LAYOUT_MAGIC,
    842             .version = 1,
    843             .payload = LAYOUT_KEY,
    844             .flags = layoutFlags,
    845         },
    846     };
    847 
    848     good = good && fwrite(&outHeader, sizeof(outHeader), 1, out) == 1;
    849     good = good && fwrite(&ki, sizeof(ki), 1, out) ==  1;
    850     good = good && fwrite(buf, bufUsed, 1, out) == 1;
    851 
    852     return good ? 0 : 2;
    853 }
    854 
    855 static int handleOs(uint8_t **pbuf, uint32_t bufUsed, FILE *out, uint32_t layoutFlags, bool bare)
    856 {
    857     uint8_t *buf = *pbuf;
    858     bool good;
    859 
    860     struct OsUpdateHdr os = {
    861         .magic = OS_UPDT_MAGIC,
    862         .marker = OS_UPDT_MARKER_INPROGRESS,
    863         .size = bufUsed
    864     };
    865 
    866     struct ImageHeader outHeader = {
    867         .aosp = (struct nano_app_binary_t) {
    868             .header_version = 1,
    869             .magic = NANOAPP_AOSP_MAGIC,
    870         },
    871         .layout = (struct ImageLayout) {
    872             .magic = GOOGLE_LAYOUT_MAGIC,
    873             .version = 1,
    874             .payload = LAYOUT_OS,
    875             .flags = layoutFlags,
    876         },
    877     };
    878 
    879     if (!bare)
    880         good = fwrite(&outHeader, sizeof(outHeader), 1, out) == 1;
    881     else
    882         good = fwrite(&os, sizeof(os), 1, out) == 1;
    883     good = good && fwrite(buf, bufUsed, 1, out) == 1;
    884 
    885     return good ? 0 : 2;
    886 }
    887 
    888 int main(int argc, char **argv)
    889 {
    890     uint32_t bufUsed = 0;
    891     bool verbose = false;
    892     uint8_t *buf = NULL;
    893     uint64_t appId = 0;
    894     uint64_t keyId = 0;
    895     uint32_t layoutId = 0;
    896     uint32_t layoutFlags = 0;
    897     int ret = -1;
    898     uint32_t *u32Arg = NULL;
    899     uint64_t *u64Arg = NULL;
    900     const char **strArg = NULL;
    901     const char *appName = argv[0];
    902     int posArgCnt = 0;
    903     const char *posArg[2] = { NULL };
    904     FILE *out = NULL;
    905     const char *layoutName = "app";
    906     const char *prev = NULL;
    907     bool bareData = false;
    908     bool staticElf = false;
    909 
    910     for (int i = 1; i < argc; i++) {
    911         char *end = NULL;
    912         if (argv[i][0] == '-') {
    913             prev = argv[i];
    914             if (!strcmp(argv[i], "-v"))
    915                 verbose = true;
    916             else if (!strcmp(argv[i], "-r"))
    917                 bareData = true;
    918             else if (!strcmp(argv[i], "-s"))
    919                 staticElf = true;
    920             else if (!strcmp(argv[i], "-a"))
    921                 u64Arg = &appId;
    922             else if (!strcmp(argv[i], "-k"))
    923                 u64Arg = &keyId;
    924             else if (!strcmp(argv[i], "-n"))
    925                 strArg = &layoutName;
    926             else if (!strcmp(argv[i], "-i"))
    927                 u32Arg = &layoutId;
    928             else if (!strcmp(argv[i], "-f"))
    929                 u32Arg = &layoutFlags;
    930             else
    931                 fatalUsage(appName, "unknown argument", argv[i]);
    932         } else {
    933             if (u64Arg) {
    934                 uint64_t tmp = strtoull(argv[i], &end, 16);
    935                 if (*end == '\0')
    936                     *u64Arg = tmp;
    937                 u64Arg = NULL;
    938             } else if (u32Arg) {
    939                 uint32_t tmp = strtoul(argv[i], &end, 16);
    940                 if (*end == '\0')
    941                     *u32Arg = tmp;
    942                 u32Arg = NULL;
    943             } else if (strArg) {
    944                     *strArg = argv[i];
    945                 strArg = NULL;
    946             } else {
    947                 if (posArgCnt < 2)
    948                     posArg[posArgCnt++] = argv[i];
    949                 else
    950                     fatalUsage(appName, "too many positional arguments", argv[i]);
    951             }
    952             prev = NULL;
    953         }
    954     }
    955     if (prev)
    956         fatalUsage(appName, "missing argument after", prev);
    957 
    958     if (!posArgCnt)
    959         fatalUsage(appName, "missing input file name", NULL);
    960 
    961     if (!layoutId) {
    962         if (strcmp(layoutName, "app") == 0)
    963             layoutId = LAYOUT_APP;
    964         else if (strcmp(layoutName, "os") == 0)
    965             layoutId = LAYOUT_OS;
    966         else if (strcmp(layoutName, "key") == 0)
    967             layoutId = LAYOUT_KEY;
    968         else
    969             fatalUsage(appName, "Invalid layout name", layoutName);
    970     }
    971 
    972     if (staticElf && layoutId != LAYOUT_APP)
    973         fatalUsage(appName, "Only app layout is supported for static option", NULL);
    974 
    975     if (layoutId == LAYOUT_APP && !appId)
    976         fatalUsage(appName, "App layout requires app ID", NULL);
    977     if (layoutId == LAYOUT_KEY && !keyId)
    978         fatalUsage(appName, "Key layout requires key ID", NULL);
    979     if (layoutId == LAYOUT_OS && (keyId || appId))
    980         fatalUsage(appName, "OS layout does not need any ID", NULL);
    981 
    982     if (!staticElf) {
    983         buf = loadFile(posArg[0], &bufUsed);
    984         fprintf(stderr, "Read %" PRIu32 " bytes\n", bufUsed);
    985     }
    986 
    987     if (!posArg[1])
    988         out = stdout;
    989     else
    990         out = fopen(posArg[1], "w");
    991     if (!out)
    992         fatalUsage(appName, "failed to create/open output file", posArg[1]);
    993 
    994     switch(layoutId) {
    995     case LAYOUT_APP:
    996         if (staticElf) {
    997             ret = handleAppStatic(posArg[0], out, layoutFlags, appId, verbose);
    998         } else {
    999             ret = handleApp(&buf, bufUsed, out, layoutFlags, appId, verbose);
   1000         }
   1001         break;
   1002     case LAYOUT_KEY:
   1003         ret = handleKey(&buf, bufUsed, out, layoutFlags, appId, keyId);
   1004         break;
   1005     case LAYOUT_OS:
   1006         ret = handleOs(&buf, bufUsed, out, layoutFlags, bareData);
   1007         break;
   1008     }
   1009 
   1010     free(buf);
   1011     fclose(out);
   1012     return ret;
   1013 }
   1014