gcc ignore casing of symbol names while linking - gcc

A software I am working on ships with NETLIB BLAS/LAPACK embedded into its sources using all-lowercase symbol names but now while porting the application to windows I discovered that Intel MKL and several other BLAS/LAPACK implementations for this platform use all-uppercase symbol names. Is there a way to tell the gnu compiler/linker to ignore case while matching symbol names?
.
.
.
undefined reference to `_dgeqp3'
.
.
.
$ nm /lib/LAPACK.lib | grep -i " T _dgeqp3"
00000000 T _DGEQP3

The difference you're seeing is due to Fortran calling conventions: in Fortran, symbol case is unimportant, and thus every compiler has a way to translate Fortran symbol names into assembler symbol names: GNU compilers usually translate all to lowercase, Intel on Windows goes for uppercase.
If you're working with Fortran code, you can use the -fsymbol-case-upper option on the older g77 compiler (the newer gfortran compiler doesn't have this). Otherwise, no simple answer for C, except:
using #define's
using the C interfaces to BLAS and LAPACK.

I think you might be in for some trouble. Section 6.4.2.1 of the C spec says "Lowercase and uppercase letters are distinct" with respect to identifiers. That means that as far as your compiler and linker are concerned, _DGEQP3 and _dgeqp3 are different symbols. You can probably add some #define statements in a platform-specific header to line things up for you.
Is it because you're linking against a windows library rather than whatever you were using before that this bug showed up?

t.c
#define __CONCAT(x,y) x##y
#ifdef SUFFIX
#define __SUFFIX(x) __CONCAT(x,_)
#else
#define __SUFFIX(x) x
#endif
#ifdef UPPER
#define __c(U,l) __SUFFIX(U)
#else
#define __c(U,l) __SUFFIX(l)
#endif
#define xaxpy __c(XAXPY, xaxpy)
#include <stdio.h>
char* xaxpy;
char* DAXPY;
int main()
{
printf(xaxpy);
printf(DAXPY);
}
e.c
char* xaxpy = "ln";
char* xaxpy_ = "ls";
char* XAXPY = "UN";
char* XAXPY_ = "US";
there seems to be a way to introduce symbol aliases at link-time using --defsym:
Cetin#BAKA-CHAN ~
$ gcc -D UPPER -D SUFFIX -c t.c e.c
Cetin#BAKA-CHAN ~
$ gcc -o t t.o e.o -Wl,--defsym=_DAXPY=_xaxpy
Cetin#BAKA-CHAN ~
$ ./t
USln
Cetin#BAKA-CHAN ~
$
There must also be a way to give the linker different scripts to handle a large number of such symbol definitions. So I could make it part of the build process to automatically create linker scripts that create mappings between different cases.

Related

glibc versioned symbol and undefined reference to memcpy#GLIBC_2.14

Today, when I use conda zlib to compile a binary, I encountered the error Undefined reference to memcpy#GLIBC_2.14.
.../x86_64-conda-linux-gne/bin/ld: ...envs/myenv/lib/libz.so: undefined reference to memcpy#GLIBC_2.14
Although somebody asked similar questions, like this, they cannot solve my problem since I am using third party library.
I then try to understand what is happening. I did the following experiments:
~ $ ldd $CONDA_PREFIX/lib/libz.so
linux-vdso.so.1 (0x00007ffcc4a90000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fe449c1a000)
/lib64/ld-linux-x86-64.so.2 (0x00007fe449e70000)
~ $ nm $CONDA_PREFIX/lib/libz.so | grep memcpy
U memcpy##GLIBC_2.14
~ $ nm -gD /lib/x86_64-linux-gnu/libc.so.6 | grep ' memcpy'
00000000000c7a30 T memcpy#GLIBC_2.2.5
00000000000ad1e0 i memcpy##GLIBC_2.14
Q1: ## vs # in the versioned symbols
Why does nm libz.so above show memcpy##GLIBC_2.14 instead of memcpy#GLIBC_2.14.
From all-about-symbol-versioning, I learnt that ## is the default to be used if a symbol without version is requested. But If the libz.so explicitly asks for memcpy##GLIBC_2.14, shouldn't the error be undefined reference to memcpy##GLIBC_2.14?
Q2: what does i mean in the output. man nm says
For ELF format files this indicates that the symbol is an indirect function. This is a GNU extension to the standard set of ELF symbol types. It indicates a symbol which if referenced by a relocation does not evaluate to its address, but instead must be invoked at runtime. The runtime execution will then return the value to be used in the relocation.
But I cannot understand what it means.
Does the libc.so I have provide memcpy##GLIBC_2.14 for others to link against?
Q3: why my following code does not depend on symbol memcpy
I then coded a simple foo.c file
#include <stdio.h>
#include <string.h>
int main()
{
char from[10] = "hello";
char to[10] = "";
printf("from <%s> to <%s>\n", from, to);
memcpy(to, from, 10);
printf("from <%s> to <%s>\n", from, to);
}
Compiling it gcc -c foo.c and then nm foo.o, I see the following:
U _GLOBAL_OFFSET_TABLE_
0000000000000000 T main
U printf
It has U printf, but not U memcpy. Why? Is this related to the i type in Q?
Q4: why adding __asm__ has no effect
I added a line __asm__(".symver memcpy,memcpy#GLIBC_2.14"); to foo.c, the result is the same. I then changed it to one of the following. Strangely, all of them will be compiled successfully, even some of them contains various typos.
__asm__(".symver memcpy,memcpy#GLIBC_2.14");
__asm__(".symver memcpy,memcpy#GLIBC_2.18"); 2.18 does not exist
__asm__(".symver memcpy,xxxxxx#GLIBC_2.18");
It seems it has no effect for memcpy. I tested it for other functions like foo,foo#v1 and it works only if foo#v1 exists as an exported symbol. So I think the syntax and mechanism for versioned symbols is correct when foo is used; but memcpy is special.
How to explain this?
As for Q3, I think it's because gcc is inlining its builtin version of memcpy. You have to pass -fno-builtin to gcc to force the use of libc's memcpy. Not sure if Q4 is also related to this.
I'm also looking for answers to the other questions. It's not relevant, but the reason libc has multiple memcpy versions is to guarantee backwards compatibility with programs that use memcpy with overlapping regions.

Concatenate strings in a macro using gfortran

The C preprocessor macro for concatenation (##) does not seem to work on a Mac using gfortran. Using other Fortran compilers on other systems works so I am looking for a workaround for gfortran. I have to use the ## to create many variables so I can't do without them.
Example code:
#define CONCAT(x,y) x##y
program main
integer, parameter:: CONCAT(ID,2) = 3
print*,"Hello", ID_2
end program main
Compilation error with gfortran on MAC
gfortran m.F90 -o m
m.F90:5.23:
integer, parameter:: ID##2 = 3
1
Error: PARAMETER at (1) is missing an initializer
## doesn't work in gfortran (any OS, not just Mac) because it runs CPP in the traditional mode.
According to this thread the gfortran mailing list the correct operator in the traditional mode is x/**/y, so you must distinguish between different compilers:
#ifdef __GFORTRAN__
#define CONCAT(x,y) x/**/y
#else
#define CONCAT(x,y) x ## y
#endif
Others (http://c-faq.com/cpp/oldpaste.html) use this form, which behaves better when a macro passed to the CONCAT (via Concatenating an expanded macro and a word using the Fortran preprocessor):
#ifdef __GFORTRAN__
#define PASTE(a) a
#define CONCAT(a,b) PASTE(a)b
#else
#define PASTE(a) a ## b
#define CONCAT(a,b) PASTE(a,b)
#endif
The indirect formulation helps to expand the passed macro before the strings are concatenated (it is too late after).

gcc optimizations: how to deal with macro expantion in strncmp & other functions

Take this sample code:
#include <string.h>
#define STRcommaLEN(str) (str), (sizeof(str)-1)
int main() {
const char * b = "string2";
const char * c = "string3";
strncmp(b, STRcommaLEN(c));
}
If you don't use optimizations in GCC, all is fine, but if you add -O1 and above, as in gcc -E -std=gnu99 -Wall -Wextra -c -I/usr/local/include -O1 sample.c, strncmp becomes a macro, and in preprocessing stage STRcommaLen is not expanded. In fact in resulting "code" strncmp's arguments are completely stripped.
I know if I add #define NEWstrncmp(a, b) strncmp (a, b) and use it instead, the problem goes away. However, mapping your own functions to every standard function that may become a macro doesn't seem like a great solution.
I tried finding the specific optimization that is responsible for it and failed. In fact if I replace -O1 with all the flags that it enables according to man gcc, the problem goes away. My conclusion is that -O1 adds some optimizations that are not controlled by flags and this is one of them.
How would you deal with this issue in a generic way? There may be some macro magic I am not familiar with or compiler flags I haven't looked at? We have many macros and a substantial code base - this code is just written to demonstrate one example.
Btw, GCC version/platform is gcc version 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5).
Thanks,
Alen
You correctly noted that
in preprocessing stage STRcommaLen is not expanded
- more precisely, not before the strncmp macro gets expanded. This inevitably leads to an error you probably overlooked or forgot to mention:
sample.c:7:30: error: macro "strncmp" requires 3 arguments, but only 2 given
Your conclusion
that -O1 adds some optimizations that are not controlled by flags and
this is one of them
is also right - this is controlled by the macro __OPTIMIZE__ which apparently gets set by -O1.
If I'd do something like that (which I probably wouldn't, in respect of the pitfall you demonstrated by using sizeof a char *), I'd still choose
mapping your own functions to every standard function that may become
a macro
- but rather like
#include <string.h>
#define STRNCMP(s1, s2) strncmp(s1, s2, sizeof(s2)-1)
int main()
{
const char b[] = "string2";
const char c[] = "string3";
STRNCMP(b, c);
}

strdup error on g++ with c++0x

I have some C++0x code. I was able to reproduce it below. The code below works fine without -std=c++0x however i need it for my real code.
How do i include strdup in C++0x? with gcc 4.5.2
note i am using mingw. i tried including cstdlib, cstring, string.h and tried using std::. No luck.
>g++ -std=c++0x a.cpp
a.cpp: In function 'int main()':
a.cpp:4:11: error: 'strdup' was not declared in this scope
code:
#include <string.h>
int main()
{
strdup("");
return 0;
}
-std=gnu++0x (instead of -std=c++0x) does the trick for me; -D_GNU_SOURCE didn't work (I tried with a cross-compiler, but perhaps it works with other kinds of g++).
It appears that the default (no -std=... passed) is "GNU C++" and not "strict standard C++", so the flag for "don't change anything except for upgrading to C++11" is -std=gnu++0x, not -std=c++0x; the latter means "upgrade to C++11 and be stricter than by default".
strdup may not be included in the library you are linking against (you mentioned mingw). I'm not sure if it's in c++0x or not; I know it's not in earlier versions of C/C++ standards.
It's a very simple function, and you could just include it in your program (though it's not legal to call it simply "strdup" since all names beginning with "str" and a lowercase letter are reserved for implementation extensions.)
char *my_strdup(const char *str) {
size_t len = strlen(str);
char *x = (char *)malloc(len+1); /* 1 for the null terminator */
if(!x) return NULL; /* malloc could not allocate memory */
memcpy(x,str,len+1); /* copy the string into the new buffer */
return x;
}
This page explains that strdup is conforming, among others, to the POSIX and BSD standards, and that GNU extensions implement it. Maybe if you compile your code with "-D_GNU_SOURCE" it works?
EDIT: just to expand a bit, you probably do not need anything else than including cstring on a POSIX system. But you are using GCC on Windows, which is not POSIX, so you need the extra definition to enable strdup.
add this preprocessor "_CRT_NONSTDC_NO_DEPRECATE" to Project Properties->C/C++ Build->GCC C++ Compiler->Preprocessor->Tool Settings
Don't forget to check Preprocessor Only(-E)
This worked for me on windows mingw32.

How do you suppress GCC linker warnings?

I've been on a crusade lately to eliminate warnings from our code and have become more familiar with GCC warning flags (such as -Wall, -Wno-<warning to disable>, -fdiagnostics-show-option, etc.). However I haven't been able to figure out how to disable (or even control) linker warnings. The most common linker warning that I was getting is of the following form:
ld: warning: <some symbol> has different visibility (default) in
<path/to/library.a> and (hidden) in <path/to/my/class.o>
The reason I was getting this was because the library I was using was built using the default visibility while my application is built with hidden visibility. I've fixed this by rebuilding the library with hidden visibility.
My question though is: how would I suppress that warning if I wanted to? It's not something that I need to do now that I've figured out how to fix it but I'm still curious as to how you'd suppress that particular warning — or any linker warnings in general?
Using the -fdiagnostics-show-option for any of the C/C++/linker flags doesn't say where that warning comes from like with other compiler warnings.
Actually, you can't disable a GCC linker warning, as it's stored in a specific section of the binary library you're linking with. (The section is called .gnu.warning.symbol)
You can however mute it, like this (this is extracted from libc-symbols.h):
Without it:
#include <sys/stat.h>
int main()
{
lchmod("/path/to/whatever", 0666);
return 0;
}
Gives:
$ gcc a.c
/tmp/cc0TGjC8.o: in function « main »:
a.c:(.text+0xf): WARNING: lchmod is not implemented and will always fail
With disabling:
#include <sys/stat.h>
/* We want the .gnu.warning.SYMBOL section to be unallocated. */
#define __make_section_unallocated(section_string) \
__asm__ (".section " section_string "\n\t.previous");
/* When a reference to SYMBOL is encountered, the linker will emit a
warning message MSG. */
#define silent_warning(symbol) \
__make_section_unallocated (".gnu.warning." #symbol)
silent_warning(lchmod)
int main()
{
lchmod("/path/to/whatever", 0666);
return 0;
}
gives:
$ gcc a.c
/tmp/cc195eKj.o: in function « main »:
a.c:(.text+0xf): WARNING:
With hiding:
#include <sys/stat.h>
#define __hide_section_warning(section_string) \
__asm__ (".section " section_string "\n.string \"\rHello world! \"\n\t.previous");
/* If you want to hide the linker's output */
#define hide_warning(symbol) \
__hide_section_warning (".gnu.warning." #symbol)
hide_warning(lchmod)
int main()
{
lchmod("/path/to/whatever", 0666);
return 0;
}
gives:
$ gcc a.c
/tmp/cc195eKj.o: in function « main »:
Hello world!
Obviously, in that case, replace Hello world! either by multiple space or some advertisement for your wonderful project.
Unfortunately ld does not appear to have any intrinsic way of suppressing specific options. One thing that I found useful was limiting the number of duplicate warnings by passing -Wl,--warn-once to g++ (or you can pass --warn-once directly to ld).

Resources