gfortran pour les nuls: Ce n'mcmodel=moyen de faire exactement?
J'ai un code qui me donne de la relocalisation des erreurs lors de la compilation, ci-dessous est un exemple qui illustre bien le problème:
program main
common/baz/a,b,c
real a,b,c
b = 0.0
call foo()
print*, b
end
subroutine foo()
common/baz/a,b,c
real a,b,c
integer, parameter :: nx = 450
integer, parameter :: ny = 144
integer, parameter :: nz = 144
integer, parameter :: nf = 23*3
real :: bar(nf,nx*ny*nz)
!real, allocatable,dimension(:,:) :: bar
!allocate(bar(nf,nx*ny*nz))
bar = 1.0
b = bar(12,32*138*42)
return
end
De la compilation avec gfortran -O3 -g -o test test.f
, j'obtiens l'erreur suivante:
relocation truncated to fit: R_X86_64_PC32 against symbol `baz_' defined in COMMON section in /tmp/ccIkj6tt.o
Mais cela fonctionne si j'utilise gfortran -O3 -mcmodel=medium -g -o test test.f
. Notez également qu'il fonctionne si je fais le tableau affectables et les répartir au sein de la sous-routine.
Ma question est qu'est-ce exactement ne -mcmodel=medium
faire? J'étais sous l'impression que les deux versions de code (l'une avec allocatable
tableaux et l'autre sans) ont été plus ou moins équivalent ...
OriginalL'auteur mgilson | 2012-10-16
Vous devez vous connecter pour publier un commentaire.
Depuis
bar
est assez grande, le compilateur génère allocation statique au lieu d'automatique de l'allocation sur la pile. Les tableaux statiques sont créés avec la.comm
assemblée directive qui crée une allocation dite de section COMMUNE. Les symboles de cette section sont réunis, même nom les symboles sont fusionnés (réduit à un symbole de la demande avec une taille égale à la taille la plus grande de demande) et puis qu'est-ce que le repos est mappé à la BSS (données non initialisée) section dans la plupart des exécutables formats. Avec exécutables ELF la.bss
est situé dans le segment de données, juste avant le segment de données partie du tas (il y a un autre segment de la partie gérée par anonyme mappages de mémoire qui ne réside pas dans le segment de données).Avec le
small
modèle de mémoire de l'adressage 32 bits instructions sont utilisées pour traiter les symboles sur x86_64. Cela rend le code plus compact et aussi plus rapide. Certains assemblée de sortie lors de l'utilisation desmall
modèle de mémoire:Il utilise un 32 bits déplacer à l'enseignement (5 octets de long) à mettre la valeur de la
bar.1535
symbole (cette valeur est égale à l'adresse de l'emplacement du symbole) dans les 32 bits de poids faible de laRBX
registre (le supérieur, 32 bits obtenir à zéro). Lebar.1535
symbole lui-même est alloué à l'aide de la.comm
directive. Mémoire pour lebaz
bloc COMMUN est alloué par la suite. Parce quebar.1535
est très grand,baz_
finit plus de 2 GiB depuis le début de l'.bss
section. Ceci pose un problème dans la deuxièmemovl
instruction depuis une non-32bit (signé) compensation deRIP
doit être utilisé pour répondre à lab
variable dans laquelle la valeur deEAX
doit être déplacé dans. Ce n'est détectée pendant le temps de lien. L'assembleur lui-même ne connaît pas le décalage adéquate, car il ne sait pas ce que la valeur du pointeur d'instruction (RIP
) serait (cela dépend de l'absolu adresse virtuelle où le code est chargé et elle est déterminée par l'éditeur de liens), il met tout simplement un décalage de0
, puis crée un déménagement demande de typeR_X86_64_PC32
. Il indique à l'éditeur de liens pour le patch de la valeur de0
avec la vraie valeur de décalage. Mais il ne peut pas le faire car la valeur de décalage ne serait pas apte à l'intérieur d'un entier signé de 32 bits et donc renflouent.Avec le
medium
modèle de mémoire en place des choses ressembler à ceci:D'abord un 64 bits immédiat vers des instructions (10 octets de long) est utilisé pour mettre la valeur 64 bits qui représente l'adresse de
bar.1535
dans le registreR10
. Mémoire pour lebar.1535
symbole est alloué à l'aide de la.largecomm
la directive et donc il se termine dans la.lbss
section de l'ELFE exécutable..lbss
est utilisé pour stocker des symboles qui peuvent ne pas entrer dans les 2 premières GiB (et par conséquent ne devrait pas être traitées en utilisant 32 bits instructions ou RIP-l'adressage relatif), tandis que les plus petites choses aller à.bss
(baz_
est toujours allouée à l'aide de.comm
et pas.largecomm
). Depuis le.lbss
section est placé après le.bss
section de l'ELFE linker script,baz_
ne serait pas finir par être inaccessible à l'aide de 32 bits RIP liées à l'adressage.Tous les modes d'adressage sont décrites dans le Système V ABI: AMD64 Architecture de Processeur Supplément. C'est une lourde techniques de la lecture, mais d'une lecture indispensable pour quiconque veut vraiment comprendre comment de code 64 bits fonctionne sur la plupart des x86_64 systèmes Unix.
Lorsqu'un
ALLOCATABLE
tableau est utilisé au lieu de cela,gfortran
alloue de la mémoire du tas (probablement mis en œuvre comme un anonyme, un plan de mémoire, compte tenu de la grande taille de l'allocation):C'est fondamentalement
RDI = malloc(2575411200)
. À partir de là, les éléments debar
sont accessibles par le biais positif décalages à partir de la valeur stockée dansRDI
:Pour les endroits qui sont plus de 2 GiB depuis le début de
bar
, une description plus détaillée de la méthode utilisée. E. g. pour mettre en œuvreb = bar(12,144*144*450)
gfortran
émet:Ce code n'est pas affecté par le modèle de mémoire car rien de ce qui est supposé sur l'adresse où l'allocation dynamique. Aussi, puisque le tableau n'est pas passé autour, pas de descripteur de fichier est en cours de construction. Si vous ajoutez une autre fonction qui prend une hypothèse en forme de tableau et passer
bar
, un descripteur pourbar
est créé comme une variable automatique (c'est à dire sur la pile defoo
). Si le tableau est fait statique avec l'SAVE
attribut, le descripteur de fichier est placé dans le.bss
section:Le premier mouvement prépare l'argument d'un appel de fonction (dans mon exemple le cas
call boo(bar)
oùboo
a une interface qui déclare que la prise d'un supposé forme de tableau). Il se déplace à l'adresse du descripteur de tableau debar
enEDI
. C'est un 32 bits immédiate déplacer si le descripteur est prévu pour être dans les 2 premiers GiB. En effet, il est affecté dans le.bss
dans les deuxsmall
etmedium
modèles de mémoire comme ceci:juste pour l'intégralité de la réponse, j'ai ajouté également des explications à ce qui se passe quand
bar
est transmis par un descripteur à un autre sous-programme.OriginalL'auteur Hristo Iliev
Pas, de grands tableaux statiques (comme votre
bar
) peut dépasser la limite si vous n'utilisez pas-mcmodel=medium
. Mais allocatables sont mieux, bien sûr. Pour allocatables seulement le descripteur de tableau doit correspondre à 2 GO, pas l'ensemble du tableau.De GCC référence:
J'ai juste modifié la réponse quand vous avez écrit. Allocatables ont un descripteur (pointeur avec des données supplémentaires) et seulement cela doit s'inscrire dans les 2 GO. Tableau statique est complètement statique segment de même que toute autre variable statique.
(Peut-être qu'il est simplement un pointeur vers le descripteur du segment statique, mais il ne change pas la différence.)
Si je comprends bien la limite de 2 go pour les tableaux statiques ne s'applique plus pour
mcmodel=small
. Est-ce correct?Je pense que cela s'applique, elle ne s'applique pas avec les moyennes et les grandes.
OriginalL'auteur Vladimir F