本文详细记录了Contiki动态加载模块Loader在IAR下移植遇到的问题,分析及解决。

1. 编译错误

1.1 could not open source file

Contiki是在Linux平台下开发的,其源码引用了Linux库头文件(仅仅引用库文件,自己实现,比如dlfcn.hdlopen函数),当在IAR编译时提示could not open source file错误,解决方法是将这些头文件从Linux找出来并加到IAR的工程目录,Linux库头文件可能又包含其他库头文件,不过不用担心,会很快收敛的:-) 涉及到文件如下:

./include/malloc.h dlfcn.h features.h unistd.h
./include/i386-linux-gnu/bits/predefs.h wordsize.h dlfcn.h environments.h esizes.h confname.h types.h posix_opt.h
./include/i386-linux-gnu/sys/cdefs.h
./include/i386-linux-gnu/gnu/stubs.h stubs-32.h
./include/getopt.h

为了尽量少改动代码,根据源码,用文件目录core/linux_lib组织这些被引用库头文件,记得将相应路径加到IAR的预处理路径中,linux_lib文件压缩包文件:linux_lib.rar

1.2 FILE未定义

编译提示FILE未定义,在malloc.h文件,如下,在Contiki并没有用到这些函数,注释掉。

extern int malloc_info (int __options, FILE *__fp);

1.3 expression must be a pointer to a complete object type

编译时,提示错误"expression must be a pointer to a complete object type ",定位于Contiki\core\loader\cmod.c94,如下:

h.bss = h.data + h.datasize;

h类型是cle_info结构体,bssdatadatasize类型分别为void *void *cle_word(实质是u16_t)。理论上是没有错的,但这跟编译器有关(GCC可以,IAR不行),主要问题在于类似的隐式转换,这里将类型转换显式化(假设是32位的处理器),如下:

h.bss = (void *)((u32_t)h.data + h.datasize);

1.4 类型不匹配

编译时,在文件core\loader\cmod.c提示错误`a value of type "void " cannot be assigned to an entity of type "void ()(void)",提示错误的源代码如下:

cmod_module[imod].fini = cle_lookup(&h, pread, off, "_fini");
init = cle_lookup(&h, pread, off, "_init");

.init.fini是程序初始化与终结代码段,这两个段的代码会最终拼成两个函数_init()_fini()cle_lookup函数返回void类型的指针,但cmod_module[imod].fini是函数指针。

//filename:cle.c function:cle_lookup()
return (void*)(uintptr_t)(addr + s.st_value);

struct cmod_info cmod_module[CMOD_NMODULES];
struct cmod_info
{
  void *ram;
  void(*fini)(void);
};

问题转化为将指针转换为函数指针(也许在GCC无须修改),修改后代码如下:

cmod_module[imod].fini = (void (*)(void))(cle_lookup(&h, pread, off, "_fini"));

同理,init = cle_lookup(&h, pread, off, "_init")改成:

init = (void (*)(void))(cle_lookup(&h, pread, off, "_init"));

elfloader_compat.c也有类似的问题,修改后代码如下:

elfloader_fini = (void (*)(void))(cle_lookup(&h, xmem_pread, eepromaddr, "_fini")); 
elfloader_init = (void (*)(void))(cle_lookup(&h, xmem_pread, eepromaddr, "_init"));

关于如何将指针转换为函数指针可参考博文《如何将一个指针强制转换为一个函数指针》。

1.5 off_t和intptr_t重定义

off_t分别在platform/stm32test/contiki-conf.hcore/linux_lib/sys/unistd.h定义,前者实质是unsigned long,后者实质是long int,这里注释后者的定义。

intptr_t分别在IAR Systems\Embedded Workbench 5.4\arm\INC\stdint.hcore/linux_lib/sys/unistd.h定义,前者实质是__INTPTR_T_TYPE__,后者实质是int,这里注释后者的定义。

1.6 _etext_edata__data_start未定义

编译时,在elfloader_compat.c提示_etext_edata__data_start未定义错误,这些符号(通常称特殊符号)被定义在链接脚本中(ld链接器是这样,IAR也是吗?),程序使用需先声明,链接器会在链接成可执行文件时解析成正确的值。在elfloader_compat.c加入如下代码:

/***added by jelline***/
extern unsigned long _etext; //代码段结束地址 _stext为代码段开始地址
extern unsigned long __data_start; //初始化的数据开始地址
extern unsigned long _edata; //初始化的数据结束地址

1.7 ROM_ERASE_UNIT_SIZE未定义

编译时,在elfloader_compat.cROM_ERASE_UNIT_SIZE未定义错误,Contiki是按sector擦除的,这里将ROM_ERASE_UNIT_SIZE定义为COFFEE_SECTOR_SIZE,在elfloader_compat.c加入如下代码:

#include "cfs-coffee-arch.h"

#define ROM_ERASE_UNIT_SIZE COFFEE_SECTOR_SIZE

2. 链接错误

2.1 elfloader_arch_allocate_ram等重定义

链接时,提示elfloader_arch_allocate_ramelfloader_arch_allocate_ramelfloader_arch_relocateelfloader_arch_write_rom重定义,如下:

img

图1 重定义错误

elfloader_arch_allocate_ramelfloader_arch_allocate_ramelfloader_arch_relocateelfloader_arch_write_rom分别在文件core/loader/elfloader-stub.ccpu/arm/stm32f103/elfloader-stm32f10x.c实现。elfloader-stub.c可以理解为elfloader-stub.h实现的模板,我本以为还要自己实现呢(我的MCU是stm32f103),原来Contiki已经有了,这里将elfloader-stub.c从工程目录移除,并添加elfloader-stm32f10x.c

2.2 elfloader_load、elfloader_unknow重定义

链接时,提示elfloader_loadelfloader_unknow重定义,其分别在文件core/loader/elfloader.c、core/loader/elfloader_compat.c实现。这里将elfloader_compat.c从工程目录移除。

至此,编译链接成功,接下来就是写些测试例子测试下:-)

本文系Spark & Shine原创,转载需注明出处本文最近一次修改时间 2022-03-20 22:40

results matching ""

    No results matching ""