1 /*
2 * Copyright (C) 2020 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <dlfcn.h>
18 #include <cctype>
19 #include <cmath>
20 #include <cstring>
21
22 #include "chre/platform/shared/nanoapp_loader.h"
23
24 #include "ash.h"
25 #include "ash/profile.h"
26 #include "chre.h"
27 #include "chre/platform/assert.h"
28 #include "chre/platform/fatal_error.h"
29 #include "chre/platform/shared/debug_dump.h"
30 #include "chre/platform/shared/memory.h"
31 #include "chre/target_platform/platform_cache_management.h"
32 #include "chre/util/dynamic_vector.h"
33 #include "chre/util/macros.h"
34
35 #ifndef CHRE_LOADER_ARCH
36 #define CHRE_LOADER_ARCH EM_ARM
37 #endif // CHRE_LOADER_ARCH
38
39 namespace chre {
40 namespace {
41
42 using ElfHeader = ElfW(Ehdr);
43 using ProgramHeader = ElfW(Phdr);
44
45 struct ExportedData {
46 void *data;
47 const char *dataName;
48 };
49
50 //! If non-null, a nanoapp is currently being loaded. This allows certain C
51 //! functions to access the nanoapp if called during static init.
52 NanoappLoader *gCurrentlyLoadingNanoapp = nullptr;
53 //! Indicates whether a failure occurred during static initialization.
54 bool gStaticInitFailure = false;
55
56 // The new operator is used by singleton.h which causes the delete operator to
57 // be undefined in nanoapp binaries even though it's unused. Define this in case
58 // a nanoapp actually tries to use the operator.
deleteOverride(void * ptr)59 void deleteOverride(void *ptr) {
60 FATAL_ERROR("Nanoapp tried to free %p through delete operator", ptr);
61 }
62
63 // atexit is used to register functions that must be called when a binary is
64 // removed from the system.
atexitOverride(void (* function)(void))65 int atexitOverride(void (*function)(void)) {
66 LOGV("atexit invoked with %p", function);
67 if (gCurrentlyLoadingNanoapp == nullptr) {
68 CHRE_ASSERT_LOG(false,
69 "atexit is only supported during static initialization.");
70 return -1;
71 }
72
73 gCurrentlyLoadingNanoapp->registerAtexitFunction(function);
74 return 0;
75 }
76
77 // The following functions from the cmath header need to be overridden, since
78 // they're overloaded functions, and we need to specify explicit types of the
79 // template for the compiler.
frexpOverride(double value,int * exp)80 double frexpOverride(double value, int *exp) {
81 return frexp(value, exp);
82 }
83
fmaxOverride(double x,double y)84 double fmaxOverride(double x, double y) {
85 return fmax(x, y);
86 }
87
fminOverride(double x,double y)88 double fminOverride(double x, double y) {
89 return fmin(x, y);
90 }
91
floorOverride(double value)92 double floorOverride(double value) {
93 return floor(value);
94 }
95
sinOverride(double rad)96 double sinOverride(double rad) {
97 return sin(rad);
98 }
99
asinOverride(double val)100 double asinOverride(double val) {
101 return asin(val);
102 }
103
atan2Override(double y,double x)104 double atan2Override(double y, double x) {
105 return atan2(y, x);
106 }
107
cosOverride(double rad)108 double cosOverride(double rad) {
109 return cos(rad);
110 }
111
sqrtOverride(float val)112 float sqrtOverride(float val) {
113 return sqrt(val);
114 }
115
roundOverride(double val)116 double roundOverride(double val) {
117 return round(val);
118 }
119
120 // This function is required to be exposed to nanoapps to handle errors from
121 // invoking virtual functions.
__cxa_pure_virtual(void)122 void __cxa_pure_virtual(void) {
123 chreAbort(CHRE_ERROR /* abortCode */);
124 }
125
126 #define ADD_EXPORTED_SYMBOL(function_name, function_string) \
127 { reinterpret_cast<void *>(function_name), function_string }
128 #define ADD_EXPORTED_C_SYMBOL(function_name) \
129 ADD_EXPORTED_SYMBOL(function_name, STRINGIFY(function_name))
130
131 // TODO(karthikmb/stange): While this array was hand-coded for simple
132 // "hello-world" prototyping, the list of exported symbols must be
133 // generated to minimize runtime errors and build breaks.
134 // clang-format off
135 // Disable deprecation warning so that deprecated symbols in the array
136 // can be exported for older nanoapps and tests.
137 CHRE_DEPRECATED_PREAMBLE
138 const ExportedData gExportedData[] = {
139 /* libmath overrrides and symbols */
140 ADD_EXPORTED_SYMBOL(asinOverride, "asin"),
141 ADD_EXPORTED_SYMBOL(atan2Override, "atan2"),
142 ADD_EXPORTED_SYMBOL(cosOverride, "cos"),
143 ADD_EXPORTED_SYMBOL(frexpOverride, "frexp"),
144 ADD_EXPORTED_SYMBOL(fmaxOverride, "fmax"),
145 ADD_EXPORTED_SYMBOL(fminOverride, "fmin"),
146 ADD_EXPORTED_SYMBOL(floorOverride, "floor"),
147 ADD_EXPORTED_SYMBOL(roundOverride, "round"),
148 ADD_EXPORTED_SYMBOL(sinOverride, "sin"),
149 ADD_EXPORTED_SYMBOL(sqrtOverride, "sqrt"),
150 ADD_EXPORTED_C_SYMBOL(acosf),
151 ADD_EXPORTED_C_SYMBOL(asinf),
152 ADD_EXPORTED_C_SYMBOL(atan2f),
153 ADD_EXPORTED_C_SYMBOL(cosf),
154 ADD_EXPORTED_C_SYMBOL(expf),
155 ADD_EXPORTED_C_SYMBOL(floorf),
156 ADD_EXPORTED_C_SYMBOL(fmaxf),
157 ADD_EXPORTED_C_SYMBOL(fminf),
158 ADD_EXPORTED_C_SYMBOL(fmodf),
159 ADD_EXPORTED_C_SYMBOL(log10f),
160 ADD_EXPORTED_C_SYMBOL(lroundf),
161 ADD_EXPORTED_C_SYMBOL(roundf),
162 ADD_EXPORTED_C_SYMBOL(sinf),
163 ADD_EXPORTED_C_SYMBOL(sqrtf),
164 ADD_EXPORTED_C_SYMBOL(tanhf),
165 /* libc overrides and symbols */
166 ADD_EXPORTED_C_SYMBOL(__cxa_pure_virtual),
167 ADD_EXPORTED_SYMBOL(atexitOverride, "atexit"),
168 ADD_EXPORTED_SYMBOL(deleteOverride, "_ZdlPv"),
169 ADD_EXPORTED_C_SYMBOL(dlsym),
170 ADD_EXPORTED_C_SYMBOL(memcmp),
171 ADD_EXPORTED_C_SYMBOL(memcpy),
172 ADD_EXPORTED_C_SYMBOL(memmove),
173 ADD_EXPORTED_C_SYMBOL(memset),
174 ADD_EXPORTED_C_SYMBOL(snprintf),
175 ADD_EXPORTED_C_SYMBOL(strcmp),
176 ADD_EXPORTED_C_SYMBOL(strlen),
177 ADD_EXPORTED_C_SYMBOL(strncmp),
178 ADD_EXPORTED_C_SYMBOL(tolower),
179 /* ash symbols */
180 ADD_EXPORTED_C_SYMBOL(ashProfileInit),
181 ADD_EXPORTED_C_SYMBOL(ashProfileBegin),
182 ADD_EXPORTED_C_SYMBOL(ashProfileEnd),
183 ADD_EXPORTED_C_SYMBOL(ashLoadCalibrationParams),
184 ADD_EXPORTED_C_SYMBOL(ashSaveCalibrationParams),
185 ADD_EXPORTED_C_SYMBOL(ashSetCalibration),
186 ADD_EXPORTED_C_SYMBOL(ashLoadMultiCalibrationParams),
187 ADD_EXPORTED_C_SYMBOL(ashSaveMultiCalibrationParams),
188 ADD_EXPORTED_C_SYMBOL(ashSetMultiCalibration),
189 /* CHRE symbols */
190 ADD_EXPORTED_C_SYMBOL(chreAbort),
191 ADD_EXPORTED_C_SYMBOL(chreAudioConfigureSource),
192 ADD_EXPORTED_C_SYMBOL(chreAudioGetSource),
193 ADD_EXPORTED_C_SYMBOL(chreConfigureDebugDumpEvent),
194 ADD_EXPORTED_C_SYMBOL(chreConfigureHostSleepStateEvents),
195 ADD_EXPORTED_C_SYMBOL(chreConfigureNanoappInfoEvents),
196 ADD_EXPORTED_C_SYMBOL(chreDebugDumpLog),
197 ADD_EXPORTED_C_SYMBOL(chreGetApiVersion),
198 ADD_EXPORTED_C_SYMBOL(chreGetAppId),
199 ADD_EXPORTED_C_SYMBOL(chreGetInstanceId),
200 ADD_EXPORTED_C_SYMBOL(chreGetEstimatedHostTimeOffset),
201 ADD_EXPORTED_C_SYMBOL(chreGetNanoappInfoByAppId),
202 ADD_EXPORTED_C_SYMBOL(chreGetNanoappInfoByInstanceId),
203 ADD_EXPORTED_C_SYMBOL(chreGetPlatformId),
204 ADD_EXPORTED_C_SYMBOL(chreGetSensorInfo),
205 ADD_EXPORTED_C_SYMBOL(chreGetSensorSamplingStatus),
206 ADD_EXPORTED_C_SYMBOL(chreGetTime),
207 ADD_EXPORTED_C_SYMBOL(chreGetVersion),
208 ADD_EXPORTED_C_SYMBOL(chreGnssConfigurePassiveLocationListener),
209 ADD_EXPORTED_C_SYMBOL(chreGnssGetCapabilities),
210 ADD_EXPORTED_C_SYMBOL(chreGnssLocationSessionStartAsync),
211 ADD_EXPORTED_C_SYMBOL(chreGnssLocationSessionStopAsync),
212 ADD_EXPORTED_C_SYMBOL(chreGnssMeasurementSessionStartAsync),
213 ADD_EXPORTED_C_SYMBOL(chreGnssMeasurementSessionStopAsync),
214 ADD_EXPORTED_C_SYMBOL(chreHeapAlloc),
215 ADD_EXPORTED_C_SYMBOL(chreHeapFree),
216 ADD_EXPORTED_C_SYMBOL(chreIsHostAwake),
217 ADD_EXPORTED_C_SYMBOL(chreLog),
218 ADD_EXPORTED_C_SYMBOL(chreSendEvent),
219 ADD_EXPORTED_C_SYMBOL(chreSendMessageToHost),
220 ADD_EXPORTED_C_SYMBOL(chreSendMessageToHostEndpoint),
221 ADD_EXPORTED_C_SYMBOL(chreSendMessageWithPermissions),
222 ADD_EXPORTED_C_SYMBOL(chreSensorConfigure),
223 ADD_EXPORTED_C_SYMBOL(chreSensorConfigureBiasEvents),
224 ADD_EXPORTED_C_SYMBOL(chreSensorFind),
225 ADD_EXPORTED_C_SYMBOL(chreSensorFindDefault),
226 ADD_EXPORTED_C_SYMBOL(chreSensorFlushAsync),
227 ADD_EXPORTED_C_SYMBOL(chreSensorGetThreeAxisBias),
228 ADD_EXPORTED_C_SYMBOL(chreTimerCancel),
229 ADD_EXPORTED_C_SYMBOL(chreTimerSet),
230 ADD_EXPORTED_C_SYMBOL(chreUserSettingConfigureEvents),
231 ADD_EXPORTED_C_SYMBOL(chreUserSettingGetState),
232 ADD_EXPORTED_C_SYMBOL(chreWifiConfigureScanMonitorAsync),
233 ADD_EXPORTED_C_SYMBOL(chreWifiGetCapabilities),
234 ADD_EXPORTED_C_SYMBOL(chreWifiRequestScanAsync),
235 ADD_EXPORTED_C_SYMBOL(chreWifiRequestRangingAsync),
236 ADD_EXPORTED_C_SYMBOL(chreWwanGetCapabilities),
237 ADD_EXPORTED_C_SYMBOL(chreWwanGetCellInfoAsync),
238 ADD_EXPORTED_C_SYMBOL(platform_chreDebugDumpVaLog),
239 };
240 CHRE_DEPRECATED_EPILOGUE
241 // clang-format on
242
243 } // namespace
244
create(void * elfInput,bool mapIntoTcm)245 void *NanoappLoader::create(void *elfInput, bool mapIntoTcm) {
246 void *instance = nullptr;
247 NanoappLoader *loader = memoryAllocDram<NanoappLoader>(elfInput, mapIntoTcm);
248 if (loader != nullptr) {
249 if (loader->open()) {
250 instance = loader;
251 } else {
252 memoryFreeDram(loader);
253 }
254 } else {
255 LOG_OOM();
256 }
257
258 return instance;
259 }
260
destroy(NanoappLoader * loader)261 void NanoappLoader::destroy(NanoappLoader *loader) {
262 loader->close();
263 // TODO(b/151847750): Modify utilities to support free'ing from regions other
264 // than SRAM.
265 loader->~NanoappLoader();
266 memoryFreeDram(loader);
267 }
268
findExportedSymbol(const char * name)269 void *NanoappLoader::findExportedSymbol(const char *name) {
270 size_t nameLen = strlen(name);
271 for (size_t i = 0; i < ARRAY_SIZE(gExportedData); i++) {
272 if (nameLen == strlen(gExportedData[i].dataName) &&
273 strncmp(name, gExportedData[i].dataName, nameLen) == 0) {
274 return gExportedData[i].data;
275 }
276 }
277
278 LOGE("Unable to find %s", name);
279 return nullptr;
280 }
281
open()282 bool NanoappLoader::open() {
283 bool success = false;
284 if (mBinary != nullptr) {
285 if (!copyAndVerifyHeaders()) {
286 LOGE("Failed to verify headers");
287 } else if (!createMappings()) {
288 LOGE("Failed to create mappings");
289 } else if (!fixRelocations()) {
290 LOGE("Failed to fix relocations");
291 } else if (!resolveGot()) {
292 LOGE("Failed to resolve GOT");
293 } else {
294 // Wipe caches before calling init array to ensure initializers are not in
295 // the data cache.
296 wipeSystemCaches();
297 if (!callInitArray()) {
298 LOGE("Failed to perform static init");
299 } else {
300 success = true;
301 }
302 }
303 }
304
305 if (!success) {
306 freeAllocatedData();
307 }
308
309 return success;
310 }
311
close()312 void NanoappLoader::close() {
313 callAtexitFunctions();
314 callTerminatorArray();
315 freeAllocatedData();
316 }
317
findSymbolByName(const char * name)318 void *NanoappLoader::findSymbolByName(const char *name) {
319 void *symbol = nullptr;
320 uint8_t *index = mSymbolTablePtr;
321 while (index < (mSymbolTablePtr + mSymbolTableSize)) {
322 ElfSym *currSym = reinterpret_cast<ElfSym *>(index);
323 const char *symbolName = &mStringTablePtr[currSym->st_name];
324
325 if (strncmp(symbolName, name, strlen(name)) == 0) {
326 symbol = mMapping + currSym->st_value;
327 break;
328 }
329
330 index += sizeof(ElfSym);
331 }
332 return symbol;
333 }
334
registerAtexitFunction(void (* function)(void))335 void NanoappLoader::registerAtexitFunction(void (*function)(void)) {
336 if (!mAtexitFunctions.push_back(function)) {
337 LOG_OOM();
338 gStaticInitFailure = true;
339 }
340 }
341
mapBss(const ProgramHeader * hdr)342 void NanoappLoader::mapBss(const ProgramHeader *hdr) {
343 // if the memory size of this segment exceeds the file size zero fill the
344 // difference.
345 LOGV("Program Hdr mem sz: %zu file size: %zu", hdr->p_memsz, hdr->p_filesz);
346 if (hdr->p_memsz > hdr->p_filesz) {
347 ElfAddr endOfFile = hdr->p_vaddr + hdr->p_filesz + mLoadBias;
348 ElfAddr endOfMem = hdr->p_vaddr + hdr->p_memsz + mLoadBias;
349 if (endOfMem > endOfFile) {
350 auto deltaMem = endOfMem - endOfFile;
351 LOGV("Zeroing out %zu from page %x", deltaMem, endOfFile);
352 memset(reinterpret_cast<void *>(endOfFile), 0, deltaMem);
353 }
354 }
355 }
356
callInitArray()357 bool NanoappLoader::callInitArray() {
358 bool success = true;
359 // Sets global variable used by atexit in case it's invoked as part of
360 // initializing static data.
361 gCurrentlyLoadingNanoapp = this;
362
363 // TODO(b/151847750): ELF can have other sections like .init, .preinit, .fini
364 // etc. Be sure to look for those if they end up being something that should
365 // be supported for nanoapps.
366 for (size_t i = 0; i < mNumSectionHeaders; ++i) {
367 const char *name = getSectionHeaderName(mSectionHeadersPtr[i].sh_name);
368 if (strncmp(name, kInitArrayName, strlen(kInitArrayName)) == 0) {
369 LOGV("Invoking init function");
370 uintptr_t initArray = reinterpret_cast<uintptr_t>(
371 mLoadBias + mSectionHeadersPtr[i].sh_addr);
372 uintptr_t offset = 0;
373 while (offset < mSectionHeadersPtr[i].sh_size) {
374 ElfAddr *funcPtr = reinterpret_cast<ElfAddr *>(initArray + offset);
375 uintptr_t initFunction = reinterpret_cast<uintptr_t>(*funcPtr);
376 ((void (*)())initFunction)();
377 offset += sizeof(initFunction);
378 if (gStaticInitFailure) {
379 success = false;
380 break;
381 }
382 }
383 break;
384 }
385 }
386
387 //! Reset global state so it doesn't leak into the next load.
388 gCurrentlyLoadingNanoapp = nullptr;
389 gStaticInitFailure = false;
390 return success;
391 }
392
roundDownToAlign(uintptr_t virtualAddr)393 uintptr_t NanoappLoader::roundDownToAlign(uintptr_t virtualAddr) {
394 return virtualAddr & -kBinaryAlignment;
395 }
396
freeAllocatedData()397 void NanoappLoader::freeAllocatedData() {
398 if (mIsTcmBinary) {
399 nanoappBinaryFree(mMapping);
400 } else {
401 nanoappBinaryDramFree(mMapping);
402 }
403 memoryFreeDram(mSectionHeadersPtr);
404 memoryFreeDram(mSectionNamesPtr);
405 memoryFreeDram(mSymbolTablePtr);
406 memoryFreeDram(mStringTablePtr);
407 }
408
verifyElfHeader()409 bool NanoappLoader::verifyElfHeader() {
410 bool success = false;
411 ElfHeader *elfHeader = getElfHeader();
412 if (elfHeader != nullptr && (elfHeader->e_ident[EI_MAG0] == ELFMAG0) &&
413 (elfHeader->e_ident[EI_MAG1] == ELFMAG1) &&
414 (elfHeader->e_ident[EI_MAG2] == ELFMAG2) &&
415 (elfHeader->e_ident[EI_MAG3] == ELFMAG3) &&
416 (elfHeader->e_ehsize == sizeof(ElfHeader)) &&
417 (elfHeader->e_phentsize == sizeof(ProgramHeader)) &&
418 (elfHeader->e_shentsize == sizeof(SectionHeader)) &&
419 (elfHeader->e_shstrndx < elfHeader->e_shnum) &&
420 (elfHeader->e_version == EV_CURRENT) &&
421 (elfHeader->e_machine == CHRE_LOADER_ARCH) &&
422 (elfHeader->e_type == ET_DYN)) {
423 success = true;
424 }
425 return success;
426 }
427
verifyProgramHeaders()428 bool NanoappLoader::verifyProgramHeaders() {
429 // This is a minimal check for now -
430 // there should be at least one load segment.
431 bool success = false;
432 for (size_t i = 0; i < getProgramHeaderArraySize(); ++i) {
433 if (getProgramHeaderArray()[i].p_type == PT_LOAD) {
434 success = true;
435 break;
436 }
437 }
438 return success;
439 }
440
getSectionHeaderName(size_t headerOffset)441 const char *NanoappLoader::getSectionHeaderName(size_t headerOffset) {
442 if (headerOffset == 0) {
443 return "";
444 }
445
446 return &mSectionNamesPtr[headerOffset];
447 }
448
getSectionHeader(const char * headerName)449 NanoappLoader::SectionHeader *NanoappLoader::getSectionHeader(
450 const char *headerName) {
451 SectionHeader *rv = nullptr;
452 for (size_t i = 0; i < mNumSectionHeaders; ++i) {
453 const char *name = getSectionHeaderName(mSectionHeadersPtr[i].sh_name);
454 if (strncmp(name, headerName, strlen(headerName)) == 0) {
455 rv = &mSectionHeadersPtr[i];
456 break;
457 }
458 }
459 return rv;
460 }
461
getElfHeader()462 ElfHeader *NanoappLoader::getElfHeader() {
463 return reinterpret_cast<ElfHeader *>(mBinary);
464 }
465
getProgramHeaderArray()466 ProgramHeader *NanoappLoader::getProgramHeaderArray() {
467 ElfHeader *elfHeader = getElfHeader();
468 ProgramHeader *programHeader = nullptr;
469 if (elfHeader != nullptr) {
470 programHeader =
471 reinterpret_cast<ProgramHeader *>(mBinary + elfHeader->e_phoff);
472 }
473
474 return programHeader;
475 }
476
getProgramHeaderArraySize()477 size_t NanoappLoader::getProgramHeaderArraySize() {
478 ElfHeader *elfHeader = getElfHeader();
479 size_t arraySize = 0;
480 if (elfHeader != nullptr) {
481 arraySize = elfHeader->e_phnum;
482 }
483
484 return arraySize;
485 }
486
getDynamicStringTable()487 char *NanoappLoader::getDynamicStringTable() {
488 char *table = nullptr;
489
490 SectionHeader *dynamicStringTablePtr = getSectionHeader(".dynstr");
491 CHRE_ASSERT(dynamicStringTablePtr != nullptr);
492 if (dynamicStringTablePtr != nullptr && mBinary != nullptr) {
493 table =
494 reinterpret_cast<char *>(mBinary + dynamicStringTablePtr->sh_offset);
495 }
496
497 return table;
498 }
499
getDynamicSymbolTable()500 uint8_t *NanoappLoader::getDynamicSymbolTable() {
501 uint8_t *table = nullptr;
502
503 SectionHeader *dynamicSymbolTablePtr = getSectionHeader(".dynsym");
504 CHRE_ASSERT(dynamicSymbolTablePtr != nullptr);
505 if (dynamicSymbolTablePtr != nullptr && mBinary != nullptr) {
506 table = (mBinary + dynamicSymbolTablePtr->sh_offset);
507 }
508
509 return table;
510 }
511
getDynamicSymbolTableSize()512 size_t NanoappLoader::getDynamicSymbolTableSize() {
513 size_t tableSize = 0;
514
515 SectionHeader *dynamicSymbolTablePtr = getSectionHeader(".dynsym");
516 CHRE_ASSERT(dynamicSymbolTablePtr != nullptr);
517 if (dynamicSymbolTablePtr != nullptr) {
518 tableSize = dynamicSymbolTablePtr->sh_size;
519 }
520
521 return tableSize;
522 }
523
verifySectionHeaders()524 bool NanoappLoader::verifySectionHeaders() {
525 bool foundSymbolTableHeader = false;
526 bool foundStringTableHeader = false;
527
528 for (size_t i = 0; i < mNumSectionHeaders; ++i) {
529 const char *name = getSectionHeaderName(mSectionHeadersPtr[i].sh_name);
530
531 if (strncmp(name, kSymTableName, strlen(kSymTableName)) == 0) {
532 foundSymbolTableHeader = true;
533 } else if (strncmp(name, kStrTableName, strlen(kStrTableName)) == 0) {
534 foundStringTableHeader = true;
535 }
536 }
537
538 return foundSymbolTableHeader && foundStringTableHeader;
539 }
540
copyAndVerifyHeaders()541 bool NanoappLoader::copyAndVerifyHeaders() {
542 size_t offset = 0;
543 bool success = false;
544 uint8_t *pDataBytes = mBinary;
545
546 // Verify the ELF Header
547 ElfHeader *elfHeader = getElfHeader();
548 success = verifyElfHeader();
549
550 LOGV("Verified ELF header %d", success);
551
552 // Verify Program Headers
553 if (success) {
554 success = verifyProgramHeaders();
555 }
556
557 LOGV("Verified Program headers %d", success);
558
559 // Load Section Headers
560 if (success) {
561 offset = elfHeader->e_shoff;
562 size_t sectionHeaderSizeBytes = sizeof(SectionHeader) * elfHeader->e_shnum;
563 mSectionHeadersPtr =
564 static_cast<SectionHeader *>(memoryAllocDram(sectionHeaderSizeBytes));
565 if (mSectionHeadersPtr == nullptr) {
566 success = false;
567 LOG_OOM();
568 } else {
569 memcpy(mSectionHeadersPtr, (pDataBytes + offset), sectionHeaderSizeBytes);
570 mNumSectionHeaders = elfHeader->e_shnum;
571 }
572 }
573
574 LOGV("Loaded section headers %d", success);
575
576 // Load section header names
577 if (success) {
578 SectionHeader &stringSection = mSectionHeadersPtr[elfHeader->e_shstrndx];
579 size_t sectionSize = stringSection.sh_size;
580 mSectionNamesPtr = static_cast<char *>(memoryAllocDram(sectionSize));
581 if (mSectionNamesPtr == nullptr) {
582 LOG_OOM();
583 success = false;
584 } else {
585 memcpy(mSectionNamesPtr, mBinary + stringSection.sh_offset, sectionSize);
586 }
587 }
588
589 LOGV("Loaded section header names %d", success);
590
591 success = verifySectionHeaders();
592 LOGV("Verified Section headers %d", success);
593
594 // Load symbol table
595 if (success) {
596 SectionHeader *symbolTableHeader = getSectionHeader(kSymTableName);
597 mSymbolTableSize = symbolTableHeader->sh_size;
598 if (mSymbolTableSize == 0) {
599 LOGE("No symbols to resolve");
600 success = false;
601 } else {
602 mSymbolTablePtr =
603 static_cast<uint8_t *>(memoryAllocDram(mSymbolTableSize));
604 if (mSymbolTablePtr == nullptr) {
605 LOG_OOM();
606 success = false;
607 } else {
608 memcpy(mSymbolTablePtr, mBinary + symbolTableHeader->sh_offset,
609 mSymbolTableSize);
610 }
611 }
612 }
613
614 LOGV("Loaded symbol table %d", success);
615
616 // Load string table
617 if (success) {
618 SectionHeader *stringTableHeader = getSectionHeader(kStrTableName);
619 size_t stringTableSize = stringTableHeader->sh_size;
620 if (mSymbolTableSize == 0) {
621 LOGE("No string table corresponding to symbols");
622 success = false;
623 } else {
624 mStringTablePtr = static_cast<char *>(memoryAllocDram(stringTableSize));
625 if (mStringTablePtr == nullptr) {
626 LOG_OOM();
627 success = false;
628 } else {
629 memcpy(mStringTablePtr, mBinary + stringTableHeader->sh_offset,
630 stringTableSize);
631 }
632 }
633 }
634
635 LOGV("Loaded string table %d", success);
636
637 return success;
638 }
639
createMappings()640 bool NanoappLoader::createMappings() {
641 // ELF needs pt_load segments to be in contiguous ascending order of
642 // virtual addresses. So the first and last segs can be used to
643 // calculate the entire address span of the image.
644 ElfHeader *elfHeader = getElfHeader();
645 ProgramHeader *programHeaderArray = getProgramHeaderArray();
646 size_t numProgramHeaders = getProgramHeaderArraySize();
647 const ProgramHeader *first = &programHeaderArray[0];
648 const ProgramHeader *last = &programHeaderArray[numProgramHeaders - 1];
649
650 // Find first load segment
651 while (first->p_type != PT_LOAD && first <= last) {
652 ++first;
653 }
654
655 bool success = false;
656 if (first->p_type != PT_LOAD) {
657 LOGE("Unable to find any load segments in the binary");
658 } else {
659 // Verify that the first load segment has a program header
660 // first byte of a valid load segment can't be greater than the
661 // program header offset
662 bool valid =
663 (first->p_offset < elfHeader->e_phoff) &&
664 (first->p_filesz >
665 (elfHeader->e_phoff + (numProgramHeaders * sizeof(ProgramHeader))));
666 if (!valid) {
667 LOGE("Load segment program header validation failed");
668 } else {
669 // Get the last load segment
670 while (last > first && last->p_type != PT_LOAD) --last;
671
672 size_t memorySpan = last->p_vaddr + last->p_memsz - first->p_vaddr;
673 LOGV("Nanoapp image Memory Span: %u", memorySpan);
674
675 if (mIsTcmBinary) {
676 mMapping = static_cast<uint8_t *>(
677 nanoappBinaryAlloc(memorySpan, kBinaryAlignment));
678 } else {
679 mMapping = static_cast<uint8_t *>(
680 nanoappBinaryDramAlloc(memorySpan, kBinaryAlignment));
681 }
682
683 if (mMapping == nullptr) {
684 LOG_OOM();
685 } else {
686 LOGV("Starting location of mappings %p", mMapping);
687
688 // Calculate the load bias using the first load segment.
689 uintptr_t adjustedFirstLoadSegAddr = roundDownToAlign(first->p_vaddr);
690 mLoadBias =
691 reinterpret_cast<uintptr_t>(mMapping) - adjustedFirstLoadSegAddr;
692 LOGV("Load bias is %" PRIu32, mLoadBias);
693
694 success = true;
695 }
696 }
697 }
698
699 if (success) {
700 // Map the remaining segments
701 for (const ProgramHeader *ph = first; ph <= last; ++ph) {
702 if (ph->p_type == PT_LOAD) {
703 ElfAddr segStart = ph->p_vaddr + mLoadBias;
704 void *startPage = reinterpret_cast<void *>(segStart);
705 void *binaryStartPage = mBinary + ph->p_offset;
706 size_t segmentLen = ph->p_filesz;
707
708 LOGV("Mapping start page %p from %p with length %zu", startPage,
709 binaryStartPage, segmentLen);
710 memcpy(startPage, binaryStartPage, segmentLen);
711 mapBss(ph);
712 } else {
713 LOGE("Non-load segment found between load segments");
714 success = false;
715 break;
716 }
717 }
718 }
719
720 return success;
721 }
722
getDataName(size_t posInSymbolTable)723 const char *NanoappLoader::getDataName(size_t posInSymbolTable) {
724 size_t sectionSize = getDynamicSymbolTableSize();
725 uint8_t *dynamicSymbolTable = getDynamicSymbolTable();
726 size_t numElements = sectionSize / sizeof(ElfSym);
727 CHRE_ASSERT(posInSymbolTable < numElements);
728 char *dataName = nullptr;
729 if (posInSymbolTable < numElements) {
730 ElfSym *sym = reinterpret_cast<ElfSym *>(
731 &dynamicSymbolTable[posInSymbolTable * sizeof(ElfSym)]);
732 dataName = &getDynamicStringTable()[sym->st_name];
733 }
734 return dataName;
735 }
736
resolveData(size_t posInSymbolTable)737 void *NanoappLoader::resolveData(size_t posInSymbolTable) {
738 const char *dataName = getDataName(posInSymbolTable);
739
740 if (dataName != nullptr) {
741 LOGV("Resolving %s", dataName);
742 return findExportedSymbol(dataName);
743 }
744
745 return nullptr;
746 }
747
getDynamicHeader()748 NanoappLoader::DynamicHeader *NanoappLoader::getDynamicHeader() {
749 DynamicHeader *dyn = nullptr;
750 ProgramHeader *programHeaders = getProgramHeaderArray();
751 for (size_t i = 0; i < getProgramHeaderArraySize(); ++i) {
752 if (programHeaders[i].p_type == PT_DYNAMIC) {
753 dyn = reinterpret_cast<DynamicHeader *>(programHeaders[i].p_offset +
754 mBinary);
755 break;
756 }
757 }
758 return dyn;
759 }
760
getFirstRoSegHeader()761 NanoappLoader::ProgramHeader *NanoappLoader::getFirstRoSegHeader() {
762 // return the first read only segment found
763 ProgramHeader *ro = nullptr;
764 ProgramHeader *programHeaders = getProgramHeaderArray();
765 for (size_t i = 0; i < getProgramHeaderArraySize(); ++i) {
766 if (!(programHeaders[i].p_flags & PF_W)) {
767 ro = &programHeaders[i];
768 break;
769 }
770 }
771 return ro;
772 }
773
getDynEntry(DynamicHeader * dyn,int field)774 NanoappLoader::ElfWord NanoappLoader::getDynEntry(DynamicHeader *dyn,
775 int field) {
776 ElfWord rv = 0;
777
778 while (dyn->d_tag != DT_NULL) {
779 if (dyn->d_tag == field) {
780 rv = dyn->d_un.d_val;
781 break;
782 }
783 ++dyn;
784 }
785
786 return rv;
787 }
788
fixRelocations()789 bool NanoappLoader::fixRelocations() {
790 ElfAddr *addr;
791 DynamicHeader *dyn = getDynamicHeader();
792 ProgramHeader *roSeg = getFirstRoSegHeader();
793
794 bool success = false;
795 if ((dyn == nullptr) || (roSeg == nullptr)) {
796 LOGE("Mandatory headers missing from shared object, aborting load");
797 } else if (getDynEntry(dyn, DT_RELA) != 0) {
798 LOGE("Elf binaries with a DT_RELA dynamic entry are unsupported");
799 } else {
800 ElfRel *reloc =
801 reinterpret_cast<ElfRel *>(mBinary + getDynEntry(dyn, DT_REL));
802 size_t relocSize = getDynEntry(dyn, DT_RELSZ);
803 size_t nRelocs = relocSize / sizeof(ElfRel);
804 LOGV("Relocation %zu entries in DT_REL table", nRelocs);
805
806 size_t i;
807 for (i = 0; i < nRelocs; ++i) {
808 ElfRel *curr = &reloc[i];
809 int relocType = ELFW_R_TYPE(curr->r_info);
810 switch (relocType) {
811 case R_ARM_RELATIVE:
812 LOGV("Resolving ARM_RELATIVE at offset %" PRIx32, curr->r_offset);
813 addr = reinterpret_cast<ElfAddr *>(mMapping + curr->r_offset);
814 // TODO: When we move to DRAM allocations, we need to check if the
815 // above address is in a Read-Only section of memory, and give it
816 // temporary write permission if that is the case.
817 *addr += reinterpret_cast<uintptr_t>(mMapping);
818 break;
819
820 case R_ARM_ABS32: {
821 LOGV("Resolving ARM_ABS32 at offset %" PRIx32, curr->r_offset);
822 addr = reinterpret_cast<ElfAddr *>(mMapping + curr->r_offset);
823 size_t posInSymbolTable = ELFW_R_SYM(curr->r_info);
824 auto *dynamicSymbolTable =
825 reinterpret_cast<ElfSym *>(getDynamicSymbolTable());
826 ElfSym *sym = &dynamicSymbolTable[posInSymbolTable];
827 *addr = reinterpret_cast<uintptr_t>(mMapping + sym->st_value);
828
829 break;
830 }
831
832 case R_ARM_GLOB_DAT: {
833 LOGV("Resolving type ARM_GLOB_DAT at offset %" PRIx32,
834 curr->r_offset);
835 addr = reinterpret_cast<ElfAddr *>(mMapping + curr->r_offset);
836 size_t posInSymbolTable = ELFW_R_SYM(curr->r_info);
837 void *resolved = resolveData(posInSymbolTable);
838 if (resolved == nullptr) {
839 LOGV("Failed to resolve global symbol(%d) at offset 0x%x", i,
840 curr->r_offset);
841 return false;
842 }
843 // TODO: When we move to DRAM allocations, we need to check if the
844 // above address is in a Read-Only section of memory, and give it
845 // temporary write permission if that is the case.
846 *addr = reinterpret_cast<ElfAddr>(resolved);
847 break;
848 }
849
850 case R_ARM_COPY:
851 LOGE("R_ARM_COPY is an invalid relocation for shared libraries");
852 break;
853 default:
854 LOGE("Invalid relocation type %u", relocType);
855 break;
856 }
857 }
858
859 if (i != nRelocs) {
860 LOGE("Unable to resolve all symbols in the binary");
861 } else {
862 success = true;
863 }
864 }
865
866 return success;
867 }
868
resolveGot()869 bool NanoappLoader::resolveGot() {
870 ElfAddr *addr;
871 ElfRel *reloc = reinterpret_cast<ElfRel *>(
872 mMapping + getDynEntry(getDynamicHeader(), DT_JMPREL));
873 size_t relocSize = getDynEntry(getDynamicHeader(), DT_PLTRELSZ);
874 size_t nRelocs = relocSize / sizeof(ElfRel);
875 LOGV("Resolving GOT with %zu relocations", nRelocs);
876
877 for (size_t i = 0; i < nRelocs; ++i) {
878 ElfRel *curr = &reloc[i];
879 int relocType = ELFW_R_TYPE(curr->r_info);
880
881 switch (relocType) {
882 case R_ARM_JUMP_SLOT: {
883 LOGV("Resolving ARM_JUMP_SLOT at offset %" PRIx32, curr->r_offset);
884 addr = reinterpret_cast<ElfAddr *>(mMapping + curr->r_offset);
885 size_t posInSymbolTable = ELFW_R_SYM(curr->r_info);
886 void *resolved = resolveData(posInSymbolTable);
887 if (resolved == nullptr) {
888 LOGV("Failed to resolve symbol(%d) at offset 0x%x", i,
889 curr->r_offset);
890 return false;
891 }
892 *addr = reinterpret_cast<ElfAddr>(resolved);
893 break;
894 }
895
896 default:
897 LOGE("Unsupported relocation type: %u for symbol %s", relocType,
898 getDataName(ELFW_R_SYM(curr->r_info)));
899 return false;
900 }
901 }
902 return true;
903 }
904
callAtexitFunctions()905 void NanoappLoader::callAtexitFunctions() {
906 while (!mAtexitFunctions.empty()) {
907 LOGV("Calling atexit at %p", mAtexitFunctions.back());
908 mAtexitFunctions.back()();
909 mAtexitFunctions.pop_back();
910 }
911 }
912
callTerminatorArray()913 void NanoappLoader::callTerminatorArray() {
914 for (size_t i = 0; i < mNumSectionHeaders; ++i) {
915 const char *name = getSectionHeaderName(mSectionHeadersPtr[i].sh_name);
916 if (strncmp(name, kFiniArrayName, strlen(kFiniArrayName)) == 0) {
917 uintptr_t finiArray = reinterpret_cast<uintptr_t>(
918 mLoadBias + mSectionHeadersPtr[i].sh_addr);
919 uintptr_t offset = 0;
920 while (offset < mSectionHeadersPtr[i].sh_size) {
921 ElfAddr *funcPtr = reinterpret_cast<ElfAddr *>(finiArray + offset);
922 uintptr_t finiFunction = reinterpret_cast<uintptr_t>(*funcPtr);
923 ((void (*)())finiFunction)();
924 offset += sizeof(finiFunction);
925 }
926 break;
927 }
928 }
929 }
930
931 } // namespace chre
932