BTW, regarding 3) below, it looks like this is expected behavior from Clang/ LLVM. Dereferencing a NULL pointer is technically undefined in C, and by default the Clang optimizer will cause a trap to occur if you try to do it (because it assumes it's not safe for programs to do that).
The flag -fno-delete-null-pointer-checks can be used to avoid this behavior. This flag seems to be valid for Clang 9 and later. This is slightly more efficient than using the volatile keyword to defeat the optimizer. This flag is also for GCC. -Bill > Hello all: > > Recently I discovered that you can enable CSM compatibility mode in OVMF and > decided to build some images with this feature Because Of Reasons (tm). My > platform is: > > FreeBSD/amd64 12.2-RELEASE > Clang/LLVM 10.0.1 > QEMU 6.2.0 > > These days FreeBSD uses Clang as its native compiler. 12.2-RELEASE comes > with version 10.0.1, but you also have the option of installing more recent > Clang/ LLVM versions up to 12.0.1 as supplemental packages. I noticed that > CLANGDWARF is a supported tool spec for the X64 and IA32 build targets so I > decided to try that. > > Unfortunately I ran into a couple of problems: > > 1) Compilation of OvmfPkg/Library/VmgExitLib/VmgExitVcHandler.c fails due to > uninitialized local variable. > > /mnt/home/wpaul/edk2/edk2/OvmfPkg/Library/VmgExitLib/VmgExitVcHandler.c: > 1875:9: error: variable 'Compacted' is used uninitialized whenever 'if' > condition is false [-Werror,-Wsometimes-uninitialized] > if (EcxIn == 1) { > ^~~~~~~~~~ > /mnt/home/wpaul/edk2/edk2/OvmfPkg/Library/VmgExitLib/VmgExitVcHandler.c: > 1895:12: note: uninitialized use occurs here > Compacted > ^~~~~~~~~ > /mnt/home/wpaul/edk2/edk2/OvmfPkg/Library/VmgExitLib/VmgExitVcHandler.c: > 1875:5: note: remove the 'if' if its condition is always true > if (EcxIn == 1) { > ^~~~~~~~~~~~~~~~ > /mnt/home/wpaul/edk2/edk2/OvmfPkg/Library/VmgExitLib/VmgExitVcHandler.c: > 1871:37: note: initialize the variable 'Compacted' to silence this warning > BOOLEAN Compacted; > ^ > = '\0' > > I changed line 1871 to: > > BOOLEAN Compacted = FALSE; > > and that fixed it. I suspect this may be a case where Clang is being a bit > more strict than GCC about uninitialized variables. > > 2) Linking fails with numerous errors of the following kind: > > ld.lld: error: can't create dynamic relocation R_X86_64_64 against local > symbol in readonly segment; recompile object files with -fPIC or pass '-Wl,- > z,notext' to allow text relocations in the output > > >>> defined in > >>> /mnt/home/wpaul/edk2/edk2/Build/OvmfX64/RELEASE_CLANGDWARF/X64/ > > UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib/OUTPU > T/ SecPeiCpuExceptionHandlerLib.lib(ExceptionHandlerAsm.obj) > > If I edit tools_def.txt and change RELEASE_CLANGDWARF_X64_DLINK_FLAGS so > that it includes -Wl,-z,notext as the error suggests, then everything links > as expected. (The same thing is needed for DEBUG_CLANGDWARF_X64_DLINK_FLAGS > and probably NOOPT_CLANGDWARF_X64_DLINK_FLAGS.) > > This problem only occurs when building for X64. IA32 seems ok. > > Is there any particular reason why these flags aren't there already? > > 3) Although fixing the above two problems allows me to produce a complete > OVMF.fd image, it crashes at start-up with the runtime error: > > !!!! X64 Exception Type - 06(#UD - Invalid Opcode) CPU Apic ID - 00000000 > !!!! > RIP - 000000007EC8A7DB, CS - 0000000000000038, RFLAGS - 0000000000010206 > RAX - 0000000000000000, RCX - 000000007F5A0880, RDX - 000000007FF2BAE0 > RBX - 000000007FF2BBF0, RSP - 000000007FF2BB20, RBP - 000000005A1C5000 > RSI - 000000007FF2BB48, RDI - 0000000000000000 > R8 - 0000000000000008, R9 - 0000000000000000, R10 - 0000000000000000 > R11 - 000000007FF41C90, R12 - 0000000000058080, R13 - 000000007FF2BC20 > R14 - 00000000000F6DB0, R15 - 0000000000000000 > DS - 0000000000000030, ES - 0000000000000030, FS - 0000000000000030 > GS - 0000000000000030, SS - 0000000000000030 > CR0 - 0000000080010033, CR2 - 0000000000000000, CR3 - 000000007FC01000 > CR4 - 0000000000000668, CR8 - 0000000000000000 > DR0 - 0000000000000000, DR1 - 0000000000000000, DR2 - 0000000000000000 > DR3 - 0000000000000000, DR6 - 00000000FFFF0FF0, DR7 - 0000000000000400 > GDTR - 000000007F9EC000 0000000000000047, LDTR - 0000000000000000 > IDTR - 000000007F5A4018 0000000000000FFF, TR - 0000000000000000 > FXSAVE_STATE - 000000007FF2B780 > !!!! Find image based on IP(0x7EC8A7DB) (No PDB) > (ImageBase=000000007EC87000, EntryPoint=000000007EC8D7A6) !!!! > > The same thing occurs for IA32: > > !!!! IA32 Exception Type - 06(#UD - Invalid Opcode) CPU Apic ID - 00000000 > !!!! > EIP - 7ECF72D4, CS - 00000010, EFLAGS - 00010206 > EAX - 00000008, ECX - 00000000, EDX - 7F8EEE10, EBX - 5000A19D > ESP - 7FF33D44, EBP - 7FF33E4C, ESI - 7FF33D4C, EDI - 7ECFB04C > DS - 00000008, ES - 00000008, FS - 00000008, GS - 00000008, SS - > 00000008 CR0 - 80010033, CR2 - 00000000, CR3 - 7FC01000, CR4 - 00000660 > DR0 - 00000000, DR1 - 00000000, DR2 - 00000000, DR3 - 00000000 > DR6 - FFFF0FF0, DR7 - 00000400 > GDTR - 7F9EC000 00000047, IDTR - 7F5E5010 000007FF > LDTR - 00000000, TR - 00000000 > FXSAVE_STATE - 7FF33A80 > !!!! Find image based on IP(0x7ECF72D4) (No PDB) > (ImageBase=000000007ECF4000, EntryPoint=000000007ECF9FBD) !!!! > > This one had me going for a while, but I eventually traced it down to > LegacyBiosInt86() in OvmfPkg/Csm/LegacyBiosDxe/Thunk.c. > > In that function, there is this code: > > UINT16 Segment; > UINT16 Offset; > [...] > // > // The base address of legacy interrupt vector table is 0. > // We use this base address to get the legacy interrupt handler. > // > ACCESS_PAGE0_CODE ( > Segment = (UINT16)(((UINT32 *)0)[BiosInt] >> 16); > Offset = (UINT16)((UINT32 *)0)[BiosInt]; > ); > > As the comment notes, here, we're trying to directly read from address 0 > using BiosInt as an offset. This seems to trigger a problem with the Clang > optimizer. The disassembled output looks like this: > > 0000000000003786 <LegacyBiosInt86>: > 3786: 56 push %rsi > 3787: 48 83 ec 60 sub $0x60,%rsp > 378b: 41 0f b7 40 18 movzwl 0x18(%r8),%eax > 3790: 25 d4 0c 00 00 and $0xcd4,%eax > 3795: 0d 02 30 00 00 or $0x3002,%eax > 379a: 66 41 89 40 18 mov %ax,0x18(%r8) > 379f: 48 8d 74 24 28 lea 0x28(%rsp),%rsi > 37a4: 48 83 66 18 00 andq $0x0,0x18(%rsi) > 37a9: 48 8b 05 a8 59 00 00 mov 0x59a8(%rip),%rax # > 9158 <gDS> > 37b0: 31 c9 xor %ecx,%ecx > 37b2: 48 89 f2 mov %rsi,%rdx > 37b5: ff 50 38 call *0x38(%rax) > 37b8: 4c 8b 46 18 mov 0x18(%rsi),%r8 > 37bc: 41 0f ba e0 0d bt $0xd,%r8d > 37c1: 73 18 jae 37db <LegacyBiosInt86+0x55> > 37c3: 48 8b 05 8e 59 00 00 mov 0x598e(%rip),%rax # > 9158 <gDS> > 37ca: 49 81 e0 ff df ff ff and $0xffffffffffffdfff,%r8 > 37d1: ba 00 10 00 00 mov $0x1000,%edx > 37d6: 31 c9 xor %ecx,%ecx > 37d8: ff 50 40 call *0x40(%rax) > 37db: 0f 0b ud2 <--- er... what? > > Note the "ud2" instruction. I have no idea what that's supposed to be, but > it looks like Clang just gives up generating any further instructions once > it hits this code. > > I reduced this to a very simple sample C program that also reproduces the > problem: > > #include <stdint.h> > > extern int somefunc (uint16_t s, uint16_t o); > > int > foo (uint8_t BiosInt) > { > uint16_t Segment; > uint16_t Offset; > > Segment = (uint16_t)(((uint32_t *)0)[BiosInt] >> 16); > Offset = (uint16_t)((uint32_t *)0)[BiosInt]; > > return somefunc (Segment, Offset); > } > > If I compile this with: > > % clang -O2 -c edk.c > > then I get this: > > 0000000000000000 <foo>: > 0: 55 push %rbp > 1: 48 89 e5 mov %rsp,%rbp > 4: 0f 0b ud2 > > If I compile with GCC instead: > > % gcc10 -O2 -c edk.c > > then I get this: > > 0000000000000000 <foo>: > 0: 40 0f b6 ff movzbl %dil,%edi > 4: 8b 3c bd 00 00 00 00 mov 0x0(,%rdi,4),%edi > b: 0f b7 f7 movzwl %di,%esi > e: c1 ef 10 shr $0x10,%edi > 11: e9 00 00 00 00 jmp 16 <foo+0x16> > > If I compile with Clang using -O0 to disable optimization, then it produces > code: > > 0000000000000000 <foo>: > 0: 55 push %rbp > 1: 48 89 e5 mov %rsp,%rbp > 4: 48 83 ec 10 sub $0x10,%rsp > 8: 31 c0 xor %eax,%eax > a: 89 c1 mov %eax,%ecx > c: 40 88 7d ff mov %dil,-0x1(%rbp) > 10: 0f b6 45 ff movzbl -0x1(%rbp),%eax > 14: 89 c2 mov %eax,%edx > 16: 8b 04 91 mov (%rcx,%rdx,4),%eax > 19: c1 e8 10 shr $0x10,%eax > 1c: 66 89 45 fc mov %ax,-0x4(%rbp) > 20: 0f b6 75 ff movzbl -0x1(%rbp),%esi > 24: 89 f2 mov %esi,%edx > 26: 8b 34 91 mov (%rcx,%rdx,4),%esi > 29: 66 89 75 fa mov %si,-0x6(%rbp) > 2d: 66 8b 45 fc mov -0x4(%rbp),%ax > 31: 0f b7 f8 movzwl %ax,%edi > 34: 0f b7 75 fa movzwl -0x6(%rbp),%esi > 38: e8 00 00 00 00 call 3d <foo+0x3d> > 3d: 48 83 c4 10 add $0x10,%rsp > 41: 5d pop %rbp > 42: c3 ret > > Note that this is with Clang 10.0.1, however I observe exactly the same > results with Clang 12.0.1. > > I was able to fix this locally (for both X64 and IA32 targets) this by doing > this: > > UINT16 Segment; > UINT16 Offset; > volatile UINT32 * Page0 = NULL; > [...] > ACCESS_PAGE0_CODE ( > Segment = (UINT16)(Page0[BiosInt] >> 16); > Offset = (UINT16)Page0[BiosInt]; > ); > > Note that the addition of the volatile keyword seems to be the key. If you > wanted to make the change simpler, you could also just do this: > > ACCESS_PAGE0_CODE ( > Segment = (UINT16)(((volatile UINT32 *)0)[BiosInt] >> 16); > Offset = (UINT16)((volatile UINT32 *)0)[BiosInt]; > ); > > (To my eyes, the other way is more readable, but others may disagree.) > > With these three issues fixed, I'm able to boot and run my OVMF.fd images > for both X64 and IA32, and they're able to also boot and run the loaders > and OS images that I'm testing. > > I'm not sure how much testing the CLANGDWARF toolspec is getting these days, > but maybe it should get a little more. Is there any chance these issues > could be addressed? > > -Bill -- ============================================================================= -Bill Paul (510) 749-2329 | VxWorks Software Architect, wp...@windriver.com | Master of Unix-Fu - Wind River Systems ============================================================================= "I put a dollar in a change machine. Nothing changed." - George Carlin ============================================================================= -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#85578): https://edk2.groups.io/g/devel/message/85578 Mute This Topic: https://groups.io/mt/88340070/21656 Group Owner: devel+ow...@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [arch...@mail-archive.com] -=-=-=-=-=-=-=-=-=-=-=-