#include /** * hello.c */ #include "rtthread.h" #include #include #include #include static appm_list_struct g_app_list = {0}; // 找到一个空的app结构体 static app_struct *appm_new(void) { if (g_app_list.used < APPM_LIST_MAXLEN) { for (int i = 0; i < APPM_LIST_MAXLEN; i++) { app_struct *ptr = &g_app_list.app[i]; if (ptr->exe_addr == 0) { g_app_list.used++; return ptr; } } } return 0; } static int appm_delete(app_struct *app) { if (app == 0) return -1; for (int i = 0; i < APPM_LIST_MAXLEN; i++) { app_struct *ptr = &g_app_list.app[i]; if (ptr == app) { memset(ptr, 0, sizeof(app_struct)); g_app_list.used--; return 0; } } return -1; } app_struct *appm_find(char *name) { for (int i = 0; i < APPM_LIST_MAXLEN; i++) { app_struct *ptr = &g_app_list.app[i]; if (strcmp(ptr->app_info->name, name) == 0) { return ptr; } } return 0; } app_struct *appm_get(int index) { if (index >= 0 && index < APPM_LIST_MAXLEN) { if (g_app_list.app[index].exe_addr) return &g_app_list.app[index]; else return 0; } return 0; } // 获取当前正在运行的app数目 int appm_get_running_num(void) { int ret = 0; for (int i = 0; i < APPM_LIST_MAXLEN; i++) { app_struct *ptr = &g_app_list.app[i]; if (ptr->run_state) ret++; } return ret; } /**elf 文件头和section表解析和检查***/ static int check_elf_head(app_struct *app) { if (app == 0) return -1; FILE *file_elf = app->file; if (file_elf == 0) return -1; int i = 0; int MagNum = 0; unsigned long file_size = 0; int sechnum = 0; uint32_t symsize = 0; uint32_t symoff = 0; uint32_t nSyms = 0, kk = 0; Elf32_Ehdr *Elf_header = malloc(sizeof(Elf32_Ehdr)); /*文件大小*/ fseek(file_elf, 0, SEEK_END); file_size = ftell(file_elf); fseek(file_elf, 0, SEEK_SET); rt_kprintf("file total size is:%ld bytes\r\n", file_size); fread(Elf_header, sizeof(Elf32_Ehdr), 1, file_elf); /**确认是否为elf格式**/ if ((Elf_header->e_ident[EI_MAG0] == ELFMAG0) && (Elf_header->e_ident[EI_MAG1] == ELFMAG1) && (Elf_header->e_ident[EI_MAG2] == ELFMAG2) && (Elf_header->e_ident[EI_MAG3] == ELFMAG3)) { rt_kprintf("This is ELF file!\r\n"); } else { rt_kprintf("NOT ELF file!\r\n"); free(Elf_header); return -1; } free(Elf_header); return 0; } // 计算load段大小 uint32_t calc_load_size(Elf32_Phdr *phdr, int phdr_num) { uint32_t start = 0; uint32_t stop = 0; for (int i = 0; i < phdr_num; i++) { if (phdr[i].p_type == PT_LOAD) { if (start > phdr[i].p_paddr) { start = phdr[i].p_paddr; } if (stop < phdr[i].p_paddr + phdr[i].p_memsz) { stop = phdr[i].p_paddr + phdr[i].p_memsz; } } } return stop - start; } /* 加载elf文件segment 到内存中 */ static int load_elf_2_mem(app_struct *app) { if (app == 0) return -1; Elf32_Phdr *phdr_head = NULL; Elf32_Ehdr *Elf_header = NULL; FILE *file1 = app->file; uint32_t rb; Elf_header = (Elf32_Ehdr *)malloc(sizeof(Elf32_Ehdr)); memset(Elf_header, 0, sizeof(Elf32_Ehdr)); fseek(file1, 0, SEEK_SET); rb = fread(Elf_header, sizeof(Elf32_Ehdr), 1, file1); /* 这里 Elf_header->e_phentsize 应该是== sizeof(Elf32_Phdr)*/ phdr_head = malloc(Elf_header->e_phentsize * Elf_header->e_phnum); fseek(file1, Elf_header->e_phoff, SEEK_SET); fread(phdr_head, Elf_header->e_phentsize, Elf_header->e_phnum, file1); // Elf_header->e_phnum一般等于1 uint32_t load_size = calc_load_size(phdr_head, Elf_header->e_phnum); rt_kprintf("Elf_header->e_phnum=%d, load_size=%d\n", Elf_header->e_phnum, load_size); if (app->exe_addr == 0) { app->exe_addr = malloc(load_size); memset(app->exe_addr, 0, load_size); } for (int i = 0; i < Elf_header->e_phnum; i++) { // 是程序节 // Keil编译的时候程序分为RO,RW,ZI,3个节,但是从运行时角度看来这3个节合并为一个段了 if (phdr_head[i].p_type == PT_LOAD) { // 内存 { fseek(file1, phdr_head[i].p_offset, SEEK_SET); if ((rb = fread(app->exe_addr + phdr_head[i].p_paddr, 1, phdr_head[i].p_filesz, file1)) != phdr_head[i].p_filesz) { rt_kprintf("function:%s,line:%d, read p_vaddr err!\r\n", __FUNCTION__, __LINE__); rt_kprintf("read 返回值%d\r\n", rb); rt_kprintf("read(file,ProHead->p_vaddr,ProHead->p_filesz) != " "ProHead->p_filesz %x p_filesz %d\r\n", phdr_head[i].p_vaddr, phdr_head[i].p_filesz); } rt_kprintf("%s:load=0X%08X,size=%d\r\n", __func__, (uint32_t)phdr_head[i].p_paddr, phdr_head[i].p_memsz); } } } // 找到入口函数地址 app->main = (int (*)(void *))((int)app->exe_addr + Elf_header->e_entry); // 程序描述信息地址 app->app_info = (app_info_struct *)app->exe_addr; rt_kprintf("%s:exe_addr=0X%08X,size=%d\r\n", __func__, (uint32_t)app->exe_addr, load_size); rt_kprintf("%s:main()=0X%08X\r\n", __func__, (uint32_t)app->main); rt_kprintf("%s:name=%s\r\n", __func__, app->app_info->name); // 这里求得RW区在程序映像中的偏移 Elf32_Shdr *sher_head = NULL; sher_head = malloc(Elf_header->e_shentsize * Elf_header->e_shnum); fseek(file1, Elf_header->e_shoff, SEEK_SET); fread(sher_head, Elf_header->e_shentsize, Elf_header->e_shnum, file1); for (int i = 0; i < Elf_header->e_shnum; i++) { if ((sher_head[i].sh_type == SHT_PROGBITS) && (sher_head[i].sh_flags == (SHF_ALLOC | SHF_EXECINSTR))) { app->ro_size = sher_head[i].sh_size; break; } } free(sher_head); free(Elf_header); free(phdr_head); return 0; } // 关闭app文件 static void app_close(app_struct *app) { if (app == 0) return; if (app->file) fclose(app->file); } // 打开app文件 static int app_open(app_struct *app, char *path) { if (app == 0) return -1; app->file = fopen(path, "rb"); if (app->file) { return 0; } else return -1; } // 从文件中获取app的名称 // name,用于保存文件名的数组,长度必须不小于APP_INFO_NAME_MAXLEN // 返回正数成功,0失败,正数代表程序的类型 int app_get_name_from_file(char *path, char *name) { if (path == 0) return 0; if (name == 0) return 0; Elf32_Phdr *phdr_head = NULL; Elf32_Ehdr *Elf_header = NULL; FILE *file1 = fopen(path, "rb"); uint32_t rb; if (file1 == 0) return 0; Elf_header = (Elf32_Ehdr *)malloc(sizeof(Elf32_Ehdr)); memset(Elf_header, 0, sizeof(Elf32_Ehdr)); fseek(file1, 0, SEEK_SET); rb = fread(Elf_header, sizeof(Elf32_Ehdr), 1, file1); /* 这里 Elf_header->e_phentsize 应该是== sizeof(Elf32_Phdr)*/ phdr_head = malloc(Elf_header->e_phentsize * Elf_header->e_phnum); fseek(file1, Elf_header->e_phoff, SEEK_SET); fread(phdr_head, Elf_header->e_phentsize, Elf_header->e_phnum, file1); // Elf_header->e_phnum一般等于1 for (int i = 0; i < Elf_header->e_phnum; i++) { // 是程序节 // Keil编译的时候程序分为RO,RW,ZI,3个节,但是从运行时角度看来这3个节合并为一个段了 if (phdr_head[i].p_type == PT_LOAD) { fseek(file1, phdr_head[i].p_offset, SEEK_SET); if ((rb = fread(name, 1, APP_INFO_NAME_MAXLEN, file1)) == APP_INFO_NAME_MAXLEN) { int app_type = 0; fread(&app_type, 1, sizeof(int), file1); fclose(file1); free(Elf_header); free(phdr_head); return app_type; } } } fclose(file1); free(Elf_header); free(phdr_head); return 0; } // app退出运行 0,成功,非0,失败 int app_exit(app_struct *app) { if (app == 0) return -1; // 如果app正在运行,需要先退出app if (app->run_state && app->exit) { app->exit(0); } if (app->run_state == 0) { // 在app没有运行时才可以删除 if (app->exe_addr) free(app->exe_addr); appm_delete(app); return 0; } else { return -1; } } // 抢占式调用app,阻塞调用线程以运行app static int app_run_seize(app_struct *app) { int ret = 0; if (app->main) app->main(app); app_exit(app); return ret; } // 调用app,保留app镜像 static int app_run_hold(app_struct *app) { int ret = 0; if (app == 0) return -1; if (app->main) app->main(app); return ret; } static void run_thread_entry(void *t) { app_struct *app = t; int ret = 0; if (app->main) app->main(app); app_exit(app); } // 创建新线程以运行app static int app_run_thread(app_struct *app) { int ret = 0; rt_thread_t rt = rt_thread_create(app->app_info->name, run_thread_entry, app, app->app_info->stack_size, app->app_info->priority, 20); rt_thread_startup(rt); return ret; } // 运行app int app_run(app_struct *app) { int ret = 0; if (app->app_info->exe_type == APP_TYPE_SEIZE) { ret = app_run_seize(app); } else if (app->app_info->exe_type == APP_TYPE_THREAD) { ret = app_run_thread(app); } else if (app->app_info->exe_type == APP_TYPE_HOLD) { ret = app_run_hold(app); } return ret; } int app_run_path(char *path) { int ret = 0; // 如果程序已经存在于内存中,则直接调用 char name[APP_INFO_NAME_MAXLEN] = {0}; if (app_get_name_from_file(path, name) != 0) { app_struct *app = appm_find(name); if (app) { if (app->app_info->exe_type == APP_TYPE_HOLD) { ret = app_run_hold(app); } return ret; } } app_struct *app = appm_new(); if ((app_open(app, path) == 0) && (check_elf_head(app) == 0) && (load_elf_2_mem(app) == 0)) { app_close(app); app_run(app); } else { appm_delete(app); ret = -1; } return ret; }