Maldus512 / umps_uarm_hello_world

0 stars 3 forks source link

Compilare per uMPS con CMake senza invocare direttamente il linker #3

Closed acsor closed 4 years ago

acsor commented 4 years ago

I makefile di esempio nella repository (in particolare umpsmake) mostrano come ottenere gli eseguibili compilando singolarmente i file oggetto con gcc e linkandoli separatamente con ld. CMake possiede un modo diverso di compilare gli stessi, che consiste nell'invocare il solo compilatore (passando i flag utili al linker con -Wl) ma che non funziona su uMPS.

Obiettivo

Specificare l'insieme corretto di flag affinché il compilatore funzioni correttamente.

Problema

I seguenti passi dovrebbero generare kernel.core.umps ma producono un errore

mkdir build-umps
cd build-umps
cmake -D CMAKE_TOOLCHAIN_FILE=../toolchains/umps.cmake  ..
make kernel.core.umps

Causa

Il compilatore segnala i seguenti messaggi

/usr/lib/gcc-cross/mipsel-linux-gnu/6/../../../../mipsel-linux-gnu/bin/ld: CMakeFiles/kernel.dir/hello.c.obj: relocation R_MIPS_HI16 against `a local symbol' can not be used when making a shared object; recompile with -fPIC
CMakeFiles/kernel.dir/hello.c.obj: error adding symbols: Bad value

Tentativi

Si è cercato di sostituire i flag -fno-abicalls fno-pic con -fabicalls -fPIC. Potrebbe essere una strada percorribile, ma per il momento si ottiene un diverso tipo di errore (sulle macchine di laboratorio)

umps_uarm_hello_world/umps/crtso.S: Assembler messages:
umps_uarm_hello_world/umps/crtso.S:33: Warning: no .cprestore pseudo-op used in PIC code
[ 25%] Linking ASM static library libcrtso.a
...
[100%] Linking C executable kernel
/usr/mipsel-linux-gnu/lib/libc_nonshared.a(elf-init.oS): In function `__libc_csu_init':
(.text+0x48): undefined reference to `__init_array_start'
/usr/mipsel-linux-gnu/lib/libc_nonshared.a(elf-init.oS): In function `__libc_csu_init':
(.text+0x4c): undefined reference to `__init_array_end'

Suggerimenti

  1. Conoscere CMake può essere d'aiuto, ma non è necessario
  2. È possibile ispezionare i comandi seguiti dal Makefile (generato da CMake) facendo make VERBOSE=1 kernel.core.umps
  3. È possibile modificare i flag dati al compilatore editando il file umps.cmake alle righe 8 (flag compilatore) e 14 (linker)

Soluzioni alternative

È già noto un modo alternativo (poco idiomatico, prolisso e un po' difettoso) per compilare correttamente gli eseguibili uMPS, che in essenza imita letteralmente i comandi presenti in umpsmake. Funziona, ma mi piacerebbe migliorarlo (come fatto con uARM).

Maldus512 commented 4 years ago

Prima di tutto grazie per la pull request, l'aggiunta di cmake arricchisce molto l'esempio.

Detto questo, il problema che stai affrontando sembra essere particolarmente spinoso: mentre cercavo di approcciarmici ne sono emersi altri, non necessariamente collegati all'originale. Descrivo i due problemi che ho incontrato io per completezza.

Ostacolo 1

Prima di tutto non sono riuscito a riprodurre l'errore indicato come causa del problema (error adding symbols: Bad value). Generando i Makefile e provando a compilare il progetto il procedimento si ferma su una segnalazione diversa sulla mia macchina:

[100%] Linking C executable kernel
/usr/lib/cross-mipsel-linux-gnu/lib/gcc/mipsel-linux-gnu/9.2.0/../../../../mipsel-linux-gnu/bin/ld: cannot find crt1.o: No such file or directory
/usr/lib/cross-mipsel-linux-gnu/lib/gcc/mipsel-linux-gnu/9.2.0/../../../../mipsel-linux-gnu/bin/ld: cannot find crti.o: No such file or directory
/usr/lib/cross-mipsel-linux-gnu/lib/gcc/mipsel-linux-gnu/9.2.0/../../../../mipsel-linux-gnu/bin/ld: cannot find crtbegin.o: No such file or directory
collect2: error: ld returned 1 exit status
make[3]: *** [CMakeFiles/kernel.dir/build.make:87: kernel] Error 1
make[2]: *** [CMakeFiles/Makefile2:139: CMakeFiles/kernel.dir/all] Error 2
make[1]: *** [CMakeFiles/Makefile2:173: CMakeFiles/kernel.core.umps.dir/rule] Error 2
make: *** [Makefile:157: kernel.core.umps] Error 2

Dal tipo di errore pare che il compilatore cerchi di linkare la stdlib (i vari crt*.o che settano l'ambiente runtime di C), ma il progetto vuole essere standalone. Leggendo i log verbosi traspare che il flag -Wl,-nostdlib e' effettivamente passato al compilatore (e quindi al linker), ma sembra non sortire alcun effetto. La soluzione e' stata aggiungere lo stesso flag direttamente per gcc, modificando la linea 14 di umps.cmake:

set(LDFLAGS_UMPS "-nostdlib -Wl,-G,0,-nostdlib,-T,${LINK_SCRIPT}")

Ostacolo 2

Aggiungendo il flag -nostdlib ridondante la compilazione si conclude ma con un warning:

[100%] Linking C executable kernel
/usr/lib/cross-mipsel-linux-gnu/lib/gcc/mipsel-linux-gnu/9.2.0/../../../../mipsel-linux-gnu/bin/ld: libtermprint.a(termprint.c.obj): warning: linking abicalls files with non-abicalls files
[100%] Built target kernel

E aggiungendo la variabile VERBOSE=1 si vede che effettivamente termprint.c e' compilato senza il flag -mno-abicalls a differenza di tutti gli altri sorgenti (hello.c):

[ 62%] Building C object CMakeFiles/termprint.dir/termprint.c.obj
/usr/bin/mipsel-linux-gnu-gcc -DTARGET_UMPS -I/home/maldus/Projects/pasticci/umps_uarm_hello_world/include -I/home/maldus/Projects/pasticci/umps_uarm_hello_world/umps -I/home/maldus/Projects/pasticci/umps_uarm_hello_world/umps/umps  -ffreestanding -ansi -Wall -std=gnu90 -o CMakeFiles/termprint.dir/termprint.c.obj   -c /home/maldus/Projects/pasticci/umps_uarm_hello_world/termprint.c

Non mi e' chiaro cosa questo warning comporti in pratica, perche' il programma finale gira su umps2 senza problemi. L'unica differenza tra hello.c e termprint.c e' che il secondo e' indicato come libreria in umps.cmake. La mia conoscenza di CMake e' limitata, per cui non so come specificare dei CFLAGS da usare anche per questa tipologia di file; ho risolto rimuovendo termprint dalle librerie e aggiungendolo come dipendenza dell'eseguibile (righe 27 e 28 di umps.cmake):

add_executable(kernel ${SRC}/hello.c ${SRC}/termprint.c)
target_link_libraries(kernel crtso libumps)

In questo modo la compilazione va a buon fine senza segnalazioni straordinarie. Alternativamente, usando i flag -mabicalls e -fPIC il problema non si presenta (presumibilmente perche' sono il comportamento di default in assenza di specifiche, per cui librerie ed eseguibile vengono compilate comunque allo stesso modo).

Problema Iniziale

Rimane il fatto che non sono riuscito a riprodurre il tuo errore. La motivazione piu' probabile e' nella differenza nella versione dei nostri compilatori: io ho la 9.2, mentre nei tuoi log vedo la 6. Per testare questa teoria ti chiederei di provare con una versione comune. Per farlo dovresti compilare una toolchain usando ct-ng come indicato nel README; dovrebbe risultare un mipsel-linux-gnu-gcc versione 8.3.0 (o comunque qualcosa di piu' vicino).

Io sono riuscito a farlo e a compilare con successo il progetto con CMake. Per la toolchain ho usato la configurazione che allego (e' sostanzialmente mipsel-unknown-linux-gnu senza tool di debug e senza supporto per c++, che non ci servono).

config.txt

La compilazione di una toolchain puo' essere molto lunga, anche qualche ora (a seconda delle prestazioni della tua macchina). Provando con una toolchain piu' simile e vedendo cosa succede posso cercare di capire meglio la situazione.

acsor commented 4 years ago

Aggiornamento

In teoria avrei completato il setup da giorni, testandolo in locale (Fedora 31, o meglio crosstools-ng 1.24, gcc 8.3.0) e in laboratorio (Debian 9.9) dove ogni cosa è filata liscia ad eccezione del messaggio di warning. Sciaguratamente i compagni del mio gruppo, che montano Ubuntu 18.04 LTS e Linux Mint 19.3, ottengono una compilazione apparentemente priva di difetti, ma dei kernel panic nell'esecuzione del codice.

Vorrei scaricarmi in locale, rapidamente magari con Docker, le versioni dei loro sistemi per controllare ed eventualmente sistemare. Se la cosa dovesse tirare per le lunghe mi limiterò a suggerire il setup proposto, specificando la non interoperabilità per uMPS (con uARM subìto nessuna anomalia finora).

Sistemazione

La soluzione e' stata aggiungere lo stesso flag direttamente per gcc, modificando la linea 14 di umps.cmake:

Lo è stata nel suo caso come nel nostro. Pare fosse necessario, nella fase di linkaggio, passare -nostdlib sia a gcc che al linker successivamente, tramite -Wl.

Rimane il fatto che non sono riuscito a riprodurre il tuo errore. La motivazione piu' probabile e' nella differenza nella versione dei nostri compilatori

Guardi, io all'inizio ne avevo uno a 64 bit (gcc-mips64-linux-gnu) dalle repository di Fedora, ed è più probabile che l'errore dipendesse proprio da qualche incongruenza. Usare crosstools-ng ha risolto, ora sono soltanto curioso del perché la compilazione non vada su Ubuntu e Mint.

acsor commented 4 years ago

Ho appena caricato le ultime modifiche al file README.md. Purtroppo i problemi che ho evidenziato nell'ultimo aggiornamento persistono nelle distro dei miei compagni (ho difficoltà a metterci mano di presenza) ma li abbiamo superati installando le toolchain con crosstool-ng. Confesso che alle volte ho dubitato sul fatto che le toolchain (fornite dalle distro) funzionassero come avrebbero dovuto.

Ho testato in locale (Fedora 31, toolchain uMPS installata con crosstool-ng) e in laboratorio (Debian 9.9, toolchain di sistema) e tutto è filato liscio. Suggerisco di verificare il setup allo stato corrente e, in caso positivo, chiudere quest'issue.

Edit: testato con successo anche in Debian 10.3 con toolchain di sistema.

Maldus512 commented 4 years ago

Ho finalmente avuto modo di testare la PR; anche sul mio sistema (Arch Linux) la compilazione e l'esecuzione dell'esempio si concludono con successo. Testato con arm-none-eabi-gcc versione 9.2.0 (per uARM) e mipsel-linux-gnu-gcc versione 9.2.0 (per uMPS2).

Grazie per il contributo, procedo con il merge