#include <string.h> char *qq, *aa; int main(int argc, char **argv) { char *q = qq; int n; n = strlen(aa); strcpy(q, aa); q += n; *q = 0; return 0; }(Irrelevant parts removed.) What is wrong? Why does the web server react with the "page not found" reaction of showing its home page? The binary was executable, permissions OK.
% readelf -a test ... Version needs section '.gnu.version_r' contains 1 entries: Addr: 0x0000000000400390 Offset: 0x000390 Link: 6 (.dynstr) 000000: Version: 1 File: libc.so.6 Cnt: 2 0x0010: Name: GLIBC_2.14 Flags: none Version: 3 0x0020: Name: GLIBC_2.2.5 Flags: none Version: 2 ...Hmm. Why does it need GLIBC_2.14? That is a rather recent library. And indeed, this turns out to be the culprit. The dynamic loader fails, and programs that refer to GLIBC_2.14 are non-executable on this web server.
% readelf -a test | grep 2.14 4: 0000000000000000 0 FUNC GLOBAL DEFAULT UND memcpy@GLIBC_2.14 (3) 59: 0000000000000000 0 FUNC GLOBAL DEFAULT UND memcpy@@GLIBC_2.14 004: 3 (GLIBC_2.14) 0x0010: Name: GLIBC_2.14 Flags: none Version: 3Interesting. So my program does not call the function memcpy, but it does call strlen and strcpy and the compiler decides that it would be better to use memcpy, and forces a memcpy from a recent glibc. That means that the compiler output cannot be used on older machines. Bad. Smells like a gcc bug.
__asm__(".symver memcpy,memcpy@GLIBC_2.2.5");and that works. One can also compile on an older machine, or compile a private version of the toolchain. But such nonsense should not be necessary for very simple programs that have worked for dozens of years. There is a blog discussion fun with shared libraries — version GLIBC_2.14 not found, and an old article in lwn.
The original discussion was about the difference between memcpy and memmove, and that in some implementations the former can only be used on non-overlapping areas. This leads to bugs such a this one in mksquashfs, and this one (with comments from Linus) in the 64bit flash plugin.
That old working programs were suddenly broken was because of the patch by HJLu that was supposed to gain a few ns by copying backwards, but ended up costing thousands of developer hours. Linus tried to measure whether there was a speedup and did not find any.
Andreas Schwab (reacting as if flashplayer were the only program broken by this glibc change) comments: "Tell adobe" and "The only stupidity is crap software violating well known rules that have existed forever". Linus disagrees, gave an LD_PRELOAD workaround, and says "I'd personally suggest that glibc just alias memcpy() to memmove()."
So that was the old saga. HJLu changed glibc. Technically it was doubtful whether the change was a good idea. Maybe there was no speedup. Many old programs broke, a lot of Linux developer time was spent in figuring out why, and there was a lot of discussion. Of course technically such a change is OK, at least if there actually is a speedup and only undefined behavior is broken. See also this discussion. The result was that memcpy@GLIBC_2.2.5 was aliased to memmove (so old binaries remain happy), and memcpy resolves to memcpy@@GLIBC_2.14.
__asm__(".symver memcpy,memcpy@GLIBC_2.2.5");as a lasting memory of this glibc debacle. I just added it to my code as well.