La retrocompatibilità binaria su Linux è un disastro, non tanto per colpa del kernel ma per colpa di glibc.
Se compili su una macchina moderna e vuoi ottenere un binario portabile dovresti linkare tutte le librerie staticamente (o comunque, portarti dietro tutte le librerie a cui fai riferimento); il problema è che questa cosa non si può fare per glibc, dato che contiene l'implementazione di diverse cose che dipendono dalla specifica configurazione macchina (ad esempio, diverse cose riguardanti il locale e la risoluzione dei DNS, così come il loader dinamico). Per farti un esempio, una volta per sbaglio abbiamo linkato staticamente glibc su una macchina Arch Linux e succedevano cose piuttosto strane su una macchina Ubuntu 16.04 (andava a cercare pezzi in percorsi che non esistevano).
Viceversa, se anche lasci glibc come unica dipendenza dinamica (dato che non si può fare altrimenti), se compili su una macchina recente il tuo binario con ogni probabilità non girerà su una macchina con versioni più vecchie di glibc, dato che (1) vengono introdotti nuovi simboli e (2) glibc fa il versioning dei simboli. Molte funzioni di glibc non sono esportate semplicemente con il loro nome , ma con un nome versionato: quando fai riferimento a diverse funzioni di glibc (diciamo, memcpy) in realtà il tuo eseguibile si riferisce ad un simbolo versionato alla versione più recente fornita dalla glibc sul sistema su cui stai compilando (diciamo, GLIBC_2.2.5 memcpy). Se quindi anche il tuo eseguibile non usa funzioni introdotte in versioni nuove di glibc, probabilmente si romperà comunque perché fa riferimento a simboli già presenti su versioni vecchie, ma ad una versione più recente.
Ancora peggio: glibc in realtà è scorporata in più pezzi, uno dei quali è il linker dinamico (il pezzo che serve a caricare i .so), e nel tuo caso stai facendo un peccato capitale: stai mischiando pezzi diversi di glibc.
Nella tua directory lib ti sei tirato dietro libc.so.6 dalla macchina di build (cosa che non va fatta per gli stessi motivi per cui non bisogna linkare staticamente libc spiegati sopra), e la libc.so.6 "nuova" sta cercando di parlare con il loader di sistema (ld-linux-x86-64.so.2) vecchio. Il risultato è che si rompe tutto.
---
La soluzione che uso di solito è buildare sempre tutto su una macchina con la distribuzione Linux più vecchia che si intende supportare (inteso come versione di glibc), possibilmente linkando tutto staticamente tranne libc.
Se non si linka tutto staticamente, comunque conviene sempre portarsi dietro tutte le librerie tranne libc, onde evitare sorprese.
La cosa funziona perché libc è normalmente backwards-compatibile - ovvero, la glibc nuova ha sempre dentro tutti i simboli forniti dalle glibc vecchie (grazie al versioning dei simboli), per cui su un sistema nuovo il tuo programma troverà sempre gli entrypoint che gli interessano.

Rispondi quotando