flipper_applicaiton_i.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477
  1. #include "flipper_application_i.h"
  2. #include <furi.h>
  3. #define TAG "fapp-i"
  4. #define RESOLVER_THREAD_YIELD_STEP 30
  5. #define IS_FLAGS_SET(v, m) ((v & m) == m)
  6. #define SECTION_OFFSET(e, n) (e->section_table + n * sizeof(Elf32_Shdr))
  7. #define SYMBOL_OFFSET(e, n) (e->_table + n * sizeof(Elf32_Shdr))
  8. bool flipper_application_load_elf_headers(FlipperApplication* e, const char* path) {
  9. Elf32_Ehdr h;
  10. Elf32_Shdr sH;
  11. if(!storage_file_open(e->fd, path, FSAM_READ, FSOM_OPEN_EXISTING) ||
  12. !storage_file_seek(e->fd, 0, true) ||
  13. storage_file_read(e->fd, &h, sizeof(h)) != sizeof(h) ||
  14. !storage_file_seek(e->fd, h.e_shoff + h.e_shstrndx * sizeof(sH), true) ||
  15. storage_file_read(e->fd, &sH, sizeof(Elf32_Shdr)) != sizeof(Elf32_Shdr)) {
  16. return false;
  17. }
  18. e->entry = h.e_entry;
  19. e->sections = h.e_shnum;
  20. e->section_table = h.e_shoff;
  21. e->section_table_strings = sH.sh_offset;
  22. return true;
  23. }
  24. static bool flipper_application_load_metadata(FlipperApplication* e, Elf32_Shdr* sh) {
  25. if(sh->sh_size < sizeof(e->manifest)) {
  26. return false;
  27. }
  28. return storage_file_seek(e->fd, sh->sh_offset, true) &&
  29. storage_file_read(e->fd, &e->manifest, sh->sh_size) == sh->sh_size;
  30. }
  31. static bool flipper_application_load_debug_link(FlipperApplication* e, Elf32_Shdr* sh) {
  32. e->state.debug_link_size = sh->sh_size;
  33. e->state.debug_link = malloc(sh->sh_size);
  34. return storage_file_seek(e->fd, sh->sh_offset, true) &&
  35. storage_file_read(e->fd, e->state.debug_link, sh->sh_size) == sh->sh_size;
  36. }
  37. static FindFlags_t flipper_application_preload_section(
  38. FlipperApplication* e,
  39. Elf32_Shdr* sh,
  40. const char* name,
  41. int n) {
  42. FURI_LOG_D(TAG, "Processing: %s", name);
  43. const struct {
  44. const char* name;
  45. uint16_t* ptr_section_idx;
  46. FindFlags_t flags;
  47. } lookup_sections[] = {
  48. {".text", &e->text.sec_idx, FoundText},
  49. {".rodata", &e->rodata.sec_idx, FoundRodata},
  50. {".data", &e->data.sec_idx, FoundData},
  51. {".bss", &e->bss.sec_idx, FoundBss},
  52. {".rel.text", &e->text.rel_sec_idx, FoundRelText},
  53. {".rel.rodata", &e->rodata.rel_sec_idx, FoundRelRodata},
  54. {".rel.data", &e->data.rel_sec_idx, FoundRelData},
  55. };
  56. for(size_t i = 0; i < COUNT_OF(lookup_sections); i++) {
  57. if(strcmp(name, lookup_sections[i].name) == 0) {
  58. *lookup_sections[i].ptr_section_idx = n;
  59. return lookup_sections[i].flags;
  60. }
  61. }
  62. if(strcmp(name, ".symtab") == 0) {
  63. e->symbol_table = sh->sh_offset;
  64. e->symbol_count = sh->sh_size / sizeof(Elf32_Sym);
  65. return FoundSymTab;
  66. } else if(strcmp(name, ".strtab") == 0) {
  67. e->symbol_table_strings = sh->sh_offset;
  68. return FoundStrTab;
  69. } else if(strcmp(name, ".fapmeta") == 0) {
  70. // Load metadata immediately
  71. if(flipper_application_load_metadata(e, sh)) {
  72. return FoundFappManifest;
  73. }
  74. } else if(strcmp(name, ".gnu_debuglink") == 0) {
  75. if(flipper_application_load_debug_link(e, sh)) {
  76. return FoundDebugLink;
  77. }
  78. }
  79. return FoundERROR;
  80. }
  81. static bool
  82. read_string_from_offset(FlipperApplication* e, off_t offset, char* buffer, size_t buffer_size) {
  83. bool success = false;
  84. off_t old = storage_file_tell(e->fd);
  85. if(storage_file_seek(e->fd, offset, true) &&
  86. (storage_file_read(e->fd, buffer, buffer_size) == buffer_size)) {
  87. success = true;
  88. }
  89. storage_file_seek(e->fd, old, true);
  90. return success;
  91. }
  92. static bool read_section_name(FlipperApplication* e, off_t off, char* buf, size_t max) {
  93. return read_string_from_offset(e, e->section_table_strings + off, buf, max);
  94. }
  95. static bool read_symbol_name(FlipperApplication* e, off_t off, char* buf, size_t max) {
  96. return read_string_from_offset(e, e->symbol_table_strings + off, buf, max);
  97. }
  98. static bool read_section_header(FlipperApplication* e, int n, Elf32_Shdr* h) {
  99. off_t offset = SECTION_OFFSET(e, n);
  100. return storage_file_seek(e->fd, offset, true) &&
  101. storage_file_read(e->fd, h, sizeof(Elf32_Shdr)) == sizeof(Elf32_Shdr);
  102. }
  103. static bool read_section(FlipperApplication* e, int n, Elf32_Shdr* h, char* name, size_t nlen) {
  104. if(!read_section_header(e, n, h)) {
  105. return false;
  106. }
  107. if(!h->sh_name) {
  108. return true;
  109. }
  110. return read_section_name(e, h->sh_name, name, nlen);
  111. }
  112. bool flipper_application_load_section_table(FlipperApplication* e) {
  113. furi_check(e->state.mmap_entry_count == 0);
  114. size_t n;
  115. FindFlags_t found = FoundERROR;
  116. FURI_LOG_D(TAG, "Scan ELF indexs...");
  117. for(n = 1; n < e->sections; n++) {
  118. Elf32_Shdr section_header;
  119. char name[33] = {0};
  120. if(!read_section_header(e, n, &section_header)) {
  121. return false;
  122. }
  123. if(section_header.sh_name &&
  124. !read_section_name(e, section_header.sh_name, name, sizeof(name))) {
  125. return false;
  126. }
  127. FURI_LOG_T(TAG, "Examining section %d %s", n, name);
  128. FindFlags_t section_flags =
  129. flipper_application_preload_section(e, &section_header, name, n);
  130. found |= section_flags;
  131. if((section_flags & FoundGdbSection) != 0) {
  132. e->state.mmap_entry_count++;
  133. }
  134. if(IS_FLAGS_SET(found, FoundAll)) {
  135. return true;
  136. }
  137. }
  138. FURI_LOG_D(TAG, "Load symbols done");
  139. return IS_FLAGS_SET(found, FoundValid);
  140. }
  141. static const char* type_to_str(int symt) {
  142. #define STRCASE(name) \
  143. case name: \
  144. return #name;
  145. switch(symt) {
  146. STRCASE(R_ARM_NONE)
  147. STRCASE(R_ARM_ABS32)
  148. STRCASE(R_ARM_THM_PC22)
  149. STRCASE(R_ARM_THM_JUMP24)
  150. default:
  151. return "R_<unknow>";
  152. }
  153. #undef STRCASE
  154. }
  155. static void relocate_jmp_call(Elf32_Addr relAddr, int type, Elf32_Addr symAddr) {
  156. UNUSED(type);
  157. uint16_t upper_insn = ((uint16_t*)relAddr)[0];
  158. uint16_t lower_insn = ((uint16_t*)relAddr)[1];
  159. uint32_t S = (upper_insn >> 10) & 1;
  160. uint32_t J1 = (lower_insn >> 13) & 1;
  161. uint32_t J2 = (lower_insn >> 11) & 1;
  162. int32_t offset = (S << 24) | /* S -> offset[24] */
  163. ((~(J1 ^ S) & 1) << 23) | /* J1 -> offset[23] */
  164. ((~(J2 ^ S) & 1) << 22) | /* J2 -> offset[22] */
  165. ((upper_insn & 0x03ff) << 12) | /* imm10 -> offset[12:21] */
  166. ((lower_insn & 0x07ff) << 1); /* imm11 -> offset[1:11] */
  167. if(offset & 0x01000000) offset -= 0x02000000;
  168. offset += symAddr - relAddr;
  169. S = (offset >> 24) & 1;
  170. J1 = S ^ (~(offset >> 23) & 1);
  171. J2 = S ^ (~(offset >> 22) & 1);
  172. upper_insn = ((upper_insn & 0xf800) | (S << 10) | ((offset >> 12) & 0x03ff));
  173. ((uint16_t*)relAddr)[0] = upper_insn;
  174. lower_insn = ((lower_insn & 0xd000) | (J1 << 13) | (J2 << 11) | ((offset >> 1) & 0x07ff));
  175. ((uint16_t*)relAddr)[1] = lower_insn;
  176. }
  177. static bool relocate_symbol(Elf32_Addr relAddr, int type, Elf32_Addr symAddr) {
  178. switch(type) {
  179. case R_ARM_ABS32:
  180. *((uint32_t*)relAddr) += symAddr;
  181. FURI_LOG_D(TAG, " R_ARM_ABS32 relocated is 0x%08X", (unsigned int)*((uint32_t*)relAddr));
  182. break;
  183. case R_ARM_THM_PC22:
  184. case R_ARM_THM_JUMP24:
  185. relocate_jmp_call(relAddr, type, symAddr);
  186. FURI_LOG_D(
  187. TAG, " R_ARM_THM_CALL/JMP relocated is 0x%08X", (unsigned int)*((uint32_t*)relAddr));
  188. break;
  189. default:
  190. FURI_LOG_D(TAG, " Undefined relocation %d", type);
  191. return false;
  192. }
  193. return true;
  194. }
  195. static ELFSection_t* section_of(FlipperApplication* e, int index) {
  196. if(e->text.sec_idx == index) {
  197. return &e->text;
  198. } else if(e->data.sec_idx == index) {
  199. return &e->data;
  200. } else if(e->bss.sec_idx == index) {
  201. return &e->bss;
  202. } else if(e->rodata.sec_idx == index) {
  203. return &e->rodata;
  204. }
  205. return NULL;
  206. }
  207. static Elf32_Addr address_of(FlipperApplication* e, Elf32_Sym* sym, const char* sName) {
  208. if(sym->st_shndx == SHN_UNDEF) {
  209. Elf32_Addr addr = 0;
  210. if(e->api_interface->resolver_callback(sName, &addr)) {
  211. return addr;
  212. }
  213. } else {
  214. ELFSection_t* symSec = section_of(e, sym->st_shndx);
  215. if(symSec) {
  216. return ((Elf32_Addr)symSec->data) + sym->st_value;
  217. }
  218. }
  219. FURI_LOG_D(TAG, " Can not find address for symbol %s", sName);
  220. return ELF_INVALID_ADDRESS;
  221. }
  222. static bool read_symbol(FlipperApplication* e, int n, Elf32_Sym* sym, char* name, size_t nlen) {
  223. bool success = false;
  224. off_t old = storage_file_tell(e->fd);
  225. off_t pos = e->symbol_table + n * sizeof(Elf32_Sym);
  226. if(storage_file_seek(e->fd, pos, true) &&
  227. storage_file_read(e->fd, sym, sizeof(Elf32_Sym)) == sizeof(Elf32_Sym)) {
  228. if(sym->st_name)
  229. success = read_symbol_name(e, sym->st_name, name, nlen);
  230. else {
  231. Elf32_Shdr shdr;
  232. success = read_section(e, sym->st_shndx, &shdr, name, nlen);
  233. }
  234. }
  235. storage_file_seek(e->fd, old, true);
  236. return success;
  237. }
  238. static bool
  239. relocation_cache_get(RelocationAddressCache_t cache, int symEntry, Elf32_Addr* symAddr) {
  240. Elf32_Addr* addr = RelocationAddressCache_get(cache, symEntry);
  241. if(addr) {
  242. *symAddr = *addr;
  243. return true;
  244. } else {
  245. return false;
  246. }
  247. }
  248. static void
  249. relocation_cache_put(RelocationAddressCache_t cache, int symEntry, Elf32_Addr symAddr) {
  250. RelocationAddressCache_set_at(cache, symEntry, symAddr);
  251. }
  252. #define MAX_SYMBOL_NAME_LEN 128u
  253. static bool relocate(FlipperApplication* e, Elf32_Shdr* h, ELFSection_t* s) {
  254. if(s->data) {
  255. Elf32_Rel rel;
  256. size_t relEntries = h->sh_size / sizeof(rel);
  257. size_t relCount;
  258. (void)storage_file_seek(e->fd, h->sh_offset, true);
  259. FURI_LOG_D(TAG, " Offset Info Type Name");
  260. int relocate_result = true;
  261. char symbol_name[MAX_SYMBOL_NAME_LEN + 1] = {0};
  262. for(relCount = 0; relCount < relEntries; relCount++) {
  263. if(relCount % RESOLVER_THREAD_YIELD_STEP == 0) {
  264. FURI_LOG_D(TAG, " reloc YIELD");
  265. furi_delay_tick(1);
  266. }
  267. if(storage_file_read(e->fd, &rel, sizeof(Elf32_Rel)) != sizeof(Elf32_Rel)) {
  268. FURI_LOG_E(TAG, " reloc read fail");
  269. return false;
  270. }
  271. Elf32_Addr symAddr;
  272. int symEntry = ELF32_R_SYM(rel.r_info);
  273. int relType = ELF32_R_TYPE(rel.r_info);
  274. Elf32_Addr relAddr = ((Elf32_Addr)s->data) + rel.r_offset;
  275. if(!relocation_cache_get(e->relocation_cache, symEntry, &symAddr)) {
  276. Elf32_Sym sym;
  277. if(!read_symbol(e, symEntry, &sym, symbol_name, MAX_SYMBOL_NAME_LEN)) {
  278. FURI_LOG_E(TAG, " symbol read fail");
  279. return false;
  280. }
  281. FURI_LOG_D(
  282. TAG,
  283. " %08X %08X %-16s %s",
  284. (unsigned int)rel.r_offset,
  285. (unsigned int)rel.r_info,
  286. type_to_str(relType),
  287. symbol_name);
  288. symAddr = address_of(e, &sym, symbol_name);
  289. relocation_cache_put(e->relocation_cache, symEntry, symAddr);
  290. }
  291. if(symAddr != ELF_INVALID_ADDRESS) {
  292. FURI_LOG_D(
  293. TAG,
  294. " symAddr=%08X relAddr=%08X",
  295. (unsigned int)symAddr,
  296. (unsigned int)relAddr);
  297. if(!relocate_symbol(relAddr, relType, symAddr)) {
  298. relocate_result = false;
  299. }
  300. } else {
  301. FURI_LOG_D(TAG, " No symbol address of %s", symbol_name);
  302. relocate_result = false;
  303. }
  304. }
  305. return relocate_result;
  306. } else
  307. FURI_LOG_I(TAG, "Section not loaded");
  308. return false;
  309. }
  310. static bool flipper_application_load_section_data(FlipperApplication* e, ELFSection_t* s) {
  311. Elf32_Shdr section_header;
  312. if(s->sec_idx == 0) {
  313. FURI_LOG_I(TAG, "Section is not present");
  314. return true;
  315. }
  316. if(!read_section_header(e, s->sec_idx, &section_header)) {
  317. return false;
  318. }
  319. if(section_header.sh_size == 0) {
  320. FURI_LOG_I(TAG, "No data for section");
  321. return true;
  322. }
  323. s->data = aligned_malloc(section_header.sh_size, section_header.sh_addralign);
  324. // e->state.mmap_entry_count++;
  325. if(section_header.sh_type == SHT_NOBITS) {
  326. /* section is empty (.bss?) */
  327. /* no need to memset - allocator already did that */
  328. /* memset(s->data, 0, h->sh_size); */
  329. FURI_LOG_D(TAG, "0x%X", s->data);
  330. return true;
  331. }
  332. if((!storage_file_seek(e->fd, section_header.sh_offset, true)) ||
  333. (storage_file_read(e->fd, s->data, section_header.sh_size) != section_header.sh_size)) {
  334. FURI_LOG_E(TAG, " seek/read fail");
  335. flipper_application_free_section(s);
  336. return false;
  337. }
  338. FURI_LOG_D(TAG, "0x%X", s->data);
  339. return true;
  340. }
  341. static bool flipper_application_relocate_section(FlipperApplication* e, ELFSection_t* s) {
  342. Elf32_Shdr section_header;
  343. if(s->rel_sec_idx) {
  344. FURI_LOG_D(TAG, "Relocating section");
  345. if(read_section_header(e, s->rel_sec_idx, &section_header))
  346. return relocate(e, &section_header, s);
  347. else {
  348. FURI_LOG_E(TAG, "Error reading section header");
  349. return false;
  350. }
  351. } else
  352. FURI_LOG_D(TAG, "No relocation index"); /* Not an error */
  353. return true;
  354. }
  355. FlipperApplicationLoadStatus flipper_application_load_sections(FlipperApplication* e) {
  356. FlipperApplicationLoadStatus status = FlipperApplicationLoadStatusSuccess;
  357. RelocationAddressCache_init(e->relocation_cache);
  358. size_t start = furi_get_tick();
  359. struct {
  360. ELFSection_t* section;
  361. const char* name;
  362. } sections[] = {
  363. {&e->text, ".text"},
  364. {&e->rodata, ".rodata"},
  365. {&e->data, ".data"},
  366. {&e->bss, ".bss"},
  367. };
  368. for(size_t i = 0; i < COUNT_OF(sections); i++) {
  369. if(!flipper_application_load_section_data(e, sections[i].section)) {
  370. FURI_LOG_E(TAG, "Error loading section '%s'", sections[i].name);
  371. status = FlipperApplicationLoadStatusUnspecifiedError;
  372. }
  373. }
  374. if(status == FlipperApplicationLoadStatusSuccess) {
  375. for(size_t i = 0; i < COUNT_OF(sections); i++) {
  376. if(!flipper_application_relocate_section(e, sections[i].section)) {
  377. FURI_LOG_E(TAG, "Error relocating section '%s'", sections[i].name);
  378. status = FlipperApplicationLoadStatusMissingImports;
  379. }
  380. }
  381. }
  382. if(status == FlipperApplicationLoadStatusSuccess) {
  383. e->state.mmap_entries =
  384. malloc(sizeof(FlipperApplicationMemoryMapEntry) * e->state.mmap_entry_count);
  385. uint32_t mmap_entry_idx = 0;
  386. for(size_t i = 0; i < COUNT_OF(sections); i++) {
  387. const void* data_ptr = sections[i].section->data;
  388. if(data_ptr) {
  389. FURI_LOG_I(TAG, "0x%X %s", (uint32_t)data_ptr, sections[i].name);
  390. e->state.mmap_entries[mmap_entry_idx].address = (uint32_t)data_ptr;
  391. e->state.mmap_entries[mmap_entry_idx].name = sections[i].name;
  392. mmap_entry_idx++;
  393. }
  394. }
  395. furi_check(mmap_entry_idx == e->state.mmap_entry_count);
  396. /* Fixing up entry point */
  397. e->entry += (uint32_t)e->text.data;
  398. }
  399. FURI_LOG_D(TAG, "Relocation cache size: %u", RelocationAddressCache_size(e->relocation_cache));
  400. RelocationAddressCache_clear(e->relocation_cache);
  401. FURI_LOG_I(TAG, "Loaded in %ums", (size_t)(furi_get_tick() - start));
  402. return status;
  403. }
  404. void flipper_application_free_section(ELFSection_t* s) {
  405. if(s->data) {
  406. aligned_free(s->data);
  407. }
  408. s->data = NULL;
  409. }