Relatif à cette autre question. J’essaye de lancer ce programme simple en gem5:
int main() { int a=1, b=2; int c=a+b; return c; }
Et cela échoue car gem5 n’a pas implémenté d’appels système.
Ma question est la suivante: pourquoi un programme simple comme celui-ci aurait-il besoin d’appels système? Cela devrait fonctionner en métal nu sans problème. Est-il possible de comstackr cela pour éviter les appels système? J’utilise arm-linux-gnueabi-gcc -static -DUNIX pour le comstackr.
Sans appels système, le programme ne peut pas quitter. La façon dont cela fonctionne est généralement quelque chose comme ceci:
// Not how it's actually implemented... just a sketch. void _start() { char **argv = ...; int argc = ...; // ... other initialization code ... int retcode = main(argc, argv); exit(retcode); }
Les détails exacts dépendent du système d’exploitation, mais exit()
, qui termine le processus, doit généralement être un appel système ou doit être implémenté avec des appels système.
Notez que cela est vrai pour les implémentations C “hébergées”, pas pour les implémentations C “autonomes”, et dépend fortement du système d’exploitation. Il existe des implémentations C autonomes pouvant fonctionner sur du métal nu, mais les implémentations C hébergées nécessitent généralement un système d’exploitation.
Vous pouvez comstackr sans bibliothèques standard et sans le runtime, mais votre point d’entrée ne peut pas retourner … il n’y a rien vers lequel retourner, sans un runtime.
Il est généralement possible de comstackr des programmes capables d’exécuter baremetal.
Utilisez -ffreestanding
. Cela fait que GCC génère un code qui ne suppose pas que la bibliothèque standard est disponible (et a d’autres effets).
Utilisez -nostdlib
. Cela empêchera GCC de se lier à la bibliothèque standard. Notez que les memcmp
, memset
, memcpy
et memmove
peuvent être générés de toute façon, vous devrez donc peut-être les fournir vous-même.
À ce stade, vous pouvez écrire votre programme, mais vous devez généralement utiliser _start
au lieu de main
:
void _start(void) { while (1) { } }
Notez que vous ne pouvez pas revenir de _start
! Pensez-y … il n’y a nulle part où retourner. Lorsque vous comstackz un programme comme celui-ci, vous constatez qu’il n’utilise aucun appel système et n’a pas de chargeur.
$ gcc -ffreestanding -nostdlib test.c
Nous pouvons vérifier qu’il ne charge aucune bibliothèque:
$ ldd a.out lié statiquement $ readelf -d a.out La section dynamic au décalage 0xf30 contient 8 entrées: Type de tag Nom / Valeur 0x000000006ffffef5 (GNU_HASH) 0x278 0x0000000000000005 (STRTAB) 0x2b0 0x0000000000000006 (SYMTAB) 0x298 0x000000000000000a (STRSZ) 1 (octets) 0x000000000000000b (SYMENT) 24 (octets) 0x0000000000000015 (DEBUG) 0x0 0x000000006ffffffb (FLAGS_1) drapeaux: PIE 0x0000000000000000 (NULL) 0x0
Nous pouvons également constater qu’il ne contient aucun code permettant d’effectuer des appels système:
$ objdump -d a.out a.out: format de fichier elf64-x86-64 Déassembly de la section .text: 00000000000002c0 <_start>: 2c0: eb fe jmp 2c0 <_start>
Ma question est la suivante: pourquoi un programme simple comme celui-ci aurait-il besoin d’appels système?
Le chargeur au moment de l’exécution, ld.so
effectue des appels système. L’exécution C fait des appels système. Faites strace
et voyez.
Il est possible que vous souhaitiez extraire certains parameters de gcc. Entre autres:
Ma question est la suivante: pourquoi un programme simple comme celui-ci aurait-il besoin d’appels système?
Parce que l’entrée principale et la sortie du programme sont basées sur des appels système.
Comstackr avec arm-unknown-linux-uclibcgnueabi a résolu le problème. Apparemment, l’implémentation uclibc n’utilise pas les appels système que gem5 n’a pas implémentés.