Hello,
while trying to build qemu, I see errors in the inline
assembler. Investigating it shows that the problem is caused by code
like:
-----
typedef unsigned int size_t;
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#define Xoffsetof(TYPE, MEMBER) (*(unsigned char*)offsetof(TYPE, MEMBER))
typedef struct {
unsigned long regs[8];
} CPUState;
int foo()
{
asm(" fs movl %0, %%eax\n"
" fs movl %1, %%ebx\n"
" fs movl %2, %%ecx\n"
" fs movl %3, %%edx\n"
" fs movl %4, %%esp\n"
" fs movl %5, %%ebp\n"
" fs movl %6, %%esi\n" // **
:
: "m" (Xoffsetof(CPUState, regs[0])),
"m" (Xoffsetof(CPUState, regs[1])),
"m" (Xoffsetof(CPUState, regs[2])),
"m" (Xoffsetof(CPUState, regs[3])),
"m" (Xoffsetof(CPUState, regs[4])),
"m" (Xoffsetof(CPUState, regs[5])), // **
"m" (Xoffsetof(CPUState, regs[6]))
);
}
-------
| $ gcc -c foo.c
| foo.c: In function 'foo':
| foo.c:11: error: can't find a register in class 'GENERAL_REGS' while reloading 'asm'
gcc32 does not have problems with it and generates code like:
| $ gcc32 -c foo.c
| $ objdump -d foo.o
| 00000000 <foo>:
| 0: 55 push %ebp
| 1: 89 e5 mov %esp,%ebp
| 3: 64 a1 00 00 00 00 mov %fs:0x0,%eax
| 9: 64 8b 1d 04 00 00 00 mov %fs:0x4,%ebx
| 10: 64 8b 0d 08 00 00 00 mov %fs:0x8,%ecx
| 17: 64 8b 15 0c 00 00 00 mov %fs:0xc,%edx
| 1e: 64 8b 25 10 00 00 00 mov %fs:0x10,%esp
| 25: 64 8b 2d 14 00 00 00 mov %fs:0x14,%ebp
| 2c: 64 8b 35 18 00 00 00 mov %fs:0x18,%esi
| 33: c9 leave
| 34: c3 ret
Further investigations show that the removal of the lines marked with '**'
lets it succeed with gcc-4 also, and generates correct but ineffizient
code:
| $ gcc -c foo.c
| $ objdump -d foo.o
| 00000000 <foo>:
| 0: 55 push %ebp
| 1: 89 e5 mov %esp,%ebp
| 3: 57 push %edi
| 4: 56 push %esi
| 5: 53 push %ebx
| 6: bf 00 00 00 00 mov $0x0,%edi
| b: bb 04 00 00 00 mov $0x4,%ebx
| 10: be 08 00 00 00 mov $0x8,%esi
| 15: b9 0c 00 00 00 mov $0xc,%ecx
| 1a: ba 10 00 00 00 mov $0x10,%edx
| 1f: b8 18 00 00 00 mov $0x18,%eax
| 24: 64 8b 07 mov %fs:(%edi),%eax
| 27: 64 8b 1b mov %fs:(%ebx),%ebx
| 2a: 64 8b 0e mov %fs:(%esi),%ecx
| 2d: 64 8b 11 mov %fs:(%ecx),%edx
| 30: 64 8b 22 mov %fs:(%edx),%esp
| 33: 64 8b 28 mov %fs:(%eax),%ebp
| 36: 5b pop %ebx
| 37: 5e pop %esi
| 38: 5f pop %edi
| 39: c9 leave
| 3a: c3 ret
This explains why gcc-4 complains about the missing regs: it tries to
load the immediate offset values into general regs first and accesses
the memory based on them then. With more than 6 variables there are not
enough regs available.
Now my question: what is the correct way to achieve the first object
code with inline assembler? Using the specific registers as machine
constraints does not work as the posted assembly block happens within
more complex code in the real qemu code.
I tried things like
| asm("fs movl (%0),%%ebx" : : "i"(offsetof(CPUState, regs[1])))
already but it generates the wrong code ('mov %fs:0x0,%ebx').
Enrico