Files
2025-07-05 19:47:28 +08:00

494 lines
8.9 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <stdio.h>
/**
* hello.c
*/
#include <stdlib.h>
#include <string.h>
#include <elf.h>
#include <errno.h>
#include "rtthread.h"
//#define FILE ft_file_struct
//#define fclose ft_if_fclose
//#define fopen ft_if_fopen
//#define fread ft_if_fread
//#define fseek ft_if_fseek
//#define ftell ft_if_ftell
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);
printf("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))
{
printf("This is ELF file!\r\n");
}
else
{
printf("NOT ELF file!\r\n");
free(Elf_header);
return -1;
}
free(Elf_header);
return 0;
}
/* 加载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
for(int i=0;i< Elf_header->e_phnum; i++)
{
//是程序节
//Keil编译的时候程序分为RORWZI3个节但是从运行时角度看来这3个节合并为一个段了
if(phdr_head[i].p_type == PT_LOAD )
{
//内存
if(app->exe_addr==0)
{
app->exe_addr=malloc(phdr_head[i].p_memsz);
fseek( file1,phdr_head[i].p_offset,SEEK_SET);
if((rb = fread(app->exe_addr,1,phdr_head[i].p_filesz,file1)) != phdr_head[i].p_filesz)
{
printf("function:%s,line:%d, read p_vaddr err!\r\n",__FUNCTION__,__LINE__);
printf("read 返回值%d\r\n",rb);
printf("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);
}
/**多余的空间写0做BSS段**/
if((phdr_head[i].p_filesz) < (phdr_head[i].p_memsz))
{
memset((uint8_t*)app->exe_addr+phdr_head[i].p_filesz,
0,
phdr_head[i].p_memsz - phdr_head[i].p_filesz);
}
//找到入口函数地址
app->main=(int (*)(void *))((int)app->exe_addr+Elf_header->e_entry);
//程序描述信息地址
app->app_info=(app_info_struct *)app->exe_addr;
printf("%s:exe_addr=0X%08X,size=%d\r\n",__func__,(uint32_t)app->exe_addr,phdr_head[i].p_memsz);
printf("%s:main()=0X%08X\r\n",__func__,(uint32_t)app->main);
printf("%s:name=%s\r\n",__func__,app->app_info->name);
break;
}
}
}
//这里求得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编译的时候程序分为RORWZI3个节但是从运行时角度看来这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;
}
}
//获取和保存r9寄存器
void *get_r9(void);
void set_r9(void *r9);
//抢占式调用app阻塞调用线程以运行app
static int app_run_seize(app_struct *app)
{
int ret=0;
app->r9=get_r9();
set_r9((void *)((int)app->exe_addr+app->ro_size));
if (app->main) app->main(app);
set_r9(app->r9);
app_exit(app);
return ret;
}
//调用app保留app镜像
static int app_run_hold(app_struct *app)
{
int ret=0;
if(app==0) return -1;
app->r9=get_r9();
set_r9((void *)((int)app->exe_addr+app->ro_size));
if (app->main) app->main(app);
set_r9(app->r9);
return ret;
}
static void run_thread_entry(void *t)
{
app_struct *app=t;
int ret=0;
app->r9=get_r9();
set_r9((void *)((int)app->exe_addr+app->ro_size));
if (app->main) app->main(app);
set_r9(app->r9);
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);
ret=0;
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;
}