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 <sys/types.h>
     20 #include <stdbool.h>
     21 #include <unistd.h>
     22 #include <stdlib.h>
     23 #include <string.h>
     24 #include <stdint.h>
     25 #include <stdio.h>
     26 #include <stddef.h>
     27 #include <errno.h>
     28 
     29 #include <nanohub/nanohub.h>
     30 #include <nanohub/nanoapp.h>
     31 #include <nanohub/appRelocFormat.h>
     32 
     33 //This code assumes it is run on a LE CPU with unaligned access abilities. Sorry.
     34 
     35 #define FLASH_BASE  0x10000000u
     36 #define RAM_BASE    0x80000000u
     37 
     38 #define FLASH_SIZE  0x10000000u  //256MB ought to be enough for everyone
     39 #define RAM_SIZE    0x10000000u  //256MB ought to be enough for everyone
     40 
     41 //caution: double evaluation
     42 #define IS_IN_RANGE_E(_val, _rstart, _rend) (((_val) >= (_rstart)) && ((_val) < (_rend)))
     43 #define IS_IN_RANGE(_val, _rstart, _rsz)    IS_IN_RANGE_E((_val), (_rstart), ((_rstart) + (_rsz)))
     44 #define IS_IN_RAM(_val)              IS_IN_RANGE(_val, RAM_BASE, RAM_SIZE)
     45 #define IS_IN_FLASH(_val)            IS_IN_RANGE(_val, FLASH_BASE, FLASH_SIZE)
     46 
     47 
     48 #define NANO_RELOC_TYPE_RAM    0
     49 #define NANO_RELOC_TYPE_FLASH  1
     50 #define NANO_RELOC_LAST        2 //must be <= (RELOC_TYPE_MASK >> RELOC_TYPE_SHIFT)
     51 
     52 struct RelocEntry {
     53     uint32_t where;
     54     uint32_t info;  //bottom 8 bits is type, top 24 is sym idx
     55 };
     56 
     57 #define RELOC_TYPE_ABS_S    2
     58 #define RELOC_TYPE_ABS_D    21
     59 #define RELOC_TYPE_SECT     23
     60 
     61 
     62 struct SymtabEntry {
     63     uint32_t a;
     64     uint32_t addr;
     65     uint32_t b, c;
     66 };
     67 
     68 struct NanoRelocEntry {
     69     uint32_t ofstInRam;
     70     uint8_t type;
     71 };
     72 
     73 struct NanoAppInfo {
     74     union {
     75         struct BinHdr *bin;
     76         uint8_t *data;
     77     };
     78     size_t dataSizeUsed;
     79     size_t dataSizeAllocated;
     80     size_t codeAndDataSize;   // not including symbols, relocs and BinHdr
     81     size_t codeAndRoDataSize; // also not including GOT & RW data in flash
     82     struct SymtabEntry *symtab;
     83     size_t symtabSize; // number of symbols
     84     struct RelocEntry *reloc;
     85     size_t relocSize; // number of reloc entries
     86     struct NanoRelocEntry *nanoReloc;
     87     size_t nanoRelocSize; // number of nanoReloc entries <= relocSize
     88     uint8_t *packedNanoReloc;
     89     size_t packedNanoRelocSize;
     90 
     91     bool debug;
     92 };
     93 
     94 #ifndef ARRAY_SIZE
     95 #define ARRAY_SIZE(ary) (sizeof(ary) / sizeof((ary)[0]))
     96 #endif
     97 
     98 static FILE *stdlog = NULL;
     99 
    100 #define DBG(fmt, ...) fprintf(stdlog, fmt "\n", ##__VA_ARGS__)
    101 #define ERR(fmt, ...) fprintf(stderr, fmt "\n", ##__VA_ARGS__)
    102 
    103 static void fatalUsage(const char *name, const char *msg, const char *arg)
    104 {
    105     if (msg && arg)
    106         ERR("Error: %s: %s\n", msg, arg);
    107     else if (msg)
    108         ERR("Error: %s\n", msg);
    109 
    110     ERR("USAGE: %s [-v] [-k <key id>] [-a <app id>] [-r] [-n <layout name>] [-i <layout id>] <input file> [<output file>]\n"
    111         "       -v               : be verbose\n"
    112         "       -n <layout name> : app, os, key\n"
    113         "       -i <layout id>   : 1 (app), 2 (key), 3 (os)\n"
    114         "       -f <layout flags>: 16-bit hex value, stored as layout-specific flags\n"
    115         "       -a <app ID>      : 64-bit hex number != 0\n"
    116         "       -e <app ver>     : 32-bit hex number\n"
    117         "       -k <key ID>      : 64-bit hex number != 0\n"
    118         "       -r               : bare (no AOSP header); used only for inner OS image generation\n"
    119         "       layout ID and layout name control the same parameter, so only one of them needs to be used\n"
    120         , name);
    121     exit(1);
    122 }
    123 
    124 bool packNanoRelocs(struct NanoAppInfo *app)
    125 {
    126     size_t i, j, k;
    127     uint8_t *packedNanoRelocs;
    128     uint32_t packedNanoRelocSz;
    129     uint32_t lastOutType = 0, origin = 0;
    130     bool verbose = app->debug;
    131 
    132     //sort by type and then offset
    133     for (i = 0; i < app->nanoRelocSize; i++) {
    134         struct NanoRelocEntry t;
    135 
    136         for (k = i, j = k + 1; j < app->nanoRelocSize; j++) {
    137             if (app->nanoReloc[j].type > app->nanoReloc[k].type)
    138                 continue;
    139             if ((app->nanoReloc[j].type < app->nanoReloc[k].type) || (app->nanoReloc[j].ofstInRam < app->nanoReloc[k].ofstInRam))
    140                 k = j;
    141         }
    142         memcpy(&t, app->nanoReloc + i, sizeof(struct NanoRelocEntry));
    143         memcpy(app->nanoReloc + i, app->nanoReloc + k, sizeof(struct NanoRelocEntry));
    144         memcpy(app->nanoReloc + k, &t, sizeof(struct NanoRelocEntry));
    145 
    146         if (app->debug)
    147             DBG("SortedReloc[%3zu] = {0x%08" PRIX32 ",0x%02" PRIX8 "}", i, app->nanoReloc[i].ofstInRam, app->nanoReloc[i].type);
    148     }
    149 
    150     //produce output nanorelocs in packed format
    151     packedNanoRelocs = malloc(app->nanoRelocSize * 6); //definitely big enough
    152     packedNanoRelocSz = 0;
    153 
    154     if (!packedNanoRelocs) {
    155         ERR("Failed to allocate memory for packed relocs");
    156         return false;
    157     }
    158 
    159     for (i = 0; i < app->nanoRelocSize; i++) {
    160         uint32_t displacement;
    161 
    162         if (lastOutType != app->nanoReloc[i].type) {  //output type if ti changed
    163             if (app->nanoReloc[i].type - lastOutType == 1) {
    164                 packedNanoRelocs[packedNanoRelocSz++] = TOKEN_RELOC_TYPE_NEXT;
    165                 if (verbose)
    166                     DBG("Out: RelocTC [size 1] // to 0x%02" PRIX8, app->nanoReloc[i].type);
    167             } else {
    168                 packedNanoRelocs[packedNanoRelocSz++] = TOKEN_RELOC_TYPE_CHG;
    169                 packedNanoRelocs[packedNanoRelocSz++] = app->nanoReloc[i].type - lastOutType - 1;
    170                 if (verbose)
    171                     DBG("Out: RelocTC [size 2] (0x%02" PRIX8 ")  // to 0x%02" PRIX8,
    172                         (uint8_t)(app->nanoReloc[i].type - lastOutType - 1), app->nanoReloc[i].type);
    173             }
    174             lastOutType = app->nanoReloc[i].type;
    175             origin = 0;
    176         }
    177         displacement = app->nanoReloc[i].ofstInRam - origin;
    178         origin = app->nanoReloc[i].ofstInRam + 4;
    179         if (displacement & 3) {
    180             ERR("Unaligned relocs are not possible!");
    181             return false;
    182         }
    183         displacement /= 4;
    184 
    185         //might be start of a run. look into that
    186         if (!displacement) {
    187             for (j = 1; (j + i) < app->nanoRelocSize && j < MAX_RUN_LEN &&
    188                         app->nanoReloc[j + i].type == lastOutType &&
    189                         (app->nanoReloc[j + i].ofstInRam - app->nanoReloc[j + i - 1].ofstInRam) == 4; j++);
    190             if (j >= MIN_RUN_LEN) {
    191                 if (verbose)
    192                     DBG("Out: Reloc0 [size 2]; repeat=%zu", j);
    193                 packedNanoRelocs[packedNanoRelocSz++] = TOKEN_CONSECUTIVE;
    194                 packedNanoRelocs[packedNanoRelocSz++] = j - MIN_RUN_LEN;
    195                 origin = app->nanoReloc[j + i - 1].ofstInRam + 4;  //reset origin to last one
    196                 i += j - 1;  //loop will increment anyways, hence +1
    197                 continue;
    198             }
    199         }
    200 
    201         //produce output
    202         if (displacement <= MAX_8_BIT_NUM) {
    203             if (verbose)
    204                 DBG("Out: Reloc8 [size 1] 0x%02" PRIX32, displacement);
    205             packedNanoRelocs[packedNanoRelocSz++] = displacement;
    206         } else if (displacement <= MAX_16_BIT_NUM) {
    207             if (verbose)
    208                 DBG("Out: Reloc16 [size 3] 0x%06" PRIX32, displacement);
    209                         displacement -= MAX_8_BIT_NUM;
    210             packedNanoRelocs[packedNanoRelocSz++] = TOKEN_16BIT_OFST;
    211             packedNanoRelocs[packedNanoRelocSz++] = displacement;
    212             packedNanoRelocs[packedNanoRelocSz++] = displacement >> 8;
    213         } else if (displacement <= MAX_24_BIT_NUM) {
    214             if (verbose)
    215                 DBG("Out: Reloc24 [size 4] 0x%08" PRIX32, displacement);
    216                         displacement -= MAX_16_BIT_NUM;
    217             packedNanoRelocs[packedNanoRelocSz++] = TOKEN_24BIT_OFST;
    218             packedNanoRelocs[packedNanoRelocSz++] = displacement;
    219             packedNanoRelocs[packedNanoRelocSz++] = displacement >> 8;
    220             packedNanoRelocs[packedNanoRelocSz++] = displacement >> 16;
    221         } else {
    222             if (verbose)
    223                 DBG("Out: Reloc32 [size 5] 0x%08" PRIX32, displacement);
    224             packedNanoRelocs[packedNanoRelocSz++] = TOKEN_32BIT_OFST;
    225             packedNanoRelocs[packedNanoRelocSz++] = displacement;
    226             packedNanoRelocs[packedNanoRelocSz++] = displacement >> 8;
    227             packedNanoRelocs[packedNanoRelocSz++] = displacement >> 16;
    228             packedNanoRelocs[packedNanoRelocSz++] = displacement >> 24;
    229         }
    230     }
    231 
    232     app->packedNanoReloc = packedNanoRelocs;
    233     app->packedNanoRelocSize = packedNanoRelocSz;
    234 
    235     return true;
    236 }
    237 
    238 static int finalizeAndWrite(struct NanoAppInfo *inf, FILE *out, uint32_t layoutFlags, uint64_t appId)
    239 {
    240     bool good = true;
    241     struct AppInfo app;
    242     struct SectInfo *sect;
    243     struct BinHdr *bin = inf->bin;
    244     struct ImageHeader outHeader = {
    245         .aosp = (struct nano_app_binary_t) {
    246             .header_version = 1,
    247             .magic = NANOAPP_AOSP_MAGIC,
    248             .app_id = appId,
    249             .app_version = bin->hdr.appVer,
    250             .flags       = 0, // encrypted (1), signed (2) (will be set by other tools)
    251         },
    252         .layout = (struct ImageLayout) {
    253             .magic = GOOGLE_LAYOUT_MAGIC,
    254             .version = 1,
    255             .payload = LAYOUT_APP,
    256             .flags = layoutFlags,
    257         },
    258     };
    259 
    260     app.sect = bin->sect;
    261     app.vec  = bin->vec;
    262     sect = &app.sect;
    263 
    264     //if we have any bytes to output, show stats
    265     if (inf->codeAndRoDataSize) {
    266         size_t binarySize = 0;
    267         size_t gotSz = sect->got_end - sect->data_start;
    268         size_t bssSz = sect->bss_end - sect->bss_start;
    269 
    270         good = fwrite(&outHeader, sizeof(outHeader), 1, out) == 1 && good;
    271         binarySize += sizeof(outHeader);
    272 
    273         good = fwrite(&app, sizeof(app), 1, out) == 1 && good;
    274         binarySize += sizeof(app);
    275 
    276         good = fwrite(&bin[1], inf->codeAndDataSize, 1, out) == 1 && good;
    277         binarySize += inf->codeAndDataSize;
    278 
    279         if (inf->packedNanoReloc && inf->packedNanoRelocSize) {
    280             good = fwrite(inf->packedNanoReloc, inf->packedNanoRelocSize, 1, out) == 1 && good;
    281             binarySize += inf->packedNanoRelocSize;
    282         }
    283 
    284         if (!good) {
    285             ERR("Failed to write output file: %s\n", strerror(errno));
    286         } else {
    287             DBG("Final binary size %zu bytes", binarySize);
    288             DBG("");
    289             DBG("       FW header size (flash):      %6zu bytes", FLASH_RELOC_OFFSET);
    290             DBG("       Code + RO data (flash):      %6zu bytes", inf->codeAndRoDataSize);
    291             DBG("       Relocs (flash):              %6zu bytes", inf->packedNanoRelocSize);
    292             DBG("       GOT + RW data (flash & RAM): %6zu bytes", gotSz);
    293             DBG("       BSS (RAM):                   %6zu bytes", bssSz);
    294             DBG("");
    295             DBG("Runtime flash use: %zu bytes",
    296                 (size_t)(inf->codeAndRoDataSize + inf->packedNanoRelocSize + gotSz + FLASH_RELOC_OFFSET));
    297             DBG("Runtime RAM use: %zu bytes", gotSz + bssSz);
    298         }
    299     }
    300 
    301     return good ? 0 : 2;
    302 }
    303 
    304 // Subtracts the fixed memory region offset from an absolute address and returns
    305 // the associated NANO_RELOC_* value, or NANO_RELOC_LAST if the address is not
    306 // in the expected range.
    307 static uint8_t fixupAddress(uint32_t *addr, struct SymtabEntry *sym, bool debug)
    308 {
    309     uint8_t type;
    310     uint32_t old = *addr;
    311 
    312     (*addr) += sym->addr;
    313     // TODO: this assumes that the host running this tool has the same
    314     // endianness as the image file/target processor
    315     if (IS_IN_RAM(*addr)) {
    316         *addr -= RAM_BASE;
    317         type = NANO_RELOC_TYPE_RAM;
    318         if (debug)
    319             DBG("Fixup addr 0x%08" PRIX32 " (RAM) --> 0x%08" PRIX32, old, *addr);
    320     } else if (IS_IN_FLASH(*addr)) {
    321         *addr -= FLASH_BASE + BINARY_RELOC_OFFSET;
    322         type = NANO_RELOC_TYPE_FLASH;
    323         if (debug)
    324             DBG("Fixup addr 0x%08" PRIX32 " (FLASH) --> 0x%08" PRIX32, old, *addr);
    325     } else {
    326         ERR("Error: invalid address 0x%08" PRIX32, *addr);
    327         type = NANO_RELOC_LAST;
    328     }
    329 
    330     return type;
    331 }
    332 
    333 static void relocDiag(const struct NanoAppInfo *app, const struct RelocEntry *reloc, const char *msg)
    334 {
    335     size_t symIdx = reloc->info >> 8;
    336     uint8_t symType = reloc->info;
    337 
    338     ERR("Reloc %zu %s", reloc - app->reloc, msg);
    339     ERR("INFO:");
    340     ERR("        Where: 0x%08" PRIX32, reloc->where);
    341     ERR("        type: %" PRIu8, symType);
    342     ERR("        sym: %zu", symIdx);
    343     if (symIdx < app->symtabSize) {
    344         struct SymtabEntry *sym = &app->symtab[symIdx];
    345         ERR("        addr: %" PRIu32, sym->addr);
    346     } else {
    347         ERR("        addr: <invalid>");
    348     }
    349 }
    350 
    351 static uint8_t fixupReloc(struct NanoAppInfo *app, struct RelocEntry *reloc,
    352                           struct SymtabEntry *sym, struct NanoRelocEntry *nanoReloc)
    353 {
    354     uint8_t type;
    355     uint32_t *addr;
    356     uint32_t relocOffset = reloc->where;
    357     uint32_t flashDataOffset = 0;
    358 
    359     if (IS_IN_FLASH(relocOffset)) {
    360         relocOffset -= FLASH_BASE;
    361         flashDataOffset = 0;
    362     } else if (IS_IN_RAM(reloc->where)) {
    363         relocOffset = reloc->where - RAM_BASE;
    364         flashDataOffset = app->bin->sect.data_data - FLASH_BASE;
    365     } else {
    366         relocDiag(app, reloc, "is neither in RAM nor in FLASH");
    367         return NANO_RELOC_LAST;
    368     }
    369 
    370     addr = (uint32_t*)(app->data + flashDataOffset + relocOffset);
    371 
    372     if (flashDataOffset + relocOffset >= app->dataSizeUsed - sizeof(*addr)) {
    373         relocDiag(app, reloc, "points outside valid data area");
    374         return NANO_RELOC_LAST;
    375     }
    376 
    377     switch (reloc->info & 0xFF) {
    378     case RELOC_TYPE_ABS_S:
    379     case RELOC_TYPE_ABS_D:
    380         type = fixupAddress(addr, sym, app->debug);
    381         break;
    382 
    383     case RELOC_TYPE_SECT:
    384         if (sym->addr) {
    385             relocDiag(app, reloc, "has section relocation with non-zero symbol address");
    386             return NANO_RELOC_LAST;
    387         }
    388         type = fixupAddress(addr, sym, app->debug);
    389         break;
    390     default:
    391         relocDiag(app, reloc, "has unknown type");
    392         type = NANO_RELOC_LAST;
    393     }
    394 
    395     if (nanoReloc && type != NANO_RELOC_LAST) {
    396         nanoReloc->ofstInRam = relocOffset;
    397         nanoReloc->type = type;
    398     }
    399 
    400     return type;
    401 }
    402 
    403 static int handleApp(uint8_t **pbuf, uint32_t bufUsed, FILE *out, uint32_t layoutFlags, uint64_t appId, uint32_t appVer, bool verbose)
    404 {
    405     uint32_t i;
    406     struct BinHdr *bin;
    407     int ret = -1;
    408     struct SectInfo *sect;
    409     uint8_t *buf = *pbuf;
    410     uint32_t bufSz = bufUsed * 3 /2;
    411     struct NanoAppInfo app;
    412 
    413     //make buffer 50% bigger than bufUsed in case relocs grow out of hand
    414     buf = reallocOrDie(buf, bufSz);
    415     *pbuf = buf;
    416 
    417     //sanity checks
    418     bin = (struct BinHdr*)buf;
    419     if (bufUsed < sizeof(*bin)) {
    420         ERR("File size too small: %" PRIu32, bufUsed);
    421         goto out;
    422     }
    423 
    424     if (bin->hdr.magic != NANOAPP_FW_MAGIC) {
    425         ERR("Magic value is wrong: found %08" PRIX32"; expected %08" PRIX32, bin->hdr.magic, NANOAPP_FW_MAGIC);
    426         goto out;
    427     }
    428 
    429     sect = &bin->sect;
    430     bin->hdr.appVer = appVer;
    431 
    432     if (!IS_IN_FLASH(sect->rel_start) || !IS_IN_FLASH(sect->rel_end) || !IS_IN_FLASH(sect->data_data)) {
    433         ERR("relocation data or initialized data is not in FLASH");
    434         goto out;
    435     }
    436     if (!IS_IN_RAM(sect->data_start) || !IS_IN_RAM(sect->data_end) || !IS_IN_RAM(sect->bss_start) ||
    437         !IS_IN_RAM(sect->bss_end) || !IS_IN_RAM(sect->got_start) || !IS_IN_RAM(sect->got_end)) {
    438         ERR("data, bss, or got not in ram\n");
    439         goto out;
    440     }
    441 
    442     //do some math
    443     app.reloc = (struct RelocEntry*)(buf + sect->rel_start - FLASH_BASE);
    444     app.symtab = (struct SymtabEntry*)(buf + sect->rel_end - FLASH_BASE);
    445     app.relocSize = (sect->rel_end - sect->rel_start) / sizeof(struct RelocEntry);
    446     app.nanoRelocSize = 0;
    447     app.symtabSize = (struct SymtabEntry*)(buf + bufUsed) - app.symtab;
    448     app.data = buf;
    449     app.dataSizeAllocated = bufSz;
    450     app.dataSizeUsed = bufUsed;
    451     app.codeAndRoDataSize = sect->data_data - FLASH_BASE - sizeof(*bin);
    452     app.codeAndDataSize = sect->rel_start - FLASH_BASE - sizeof(*bin);
    453     app.debug = verbose;
    454     app.nanoReloc = NULL;
    455     app.packedNanoReloc = NULL;
    456 
    457     //sanity
    458     if (app.relocSize * sizeof(struct RelocEntry) + sect->rel_start != sect->rel_end) {
    459         ERR("Relocs of nonstandard size");
    460         goto out;
    461     }
    462     if (app.symtabSize * sizeof(struct SymtabEntry) + sect->rel_end != bufUsed + FLASH_BASE) {
    463         ERR("Syms of nonstandard size");
    464         goto out;
    465     }
    466 
    467     //show some info
    468 
    469     if (verbose)
    470         DBG("Found %zu relocs and a %zu-entry symbol table", app.relocSize, app.symtabSize);
    471 
    472     //handle relocs
    473     app.nanoReloc = malloc(sizeof(struct NanoRelocEntry[app.relocSize]));
    474     if (!app.nanoReloc) {
    475         ERR("Failed to allocate a nano-reloc table\n");
    476         goto out;
    477     }
    478 
    479     for (i = 0; i < app.relocSize; i++) {
    480         struct RelocEntry *reloc = &app.reloc[i];
    481         struct NanoRelocEntry *nanoReloc = &app.nanoReloc[app.nanoRelocSize];
    482         uint32_t relocType = reloc->info & 0xff;
    483         uint32_t whichSym = reloc->info >> 8;
    484         struct SymtabEntry *sym = &app.symtab[whichSym];
    485 
    486         if (whichSym >= app.symtabSize) {
    487             relocDiag(&app, reloc, "references a nonexistent symbol");
    488             goto out;
    489         }
    490 
    491         if (verbose) {
    492             const char *seg;
    493 
    494             if (IS_IN_RANGE_E(reloc->where, sect->bss_start, sect->bss_end))
    495                 seg = ".bss";
    496             else if (IS_IN_RANGE_E(reloc->where, sect->data_start, sect->data_end))
    497                 seg = ".data";
    498             else if (IS_IN_RANGE_E(reloc->where, sect->got_start, sect->got_end))
    499                 seg = ".got";
    500             else if (IS_IN_RANGE_E(reloc->where, FLASH_BASE, FLASH_BASE + sizeof(struct BinHdr)))
    501                 seg = "APPHDR";
    502             else
    503                 seg = "???";
    504 
    505             DBG("Reloc[%3" PRIu32 "]:\n {@0x%08" PRIX32 ", type %3" PRIu32 ", -> sym[%3" PRIu32 "]: {@0x%08" PRIX32 "}, in   %s}",
    506                 i, reloc->where, reloc->info & 0xff, whichSym, sym->addr, seg);
    507         }
    508         /* handle relocs inside the header */
    509         if (IS_IN_FLASH(reloc->where) && reloc->where - FLASH_BASE < sizeof(struct BinHdr) && relocType == RELOC_TYPE_SECT) {
    510             /* relocs in header are special - runtime corrects for them */
    511             // binary header generated by objcopy, .napp header and final FW header in flash are of different layout and size.
    512             // we subtract binary header offset here, so all the entry points are relative to beginning of "sect".
    513             // FW will use &sect as a base to call these vectors; no more problems with different header sizes;
    514             // Assumption: offsets between sect & vec, vec & code are the same in all images (or, in a simpler words, { sect, vec, code }
    515             // must go together). this is enforced by linker script, and maintained by all tools and FW download code in the OS.
    516 
    517             switch (fixupReloc(&app, reloc, sym, NULL)) {
    518             case NANO_RELOC_TYPE_RAM:
    519                 relocDiag(&app, reloc, "is in APPHDR but relocated to RAM");
    520                 goto out;
    521             case NANO_RELOC_TYPE_FLASH:
    522                 break;
    523             default:
    524                 // other error happened; it is already reported
    525                 goto out;
    526             }
    527 
    528             if (verbose)
    529                 DBG("  -> Nano reloc skipped for in-header reloc");
    530 
    531             continue; /* do not produce an output reloc */
    532         }
    533 
    534         // any other relocs may only happen in RAM
    535         if (!IS_IN_RAM(reloc->where)) {
    536             relocDiag(&app, reloc, "is not in RAM");
    537             goto out;
    538         }
    539 
    540         if (fixupReloc(&app, reloc, sym, nanoReloc) != NANO_RELOC_LAST) {
    541             app.nanoRelocSize++;
    542             if (verbose)
    543                 DBG("  -> Nano reloc calculated as 0x%08" PRIX32 ",0x%02" PRIX8 "\n", nanoReloc->ofstInRam, nanoReloc->type);
    544         }
    545     }
    546 
    547     if (!packNanoRelocs(&app))
    548         goto out;
    549 
    550     // we're going to write packed relocs; set correct size
    551     sect->rel_end = sect->rel_start + app.packedNanoRelocSize;
    552 
    553     //adjust headers for easy access (RAM)
    554     sect->data_start -= RAM_BASE;
    555     sect->data_end -= RAM_BASE;
    556     sect->bss_start -= RAM_BASE;
    557     sect->bss_end -= RAM_BASE;
    558     sect->got_start -= RAM_BASE;
    559     sect->got_end -= RAM_BASE;
    560 
    561     //adjust headers for easy access (FLASH)
    562     sect->data_data -= FLASH_BASE + BINARY_RELOC_OFFSET;
    563     sect->rel_start -= FLASH_BASE + BINARY_RELOC_OFFSET;
    564     sect->rel_end -= FLASH_BASE + BINARY_RELOC_OFFSET;
    565 
    566     ret = finalizeAndWrite(&app, out, layoutFlags, appId);
    567 out:
    568     free(app.nanoReloc);
    569     free(app.packedNanoReloc);
    570     return ret;
    571 }
    572 
    573 static int handleKey(uint8_t **pbuf, uint32_t bufUsed, FILE *out, uint32_t layoutFlags, uint64_t appId, uint64_t keyId)
    574 {
    575     uint8_t *buf = *pbuf;
    576     struct KeyInfo ki = { .data = keyId };
    577     bool good = true;
    578 
    579     struct ImageHeader outHeader = {
    580         .aosp = (struct nano_app_binary_t) {
    581             .header_version = 1,
    582             .magic = NANOAPP_AOSP_MAGIC,
    583             .app_id = appId,
    584         },
    585         .layout = (struct ImageLayout) {
    586             .magic = GOOGLE_LAYOUT_MAGIC,
    587             .version = 1,
    588             .payload = LAYOUT_KEY,
    589             .flags = layoutFlags,
    590         },
    591     };
    592 
    593     good = good && fwrite(&outHeader, sizeof(outHeader), 1, out) == 1;
    594     good = good && fwrite(&ki, sizeof(ki), 1, out) ==  1;
    595     good = good && fwrite(buf, bufUsed, 1, out) == 1;
    596 
    597     return good ? 0 : 2;
    598 }
    599 
    600 static int handleOs(uint8_t **pbuf, uint32_t bufUsed, FILE *out, uint32_t layoutFlags, bool bare)
    601 {
    602     uint8_t *buf = *pbuf;
    603     bool good;
    604 
    605     struct OsUpdateHdr os = {
    606         .magic = OS_UPDT_MAGIC,
    607         .marker = OS_UPDT_MARKER_INPROGRESS,
    608         .size = bufUsed
    609     };
    610 
    611     struct ImageHeader outHeader = {
    612         .aosp = (struct nano_app_binary_t) {
    613             .header_version = 1,
    614             .magic = NANOAPP_AOSP_MAGIC,
    615         },
    616         .layout = (struct ImageLayout) {
    617             .magic = GOOGLE_LAYOUT_MAGIC,
    618             .version = 1,
    619             .payload = LAYOUT_OS,
    620             .flags = layoutFlags,
    621         },
    622     };
    623 
    624     if (!bare)
    625         good = fwrite(&outHeader, sizeof(outHeader), 1, out) == 1;
    626     else
    627         good = fwrite(&os, sizeof(os), 1, out) == 1;
    628     good = good && fwrite(buf, bufUsed, 1, out) == 1;
    629 
    630     return good ? 0 : 2;
    631 }
    632 
    633 int main(int argc, char **argv)
    634 {
    635     uint32_t bufUsed = 0;
    636     bool verbose = false;
    637     uint8_t *buf = NULL;
    638     uint64_t appId = 0;
    639     uint64_t keyId = 0;
    640     uint32_t appVer = 0;
    641     uint32_t layoutId = 0;
    642     uint32_t layoutFlags = 0;
    643     int ret = -1;
    644     uint32_t *u32Arg = NULL;
    645     uint64_t *u64Arg = NULL;
    646     const char **strArg = NULL;
    647     const char *appName = argv[0];
    648     int posArgCnt = 0;
    649     const char *posArg[2] = { NULL };
    650     FILE *out = NULL;
    651     const char *layoutName = "app";
    652     const char *prev = NULL;
    653     bool bareData = false;
    654 
    655     for (int i = 1; i < argc; i++) {
    656         char *end = NULL;
    657         if (argv[i][0] == '-') {
    658             prev = argv[i];
    659             if (!strcmp(argv[i], "-v"))
    660                 verbose = true;
    661             else if (!strcmp(argv[i], "-r"))
    662                 bareData = true;
    663             else if (!strcmp(argv[i], "-a"))
    664                 u64Arg = &appId;
    665             else if (!strcmp(argv[i], "-e"))
    666                 u32Arg = &appVer;
    667             else if (!strcmp(argv[i], "-k"))
    668                 u64Arg = &keyId;
    669             else if (!strcmp(argv[i], "-n"))
    670                 strArg = &layoutName;
    671             else if (!strcmp(argv[i], "-i"))
    672                 u32Arg = &layoutId;
    673             else if (!strcmp(argv[i], "-f"))
    674                 u32Arg = &layoutFlags;
    675             else
    676                 fatalUsage(appName, "unknown argument", argv[i]);
    677         } else {
    678             if (u64Arg) {
    679                 uint64_t tmp = strtoull(argv[i], &end, 16);
    680                 if (*end == '\0')
    681                     *u64Arg = tmp;
    682                 u64Arg = NULL;
    683             } else if (u32Arg) {
    684                 uint32_t tmp = strtoul(argv[i], &end, 16);
    685                 if (*end == '\0')
    686                     *u32Arg = tmp;
    687                 u32Arg = NULL;
    688             } else if (strArg) {
    689                     *strArg = argv[i];
    690                 strArg = NULL;
    691             } else {
    692                 if (posArgCnt < 2)
    693                     posArg[posArgCnt++] = argv[i];
    694                 else
    695                     fatalUsage(appName, "too many positional arguments", argv[i]);
    696             }
    697             prev = NULL;
    698         }
    699     }
    700     if (prev)
    701         fatalUsage(appName, "missing argument after", prev);
    702 
    703     if (!posArgCnt)
    704         fatalUsage(appName, "missing input file name", NULL);
    705 
    706     if (!layoutId) {
    707         if (strcmp(layoutName, "app") == 0)
    708             layoutId = LAYOUT_APP;
    709         else if (strcmp(layoutName, "os") == 0)
    710             layoutId = LAYOUT_OS;
    711         else if (strcmp(layoutName, "key") == 0)
    712             layoutId = LAYOUT_KEY;
    713         else
    714             fatalUsage(appName, "Invalid layout name", layoutName);
    715     }
    716 
    717     if (layoutId == LAYOUT_APP && !appId)
    718         fatalUsage(appName, "App layout requires app ID", NULL);
    719     if (layoutId == LAYOUT_KEY && !keyId)
    720         fatalUsage(appName, "Key layout requires key ID", NULL);
    721     if (layoutId == LAYOUT_OS && (keyId || appId))
    722         fatalUsage(appName, "OS layout does not need any ID", NULL);
    723 
    724     if (!posArg[1]) {
    725         out = stdout;
    726         stdlog = stderr;
    727     } else {
    728         out = fopen(posArg[1], "w");
    729         stdlog = stdout;
    730     }
    731     if (!out)
    732         fatalUsage(appName, "failed to create/open output file", posArg[1]);
    733 
    734     buf = loadFile(posArg[0], &bufUsed);
    735     DBG("Read %" PRIu32 " bytes from %s", bufUsed, posArg[0]);
    736 
    737     switch(layoutId) {
    738     case LAYOUT_APP:
    739         ret = handleApp(&buf, bufUsed, out, layoutFlags, appId, appVer, verbose);
    740         break;
    741     case LAYOUT_KEY:
    742         ret = handleKey(&buf, bufUsed, out, layoutFlags, appId, keyId);
    743         break;
    744     case LAYOUT_OS:
    745         ret = handleOs(&buf, bufUsed, out, layoutFlags, bareData);
    746         break;
    747     }
    748 
    749     free(buf);
    750     fclose(out);
    751     return ret;
    752 }
    753