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