13 votes

Obtenir la compilation de GCC sans insérer l'appel à memcpy

J'utilise actuellement GCC 4.5.3, compilé pour PowerPC 440, et je compile du code qui ne nécessite pas libc. Je n'ai pas d'appels directs à memcpy(), mais le compilateur semble en insérer un pendant la compilation.

Il y a des options de linker comme -nostdlib, -nostartfiles, -nodefaultlibs mais je ne peux pas les utiliser car je ne fais pas la phase de liaison. Je ne fais que compiler. Avec quelque chose comme ceci :

$ powerpc-440-eabi-gcc -O2 -g -c -o output.o input.c

Si je vérifie le fichier output.o avec nm, je vois une référence à memcpy :

$ powerpc-440-eabi-nm output.o | grep memcpy
     U memcpy
$ 

La page de manuel de GCC explique clairement comment supprimer les appels à memcpy et autres appels à la libc avec l'éditeur de liens, mais je ne veux pas que le compilateur les insère en premier lieu, car j'utilise un éditeur de liens complètement différent (pas ld de GNU, et il ne connaît pas la libc).

Merci de toute l'aide que vous pourrez m'apporter.

9voto

technosaurus Points 1980

Il n'est pas nécessaire de -fno-builtins o -ffreestanding car ils désactiveront inutilement de nombreuses optimisations importantes

Ceci est en fait "optimisé" par les modèles de distribution en boucle d'arbre de gcc, donc pour désactiver le comportement non désiré tout en gardant les capacités construites utiles, vous pouvez simplement utiliser :

-fno-tree-loop-distribute-patterns

Musl-libc utilise ce drapeau pour sa construction et a la note suivante dans leur configure script (j'ai regardé à travers la source et n'a pas trouvé de macros, donc ceci debe être suffisante)

# Vérifier les options qui peuvent être nécessaires pour empêcher le compilateur de
# générer des versions auto-référentielles de memcpy,, memmove, memcmp,
# et memset. Vraiment, nous devrions ajouter une vérification pour déterminer si ce
# est suffisante, et si ce n'est pas le cas, ajouter une macro pour paralyser ces
# fonctions avec volatile...
# tryflag CFLAGS_MEMOPS -fno-tree-loop-distribute-patterns

Vous pouvez également l'ajouter comme attribut à des fonctions individuelles dans gcc en utilisant son attribut optimize, afin que d'autres fonctions puissent bénéficier de l'appel à mem*()

6voto

Droopycom Points 1534

Gcc émet un appel à memcpy dans certaines circonstances, par exemple si vous copiez une structure. Il n'y a aucun moyen de changer le comportement de GCC mais vous pouvez essayer d'éviter cela en modifiant votre code pour éviter une telle copie. Le mieux est de regarder l'assemblage pour comprendre pourquoi GCC a émis le memcpy et essayer de le contourner. Cela va être ennuyeux cependant, puisque vous devez fondamentalement comprendre comment fonctionne gcc.

Extrait de http://gcc.gnu.org/onlinedocs/gcc/Standards.html :

La plupart des routines de support du compilateur utilisées par GCC sont présentes dans libgcc, mais il y a quelques exceptions. GCC exige que l'environnement autonome fournisse memcpy, memmove, memset et memcmp. Enfin, si __builtin_trap est utilisé, et que la cible n'implémente pas le motif trap, alors GCC émettra un appel à l'abandon.

5voto

Richard Pennington Points 12912

Vous devez désactiver cette optimisation avec -fno-builtin. J'ai eu ce problème une fois en essayant de compiler memcpy pour une bibliothèque C. Il s'est appelé lui-même. Oups !

4voto

phresnel Points 20082

Vous pouvez également faire de votre binaire un binaire "indépendant" :

La norme ISO C définit (dans la clause 4) deux classes d'implémentation conforme. Une implémentation hébergée conforme prend en charge l'ensemble de la norme [...] ; une implémentation autonome conforme n'est tenue de fournir que certaines fonctionnalités de bibliothèque : celles de , , , et ; depuis AMD1, également celles de ; et dans C99, également celles de et [...].

La norme définit également deux environnements pour les programmes, un environnement autonome, requis pour toutes les implémentations et qui peut ne pas avoir d'installations de bibliothèque au-delà de celles requises pour les implémentations autonomes, où la gestion du démarrage et de la fin du programme est définie par l'implémentation, et un environnement hébergé, qui n'est pas requis, dans lequel toutes les installations de bibliothèque sont fournies et le démarrage se fait par une fonction int main (void) ou int main (int, char *[]).

Le noyau d'un système d'exploitation est un environnement indépendant ; un programme utilisant les fonctionnalités d'un système d'exploitation se trouve normalement dans une implémentation hébergée.

(paragraphe ajouté par moi)

Plus de ici . Et la ou les options gcc correspondantes (mots-clés -ffreestanding ou -fno-builtin ) peut être trouvé ici .

1voto

projix Points 11

C'est une vieille question, mais j'ai rencontré le même problème, et aucune des solutions proposées ici n'a fonctionné.

J'ai donc défini cette fonction :

static __attribute__((always_inline)) inline void* imemcpy (void *dest, const void *src, size_t len) {
  char *d = dest;
  const char *s = src;
  while (len--)
    *d++ = *s++;
  return dest;
}

Et je l'ai utilisé à la place de memcpy. Cela a résolu le problème d'inlining pour moi de façon permanente. Pas très utile si vous compilez une sorte de bibliothèque cependant.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X