2016-09-28 1 views
0

J'ai écrit un compilateur lua minimal à des fins éducatives en traduisant le code lua en assembly inline en C avec gcc. Après un certain temps lorsque ma sortie générée a commencé à s'allonger avec plus d'opérandes pour les variables et les fonctions déclarées en C, cette erreur a commencé à se produire.Comment éviter l'erreur "plus de 30 opérandes dans 'asm'" avec inline assesmbly avec gcc

test.c: In function ‘int main()’: 
test.c:100:6: error: more than 30 operands in ‘asm’ 
    ); 

Lorsque googler la seule autre information que j'ai trouvé some gcc mailing list from 2008, mais ils ont dit qu'il n'y avait pas de solution à l'exception de gcc recompiler (que je ne suis pas intéressé). Le point ironique est que souvent je n'ai même pas 30 opérandes et j'ai toujours cette erreur!

Voici un exemple minimal (avec 19 opérandes, me donne encore cette erreur)

// Standard functions 
void io_read(){} 
void io_write(){} 
void print(){} 
int main(){ 
    // Working vars decl 
    long _t0, _t1, _t2, _t3, _t4, _t5, _t6, _t7, _t8; 
    long factorial, i, n, x; 
    // Strings decl 
    const char* _s0 = "enter a number:"; 
    const char* _s1 = "*number"; 
    const char* _s2 = "factorial of "; 
    const char* _s3 = " is "; 
    asm("" // My inline asm code 
    : // Output symbols 
     [_s0] "+g" (_s0), 
     [_s1] "+g" (_s1), 
     [_s2] "+g" (_s2), 
     [_s3] "+g" (_s3), 
     [_t0] "+g" (_t0), 
     [_t1] "+g" (_t1), 
     [_t3] "+g" (_t3), 
     [_t4] "+g" (_t4), 
     [_t5] "+g" (_t5), 
     [_t6] "+g" (_t6), 
     [_t7] "+g" (_t7), 
     [_t8] "+g" (_t8), 
     [factorial] "+g" (factorial), 
     [i] "+g" (i), 
     [n] "+g" (n), 
     [x] "+g" (x) 
    : // Input symbols 
     [io_read] "r" (io_read), 
     [io_write] "r" (io_write), 
     [print] "r" (print) 
    : // Clobbers 
     "cc", "rax", "rbx", "rcx", "rdx" 
    ); 
} 

Ma version gcc est 6.2.1 20.160.830

Merci à l'avance!

+1

Réutilisez des variables ou créez des tables (tableaux) et utilisez des offsets dans ces tableaux pour obtenir des variables (insérées dans le code d'assemblage par votre compilateur). –

+2

Envisager d'émettre un assemblage correct au lieu de l'assemblage en ligne. gcc a une limite de 30 opérandes pour l'assemblage en ligne et il n'est pas prévu de supprimer cette limite. – fuz

+6

Ne pas générer du code C serait beaucoup plus facile et plus simple à déboguer? Et pourquoi ne générez-vous pas directement un fichier Assmbler? Pas d'infraction, mais cette étape intermédiaire C ressemble beaucoup à un non-sens pour moi. – Olaf

Répondre

1

Je n'ai donc pas trouvé de solution directe au problème, mais grâce au Ross Ridge, j'ai pu contourner le problème.

Le premier changement que j'ai fait était de changer "+ g" avec "g" si possible. Apparemment, "+ g" compte comme deux opérandes car il permet à la fois de lire et d'écrire, donc j'ai remplacé les onces possibles par "g" qui ne permet que l'écriture.

En outre, j'ai été en mesure de supprimer complètement mes fonctions en tant qu'opérandes en les déplaçant vers une portée globale et en appelant ensuite directement avec "call print" au lieu de "call% [print]". Il convient de noter cependant que cela ne fonctionne qu'avec C en ligne et ne fonctionnera pas avec C++ en ligne.

Si vous écrivez un compilateur comme moi, je vous recommande de rester loin de l'assemblage en ligne. On dirait que plus de problèmes, il suffit d'appeler des fonctions C à partir Assembleur serait manuellement plus facile, et je certainement pas faire un compilateur sur une plus grande échelle avec ligne C.

EDIT: J'ai commencé à forcer « m » et « + m » aussi au lieu d'utiliser "g" et forcer des variables sur la pile qui semble fonctionner correctement.

+0

'" = g "' est en écriture seulement. '" g "' est en lecture seule. IDK pourquoi vous voulez sortir inline-asm du tout. Cela semble être une idée horrible. Juste sortie pure C, ou pure asm (en un '.s' qui définit' main'). Passer des appels de fonction depuis l'intérieur d'inline asm n'est même pas sûr, car vous ne pouvez pas dire à gcc que vous voulez écraser la zone rouge. Prendre des pointeurs de fonction en tant qu'entrées dans votre inline-asm est vraiment horrible, puisque vous obtenez un appel indirect de registre ou de mémoire à travers un pointeur de fonction réel. –

+0

Vous omettez toujours la mention '" = m "' ou '" = g "', ce que vous devriez utiliser lorsque la sortie est en écriture seule. Je recommanderais d'utiliser autant d'opérandes +/=/'g' que le permet gcc, et +/= /' m' pour le reste, puisque forcer tout dans la pile produirait du garbage asm. (Bien que si vous avez déjà clobé tous les registres et que vous vous enregistrez vous-même, ce que j'imagine, puisque vous devez éviter de produire addl mem, mem ou quoi que ce soit, tout sera sur la pile, sauf les constantes immédiates. Donc vous devriez toujours utiliser 'g' pour les entrées, pour autoriser les instantanés.) –