Bug#122511: gcc: illegal instructions and bad jump offsets when VMA != LMA
Package: gcc
Version: 2:2.95.4-4
Severity: normal
This one's not easy to diagnose on my end. I'll cut and paste objdump's
with --source to give an idea of the flavor. Similar bugs happen on all
combinations of binutils and gcc I've tried, which are gcc2.95.4 packages
of several versions and gcc3.0 packages of several versions, and a couple
of versions of binutils I forgot plus the latest (2.11.90.0.31).
I've got the source for the thing where this happens up on
klecker:/org/home/wli/x86init.tar.gz
I'll arrange the sources so that #defining MISCOMPILE causes this
code to be generated.
First, the miscompiled code:
for(k = 0U; k < 4096U; ++k) {
111076: c7 45 f8 00 00 00 00 movl $0x0,0xfffffff8(%ebp)
11107d: 00 00 add %al,(%eax)
11107f: 00 81 7d f8 ff 0f add %al,0xffff87d(%ecx)
111085: 00 00 add %al,(%eax)
111087: 76 07 jbe 111090 <initialize_kernel_virtual
_addressing+0x38>
111089: eb 55 jmp 1110e0 <initialize_kernel_virtual
_addressing+0x88>
11108b: 00 00 add %al,(%eax)
11108d: 00 00 add %al,(%eax)
11108f: 00 8b 45 f8 89 c2 add %cl,0xc289f845(%ebx)
low_page_table_entries[k]
111095: 8d 04 95 00 00 00 00 lea 0x0(,%edx,4),%eax
11109c: ba 00 30 11 00 mov $0x113000,%edx
1110a1: 8b 4d f8 mov 0xfffffff8(%ebp),%ecx
1110a4: 89 cb mov %ecx,%ebx
1110a6: 89 d9 mov %ebx,%ecx
1110a8: c1 e1 0c shl $0xc,%ecx
1110ab: 89 cb mov %ecx,%ebx
1110ad: 83 cb 07 or $0x7,%ebx
1110b0: 89 1c 10 mov %ebx,(%eax,%edx,1)
= (4096*k)
| PAGE_PRESENT_FIELD
| PAGE_SUPERVISOR_FIELD
| PAGE_WRITABLE_FIELD;
high_page_table_entries[k]
1110b3: 8b 45 f8 mov 0xfffffff8(%ebp),%eax
1110b6: 89 c2 mov %eax,%edx
1110b8: 8d 04 95 00 00 00 00 lea 0x0(,%edx,4),%eax
1110bf: ba 00 70 11 00 mov $0x117000,%edx
1110c4: 8b 4d f8 mov 0xfffffff8(%ebp),%ecx
1110c7: 89 cb mov %ecx,%ebx
1110c9: 89 d9 mov %ebx,%ecx
1110cb: c1 e1 0c shl $0xc,%ecx
1110ce: 89 cb mov %ecx,%ebx
1110d0: 83 cb 07 or $0x7,%ebx
1110d3: 89 1c 10 mov %ebx,(%eax,%edx,1)
1110d6: ff 45 f8 incl 0xfffffff8(%ebp)
1110d9: eb a5 jmp 111080 <initialize_kernel_virtual
_addressing+0x28>
1110db: 00 00 add %al,(%eax)
1110dd: 00 00 add %al,(%eax)
1110df: 00 c7 add %al,%bh
= (4096*k)
| PAGE_PRESENT_FIELD
| PAGE_SUPERVISOR_FIELD
| PAGE_WRITABLE_FIELD;
}
#endif
Note that 0x111080 is not on an instruction boundary.
An equivalent loop coded with gotos (the while is similarly miscompiled):
#if 1
k = 0U;
111076: c7 45 f8 00 00 00 00 movl $0x0,0xfffffff8(%ebp)
level_2_page_table_loop: {
low_page_table_entries[k]
11107d: 8b 45 f8 mov 0xfffffff8(%ebp),%eax
111080: 89 c2 mov %eax,%edx
111082: 8d 04 95 00 00 00 00 lea 0x0(,%edx,4),%eax
111089: ba 00 30 11 00 mov $0x113000,%edx
11108e: 8b 4d f8 mov 0xfffffff8(%ebp),%ecx
111091: 89 cb mov %ecx,%ebx
111093: 89 d9 mov %ebx,%ecx
111095: c1 e1 0c shl $0xc,%ecx
111098: 89 cb mov %ecx,%ebx
11109a: 83 cb 07 or $0x7,%ebx
11109d: 89 1c 10 mov %ebx,(%eax,%edx,1)
= (4096*k)
| PAGE_PRESENT_FIELD
| PAGE_SUPERVISOR_FIELD
| PAGE_WRITABLE_FIELD;
high_page_table_entries[k]
1110a0: 8b 45 f8 mov 0xfffffff8(%ebp),%eax
1110a3: 89 c2 mov %eax,%edx
1110a5: 8d 04 95 00 00 00 00 lea 0x0(,%edx,4),%eax
1110ac: ba 00 70 11 00 mov $0x117000,%edx
1110b1: 8b 4d f8 mov 0xfffffff8(%ebp),%ecx
1110b4: 89 cb mov %ecx,%ebx
1110b6: 89 d9 mov %ebx,%ecx
1110b8: c1 e1 0c shl $0xc,%ecx
1110bb: 89 cb mov %ecx,%ebx
1110bd: 83 cb 07 or $0x7,%ebx
1110c0: 89 1c 10 mov %ebx,(%eax,%edx,1)
= (4096*k)
| PAGE_PRESENT_FIELD
| PAGE_SUPERVISOR_FIELD
| PAGE_WRITABLE_FIELD;
++k;
1110c3: ff 45 f8 incl 0xfffffff8(%ebp)
if(k < 4096U)
1110c6: 81 7d f8 ff 0f 00 00 cmpl $0xfff,0xfffffff8(%ebp)
1110cd: 77 02 ja 1110d1 <initialize_kernel_virtual
_addressing+0x79>
goto level_2_page_table_loop;
1110cf: eb ac jmp 11107d <initialize_kernel_virtual
_addressing+0x25>
}
In this case the code runs, boots, and all the jump offsets line up.
I've had a much tougher time reproducing the illegal instructions,
but they seemed to crop up often without -m386 -O0
These are fairly simple for loops so I suspect there is some interaction
between the compiler and linker which is not being done properly in order
to handle the case where LMA != VMA, but I don't have any specifics.
I haven't looked very hard at the generated assembly, either, which could
perhaps tell people whether it's gcc's or binutils' fault alone.
make x86init will make the good executable.
env CFLAGS=-DMISCOMPILE make x86init will make the miscompiled one.
Well, after changing the #ifdefs the jump offsets moved around, but
they're still off. There's this:
111081: 81 7d f8 ff 0f 00 00 cmpl $0xfff,0xfffffff8(%ebp)
111088: 76 06 jbe 111090 <initialize_kernel_virtual_addressing+0x34>
11108a: eb 54 jmp 1110e0 <initialize_kernel_virtual_addressing+0x84>
11108c: 00 00 add %al,(%eax)
where it's trying to land somewhere around here:
1110dd: 00 00 add %al,(%eax)
1110df: 00 c7 add %al,%bh
1110e1: 45 inc %ebp
1110e2: f8 clc
And this is supposed to be a call to a procedure (no inline asm)
called boot_write_cr3()
111165: 20 11 and %dl,(%ecx)
111167: 00 e8 add %ch,%al
111169: fa cli
11116a: 9e sahf
11116b: 00 00 add %al,(%eax)
11116d: 83 c4 10 add $0x10,%esp
... this is code generated by gcc, no inline asm or other dirty tricks.
Cheers,
Bill
-- System Information
Debian Release: testing/unstable
Kernel Version: Linux holomorphy 2.4.17-pre1-vanilla #1 Sat Dec 1 14:28:18 PST 2001 i686 unknown
Versions of the packages gcc depends on:
ii cpp 2.95.4-4 The GNU C preprocessor.
ii cpp-2.95 2.95.4-0.01070 The GNU C preprocessor.
ii gcc-2.95 2.95.4-0.01100 The GNU C compiler.
Reply to: