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 § 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