I've found a bug in OS X version of Intel C++ compiler when compiling shared 32bit library with inline msasm code in it. The problem is that compiler fails to produce either PIC code or text relocation for inline assembler referencing global or static variables which results in wrong memory address being referenced. Here's minimal test case (also attached for your convenience):
header.h:
void f(void);
main.c:
#include "header.h" int main() { f(); return 0; }
lib.c:
#include <stdio.h> #include "header.h" void f(void) { static int i; void* p; _asm{ #ifdef __i386 lea ecx, [i] mov [p], ecx #else lea rcx, [i] mov [p], rcx #endif } printf("asm %p C %p\n", p, &i); }
test.sh (clang is included for comparison, || && logic is needed for compatibility with 2013 SP1 version):
#!/bin/bash icc -g -fno-pic -use-msasm -shared -o libtest.dylib lib.c || \ icc -g -fno-pic -use-msasm -c -o lib.o lib.c && \ clang -g -fno-pic -shared -o libtest.dylib lib.o icc -g main.c -L. -ltest -o test echo intel 64 DYLD_LIBRARY_PATH=. ./test icc -g -fPIC -use-msasm -shared -o libtest.dylib lib.c || \ icc -g -fPIC -use-msasm -c -o lib.o lib.c && \ clang -g -fPIC -shared -o libtest.dylib lib.o icc -g main.c -L. -ltest -o test echo PIC intel 64 DYLD_LIBRARY_PATH=. ./test icc -g -fno-pic -m32 -use-msasm -read_only_relocs warning -shared -o libtest.dylib lib.c || \ icc -g -fno-pic -m32 -use-msasm -c -o lib.o lib.c && \ clang -g -fno-pic -m32 -read_only_relocs warning -shared -o libtest.dylib lib.o icc -g -m32 main.c -L. -ltest -o test echo intel 32 DYLD_LIBRARY_PATH=. ./test icc -g -fPIC -m32 -use-msasm -read_only_relocs warning -shared -o libtest.dylib lib.c || \ icc -g -fPIC -m32 -use-msasm -c -o lib.o lib.c && \ clang -g -fPIC -m32 -read_only_relocs warning -shared -o libtest.dylib lib.o icc -g -m32 main.c -L. -ltest -o test echo PIC intel 32 DYLD_LIBRARY_PATH=. ./test clang -g -fno-pic -fms-extensions --shared -o libtest.dylib lib.c clang -g main.c -L. -ltest -o test echo clang 64 DYLD_LIBRARY_PATH=. ./test clang -g -fPIC -fms-extensions --shared -o libtest.dylib lib.c clang -g main.c -L. -ltest -o test echo PIC clang 64 DYLD_LIBRARY_PATH=. ./test clang -g -fno-pic -m32 -fms-extensions -read_only_relocs warning --shared -o libtest.dylib lib.c clang -g -m32 main.c -L. -ltest -o test echo clang 32 DYLD_LIBRARY_PATH=. ./test clang -g -fPIC -m32 -fms-extensions -read_only_relocs warning --shared -o libtest.dylib lib.c clang -g -m32 main.c -L. -ltest -o test echo PIC clang 32 DYLD_LIBRARY_PATH=. ./test
And output of test.sh run:
intel 64 asm 0x107544018 C 0x107544018 PIC intel 64 asm 0x102f67018 C 0x102f67018 intel 32 asm 0xc1 C 0xb400c PIC intel 32 asm 0xc1 C 0x5500c clang 64 asm 0x108615018 C 0x108615018 PIC clang 64 asm 0x10a35e018 C 0x10a35e018 ld: warning: text reloc in _f to _f.i ld: warning: text reloc in _f to cstring ld: warning: text reloc in _f to _f.i clang 32 asm 0xa400c C 0xa400c ld: warning: text reloc in _f to _f PIC clang 32 asm 0xf9eb6 C 0x7d00c
From this (and looking at disassembly of produced code) I conclude the following:
- 64 bit doesn't have this issue (BTW on Linux 32/64 bits this test case works correctly too);
- Intel compiler produces PIC code for C part in both -fPIC and -fno-pic modes;
- Intel compiler produces non-PIC code for inline asm part in both modes, but doesn't create text relocations, which results in broken library;
- Apple's clang correctly creates text relocations (and non-PIC code) for -fno-pic mode;
- Apple's clang fails in -fPIC mode by creating PIC code and text relocation, so effectively double-correcting the library load offset.
So in fairness Intel compiler isn't the only one mishandling the situation, but at least I can use non-PIC mode (which is the one I want so it happens) with Apple's clang.
I'm using latest versions of OS X (10.10.4) and Xcode (6.4). I've tested 2015 and 2013 SP1 versions of Intel Parallel Studio XE Composer Edition for C++ OS X (earlier ones don't install on my system).