让vdsp与uclinux共舞(13):应用程序加载

 

快乐虾

http://blog.csdn.net/lights_joy/

[email protected]

  

 

 

 

 

本文适用于

ADSP-BF561

Visual DSP++ 5.0(update 6)

Bfin-uclinux-2009r1.6

 

 

欢迎转载,但请保留作者信息

 

 

 

在我们的应用程序开发完成后,我们需要将之发布使之可以独立运行,此时我们有的只有一个由vdsp生成的dxe文件,我们需要写一个loader完成此dxe文件的加载。

我们直接在appstub的基础上修改:

#include <getopt.h>

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <unistd.h>

#include <fcntl.h>

#include <signal.h>

#include <paths.h>

#include <sched.h>

#include <elf.h>

#include <errno.h>

#include <sys/stat.h>

#include <sys/mman.h>

 

typedef int (*pfcall)(int argc, char *argv[]);

 

#define printf(fmt, ...) do {} while(0)

 

#ifndef EM_BLACKFIN

# define EM_BLACKFIN 106

#endif

 

#define IS_ELF(buff) /

     (buff[EI_MAG0] == ELFMAG0 && /

      buff[EI_MAG1] == ELFMAG1 && /

      buff[EI_MAG2] == ELFMAG2 && /

      buff[EI_MAG3] == ELFMAG3)

 

static void* find_entry(char* buf)

{

    // 读取函数入口

    Elf32_Ehdr* ehdr = (Elf32_Ehdr*)buf;

    Elf32_Shdr* shdr_str, *shdr;

    char* str_head;

    int i;

    pfcall entry = NULL;

   

    shdr_str = buf + ehdr->e_shoff + ehdr->e_shstrndx * ehdr->e_shentsize;

    str_head = buf + shdr_str->sh_offset;

   

    shdr = buf + ehdr->e_shoff;

    for(i=0; i < ehdr->e_shnum; i++, shdr++)

    {

        printf("section found: %s/n", str_head + shdr->sh_name);

        if(strcmp(str_head + shdr->sh_name, ".vdsp_comm") == 0)

        {

            printf("entry found./n");

            memcpy(&entry, buf+shdr->sh_offset+4, 4);

            return entry;

        }

    }

   

    return NULL;

}

 

static void* load_dxe_file(const char* fname)

{

    // 读取dxe文件中的所有section,并返回入口地址

     int i, fd;

     struct stat stat;

     void *entry = NULL;

     char* buf;

    Elf32_Ehdr* ehdr;

    Elf32_Phdr* phdr;

 

    // 打开映射文件

     fd = open(fname, O_RDONLY);

     if (fd < 0) {

         fprintf(stderr, "Unable to load %s: %s/n", fname, strerror(errno));

         return NULL;

     }

 

     if (fstat(fd, &stat) < 0) {

         fprintf(stderr, "Unable to stat %s: %s/n", fname, strerror(errno));

         return NULL;

     }

 

     if (stat.st_size < EI_NIDENT) {

         fprintf(stderr, "File is too small to be an ELF/n");

         return NULL;

     }

 

     buf = mmap(0, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);

     if (buf == MAP_FAILED) {

         fprintf(stderr, "Unable to mmap %s: %s/n", fname, strerror(errno));

         return NULL;

     }

 

    // 判断内容是否合法

     /* make sure we have a valid ELF */

     ehdr = buf;

     if (!IS_ELF(ehdr->e_ident) || ehdr->e_machine != EM_BLACKFIN)

     {

         fprintf(stderr, "file is not a Blackfin ELF file/n");

         return NULL;

     }

 

     /* make sure we have no unhandled program headers */

     phdr = (Elf32_Phdr *)(buf + ehdr->e_phoff);

     for (i = 0; i < ehdr->e_phnum; ++i)

     {

         printf("program head %d: /ntype=%d offset=%d vaddr=%08x filesz=%d memsz=%d flags=%x/n",

             i, phdr->p_type, phdr->p_offset, phdr->p_vaddr, phdr->p_filesz, phdr->p_memsz, phdr->p_flags);

         if(phdr->p_filesz > 0)

             memcpy(phdr->p_vaddr, buf + phdr->p_offset, phdr->p_filesz);

         else

             memset(phdr->p_vaddr, 0, phdr->p_memsz);

         printf("load OK!/n");

         ++phdr;

     }

   

     entry = find_entry(buf);

 

     munmap(buf, stat.st_size);

     close(fd);

    

     return entry;

}

 

/*

 * The main program.

 */

int main(int argc, char *argv[])

{

    unsigned int addr = 0;

    unsigned int *p;

    pfcall entry = NULL;

    if(argc < 2)

    {

        printf("not enough param.");

        return 1;

    }

    if(argv[1][0] == '-' && argv[1][1] == 'L')

    {

        entry = load_dxe_file(argv[1] + 2);

        if(entry)

        {

            printf("dxe entry found at 0x%08x/n", entry);

            argv[1] = argv[0];

            return entry(argc-1, argv+1);

        }

        else

            printf("no dxe entry found/n");

    }

    else if(argv[1][0] == '-' && argv[1][1] == 'E')

    {

        // 直接跳转到指定位置

        addr = strtoul(argv[1]+2, NULL, 16);

        p = (unsigned int*)addr;

        if(p[0])

        {

             printf("detect new app at %08x/n", p);

             p[0] = 0;

             if(p[1])

             {

                 printf("prepare call %08x/n", p[1]);

                 argv[1] = argv[0];

                 return ((pfcall)p[1])(argc-1, argv+1);

             }

         else

             printf("no function entry found./n");

        }

        else

             printf("old app exist./n");

    }

    return 0;

}

 

这段程序很简单,它检测dxe文件中“.vdsp_comm”这个section,从这个section中读取这个dxe文件指定的入口,然后跳转到这个位置执行。

当我们在vdsp下调试程序的时候,可以用

appstub –Eaddr …

这样的方式让它检测是否重新加载vdsp程序。

当程序要发布的时候,直接用:

appstub –Lp0.dxe ….

这样的方式来加载dxe文件。

在这两种方式中,都可以使用参数且真正要运行的程序不用理会-L-E的影响。

 

 

 

 

 

 

1       参考资料

vdspuclinux共舞(12):应用程序开发2009-11-9

vdspuclinux共舞(11):方案改进(2009-11-6)

vdspuclinux共舞(10):加载SMP内核(2009-11-4)

vdspuclinux共舞(9):查找内核函数(2009-11-3)

vdspuclinux共舞(8):vdsp驱动框架(2009-11-3)

vdspuclinux共舞(7):在内核为驱动预留空间(2009-11-2)

vdspuclinux共舞(6):用vdsp开发驱动的设想(2009-11-2)

vdspuclinux共舞(5):加入dwarf调试信息(2009-11-2)

vdspuclinux共舞(4):加载uclinux(2009-11-2)

vdspuclinux共舞(3):boot kernel(2009-10-31)

vdspuclinux共舞(2):vdsp的影响(2009-10-31)

VDSPuclinux共舞(1):开篇(2009-10-30)

 

近日,我家6岁的小姑娘参加了第六届POP全国少儿英语风采大赛,拉票进行中(2011-6-15前)。

请帮忙点击新东方网站的链接:

http://popdasai.xdf.cn/toupiao.php?do=space&uid=4237

投她一票,谢谢!

你可能感兴趣的:(框架,struct,function,File,null,程序开发)