Date
1 - 1 of 1
[Bug 970] New: #pragma visibility hidden in MdePkg/Include/X64/ProcessorBind.h is misconceived #pragma
bugzilla-daemon at bugzilla.tianocore.org...
https://bugzilla.tianocore.org/show_bug.cgi?id=970
Bug ID: 970 Summary: #pragma visibility hidden in MdePkg/Include/X64/ProcessorBind.h is misconceived Product: EDK2 Version: Current Hardware: All OS: All Status: UNCONFIRMED Severity: minor Priority: Lowest Component: Code Assignee: michael.d.kinney(a)intel.com Reporter: zenith432(a)users.sourceforge.net CC: edk2-bugs(a)lists.01.org The following code in MdePkg/Include/X64/ProcessorBind.h is based on a misconception and is less likely to cause problems if removed. ===== #if defined(__GNUC__) && defined(__pic__) && !defined(USING_LTO) // // Mark all symbol declarations and references as hidden, meaning they will // not be subject to symbol preemption. This allows the compiler to refer to // symbols directly using relative references rather than via the GOT, which // contains absolute symbol addresses that are subject to runtime relocation. // // The LTO linker will not emit GOT based relocations when all symbol // references can be resolved locally, and so there is no need to set the // pragma in that case (and doing so will cause other issues). // #pragma GCC visibility push (hidden) #endif ===== First, even though it was originally written for GCC with ELF target, it is actually included for clang with both ELF and MACHO targets as well. The rationale in the documentation is based on a misconception. Neither ELF nor MACHO associate a visibility with *symbol declarations or references*. A symbol's visibility determines whether the symbols is local or global *at the point it is defined*. When an external symbol is declared or referenced - no visibility is associated to the reference, and the compiler doesn't know whether the symbol is defined as local or global at its point of definition. The compiler generates a GOTPCREL relocation. The static link editor then usually transforms instructions called "GOT loads" into load-effective-address instructions that bypass the GOT. Below is a sample ================ gcc -v .... gcc version 8.1.1 20180502 (Red Hat 8.1.1-1) (GCC) ===== a.c ===== extern int a; extern int g(int); int f(void) { return g(a); } =============== gcc -fpic -c -Os -o a.o a.c objdump -drt a.o a.o: file format elf64-x86-64 SYMBOL TABLE: 0000000000000000 l df *ABS* 0000000000000000 a.c 0000000000000000 l d .text 0000000000000000 .text 0000000000000000 l d .data 0000000000000000 .data 0000000000000000 l d .bss 0000000000000000 .bss 0000000000000000 l d .note.GNU-stack 0000000000000000 .note.GNU-stack 0000000000000000 l d .eh_frame 0000000000000000 .eh_frame 0000000000000000 l d .comment 0000000000000000 .comment 0000000000000000 g F .text 000000000000000e f 0000000000000000 *UND* 0000000000000000 _GLOBAL_OFFSET_TABLE_ 0000000000000000 *UND* 0000000000000000 a 0000000000000000 *UND* 0000000000000000 g Disassembly of section .text: 0000000000000000 <f>: 0: 48 8b 05 00 00 00 00 mov 0x0(%rip),%rax # 7 <f+0x7> 3: R_X86_64_REX_GOTPCRELX a-0x4 7: 8b 38 mov (%rax),%edi 9: e9 00 00 00 00 jmpq e <f+0xe> a: R_X86_64_PLT32 g-0x4 =============== gcc -fpic -fvisibility=hidden -c -Os -o a.o a.c objdump -drt a.o a.o: file format elf64-x86-64 SYMBOL TABLE: 0000000000000000 l df *ABS* 0000000000000000 a.c 0000000000000000 l d .text 0000000000000000 .text 0000000000000000 l d .data 0000000000000000 .data 0000000000000000 l d .bss 0000000000000000 .bss 0000000000000000 l d .note.GNU-stack 0000000000000000 .note.GNU-stack 0000000000000000 l d .eh_frame 0000000000000000 .eh_frame 0000000000000000 l d .comment 0000000000000000 .comment 0000000000000000 g F .text 000000000000000e .hidden f 0000000000000000 *UND* 0000000000000000 _GLOBAL_OFFSET_TABLE_ 0000000000000000 *UND* 0000000000000000 a 0000000000000000 *UND* 0000000000000000 g Disassembly of section .text: 0000000000000000 <f>: 0: 48 8b 05 00 00 00 00 mov 0x0(%rip),%rax # 7 <f+0x7> 3: R_X86_64_REX_GOTPCRELX a-0x4 7: 8b 38 mov (%rax),%edi 9: e9 00 00 00 00 jmpq e <f+0xe> a: R_X86_64_PLT32 g-0x4 ================ Notice how both generate the same object code regardless of visibility. You can see that defined symbols are marked with "l" or "g" to their left based on whether they're local or global - but the UND external references have no visibility associated with them. Later, the static link editor ld transforms instructions of the form movq symbol(a)GOTPCREL(%rip), register to leaq symbol(%rip), register Similarly, the PLT32 relocations are transformed to directly call the target bypassing the PLT. In fact, the tool GetFw which convert ELF executables to COFF is not instrumented to handle GOTPCREL relocations, so if the static link editor leaves any such relocations untransformed in the ELF executable, GetFw will break with an error. I've also seen instances where the compiler generates instructions like addq symbol(a)GOTPCREL(%rip), register for pointer arithmetic done on a declared extern symbol. This instruction cannot be transformed by the static link editor and stays "as is". However, it is emitted in the object code based on the optimisation level set for the compilation, and not based on symbol visibility. By setting a different optimisation such cases can be eliminated. Additionally, it is better to discontinue use of the symbol USING_LTO because it is based on a misconception that LTO setting is global. In fact, -flto can be set in tools_def.txt, but then disabled on a per-module basis with -fno-lto in a module's inf file if LTO causes problems. Moreover, object code generated from assembly source never uses LTO. -- You are receiving this mail because: You are on the CC list for the bug.
|
|