您的位置:首页 > 运维架构 > Linux

在VDSP中编译uclinux(3):编译器的差异

2007-11-21 22:29 267 查看
虽然VDSP和GCC3.2有很好的兼容性,但是还是有一些差异的,以下列出已经碰到的一些差异及处理办法:
1、__builtin_expect(exp, val)这是GCC的一个内建函数,而VDSP无此函数,它用于为编译器提供分支预测信息,其返回值是整数表达式exp的值,val的值必须是编译时常数。这个内建函数的语义是 exp 的预期值是 val,编译器可以根据这个信息适当地重排语句块的顺序,使程序在预期的情况下有更高的执行效率。因此在移植时直接用:
#define __builtin_expect(exp, val) (exp)
2、__builtin_constant_p(EXP)此内建函数用于判断一个值是否为编译时常数,如果参数EXP 的值是常数,函数返回 1,否则返回 0。很多计算或操作在参数为常数时有更优化的实现,在 GNU C 中用上面的方法可以根据参数是否为常数,只编译常数版本或非常数版本,这样既不失通用性,又能在参数是常数时编译出最优化的代码。在移植时使用:
#define __builtin_constant_p(x) (0)
3、__builtin_return_address (LEVEL)此内建函数返回当前函数或其调用者的返回地址,参数LEVEL 指定在栈上搜索框架的个数,0 表示当前函数的返回地址,1 表示当前函数的调用者的返回地址,依此类推。在VDSP中,仅能取得当前函数的返回地址:
#define __builtin_return_address(level) ({void* addr; /
asm("%0 = rets;" : "=a"(addr)); addr;})
4、汇编中的jump 1f或者jump 1b之类的跳转语句:在VDSP中不支持这种方式的跳转,只能将其中的标号改为绝对标号,并修改相应的jump语句。
5、汇编中的.macroVDSP不支持.macro,必须将其改为#define语句,如果在.macro的中间出现了条件汇编#ifdef之类的东西,必须将这些条件移到#define语句之外。
6、汇编中的.rept世间最痛苦的事情莫过于此,无奈,使用最原始的方法,Copy/Paste。
7、__cmpxchg函数:这个函数是用嵌入汇编写的,但在VDSP下无法编译,因此用C重写,虽然效率有所降低,但我们的目标是首先有一个可以运行的版本,不是吗?
/*
* Atomic compare and exchange. Compare OLD with MEM, if identical,
* store NEW in MEM. Return the initial value in MEM. Success is
* indicated by comparing RETURN with OLD.
*/
static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
unsigned long new, int size)
{
unsigned long tmp = 0;
unsigned long flags = 0;
unsigned long* p = (unsigned long*)ptr;

local_irq_save(flags);

switch (size) {
case 1:
tmp = (*p) & 0x000000ff;
if(old != new)
(*p) = ((*p) & 0xffffff00) | (new & 0x000000ff);
//__asm__ __volatile__
// ("%0 = b%3 (z);/n/t"
// "CC = %1 == %0;/n/t"
// "IF !CC JUMP f1;/n/t"
// "B%3 = %2;/n/t"
// "f1:/n/t"
// : "=&d" (tmp) : "d" (old), "d" (new), "d" (*(unsigned char*)__xg(ptr)) : "memory");
break;
case 2:
tmp = (*p) & 0x0000ffff;
if(old != new)
(*p) = ((*p) & 0xffff0000) | (new & 0x0000ffff);
//__asm__ __volatile__
// ("%0 = w%3 (z);/n/t"
// "CC = %1 == %0;/n/t"
// "IF !CC JUMP f2;/n/t"
// "S%3 = %2;/n/t"
// "f2:/n/t"
// : "=&d" (tmp) : "d" (old), "d" (new), "d" (*(unsigned short*)__xg(ptr)) : "memory");
break;
case 4:
tmp = *p;
if(old != new)
(*p) = new;
//__asm__ __volatile__
// ("%0 = %3;/n/t"
// "CC = %1 == %0;/n/t"
// "IF !CC JUMP f3;/n/t"
// "%3 = %2;/n/t"
// "f3:/n/t"
// : "=&d" (tmp) : "d" (old), "d" (new), "d" (*(unsigned int*)__xg(ptr)) : "memory");
break;
}
local_irq_restore(flags);
return tmp;
}
8、jiffies_64的定义问题:在uclinux中,jiffies_64的定义为:
#define __jiffy_data __attribute__((section(".data")))
extern u64 __jiffy_data jiffies_64;
这样的定义本身没有问题,但是在编译kernel/timer.c时却造成了其它地方代码的编译失败,这是一个非常奇怪的问题,出错提示为:
[Error ea1008] "e:/temp/acc08143dff000/acc08143dff001.s":3601 '.epcdata':
The symbol has already been defined and cannot be redefined.

[Error ea1008] "e:/temp/acc08143dff000/acc08143dff001.s":3608 '.epcdata.end':
The symbol has already been defined and cannot be redefined.
但是如果将定义改为:
extern u64 /*__jiffy_data*/ jiffies_64;
则没有问题。

还有一些其它的问题,但是没有及时记录下来,以后再补上。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: