Chinaunix首页 | 论坛 | 博客
  • 博客访问: 276581
  • 博文数量: 69
  • 博客积分: 2408
  • 博客等级: 大尉
  • 技术积分: 745
  • 用 户 组: 普通用户
  • 注册时间: 2005-06-09 16:37
文章分类

全部博文(69)

文章存档

2011年(16)

2010年(42)

2008年(9)

2005年(2)

我的朋友

分类: LINUX

2010-09-22 00:34:53

编译linux0.11的时候出错,

static inline void put_fs_byte(char val,char *addr)
 26 {
 27 __asm__ ("movb %0,%%fs:%1"::"r" (val),"m" (*addr));
 28 }


出错原因:
http://portabilityblog.com/blog/archives/11-Bad-register-name-dil-or-sil.html:

This is a piece of code from a project that runs on both the x86 and x86_64 architectures:

 1 static inline int swap_int(int *a, int b) {
 2     asm volatile ("xchg %0, %1" : "+r" (b) , "+m" (*a));
 3     return b;
 4 }


It's fairly easy to see what it does: It swaps two values of type int. This code works perfectly fine on both architectures, provided that you're using a compiler that understands the asm statement, such as gcc. Later, this similar piece of code appears:

 1 static inline int swap_char(char *a, char b) {
 2     asm volatile ("xchg %0, %1" : "+r" (b) , "+m" (*a));
 3     return b;
 4 }


This code still compiles and works just fine. For the most part. But when optimisation is turned on, you may get this error from gcc when building for x86:

Error: bad register name `%dil'


Then you try the same on x86_64 and the error is gone again. No wonder: As opposed to x86, the x86_64 architecture actually has the %dil register.

At first, this appears to be a compiler bug. After all, the compiler is choosing a register that doesn't exist on x86. On closer look, it's a bug in the example code. The issue is that for the b argument, the constraint r is used, indicating that the value should be stored in any general-purpose register. In the first example, this is just fine. All of them will do for 32-bit operations. The second example, on closer examination, actually requires a register whose lower byte is accessible. On x86, there are only four general-purpose registers where this is true: EAX, EBX, ECX and EDX. On x86_64, this is also true for the ESI and EDI registers that are also treated as general-purpose registers on x86.

So what happens is that the compiler correctly chooses the %edi register, which satisfies the r constraint. Later, the xchg instruction is interpreted as referring to two byte-sized values due to the size of the arguments *a and b. Thus, the compiler translates the instruction to its 8-bit form and replaces the register placeholder %0 with the 8-bit form of the %edi register, which is %dil. During assembly, this fails because %dil doesn't actually exist on x86.

If there is a compiler bug, it is only that the error output is misleading. It shouldn't even try to use %dil, it should warn about the real problem.

The real bug is that in the example source, a byte-sized argument was qualified with a constraint that allowed any general-purpose register to be used, where instead, the set should be constrained to registers whose lower byte is available. In gcc, this can be achieved by using the q constraint instead of r.
阅读(3103) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~