`Relocation truncated to fit` error in Fortran with large arrays - fortran

I have written a Fortran 90 code to extract angles from molecular simulation data.
In this code I used a module with name all_parameter. In this module I defined an array such as: CH_Angles
INTEGER,PARAMETER :: totalFrames = 32000
INTEGER,PARAMETER :: AAA=75
REAL,DIMENSION(45:AAA,1:256,1:totalFrames) :: CH_Angles
If I use the value of AAA = 75, I can compile this code without any error and I can get the values I wanted. But if I change the value of AAA to be AAA=105, then I get some error messages as shown below:
gfortran lipid-Tilt-Magnitude-thermo-cello.f90
/tmp/ccXOhMqQ.o: In function `__all_parameter_MOD_find_angle_ch':
lipid-Tilt-Magnitude-thermo-cello.f90:(.text+0x35): relocation truncated to fit: R_X86_64_32S against symbol `__all_parameter_MOD_x' defined in .bss section in /tmp/ccXOhMqQ.o
lipid-Tilt-Magnitude-thermo-cello.f90:(.text+0x48): relocation truncated to fit: R_X86_64_32S against symbol `__all_parameter_MOD_y' defined in .bss section in /tmp/ccXOhMqQ.o
lipid-Tilt-Magnitude-thermo-cello.f90:(.text+0x5b): relocation truncated to fit: R_X86_64_32S against symbol `__all_parameter_MOD_z' defined in .bss section in /tmp/ccXOhMqQ.o
lipid-Tilt-Magnitude-thermo-cello.f90:(.text+0x6e): relocation truncated to fit: R_X86_64_32S against symbol `__all_parameter_MOD_x' defined in .bss section in /tmp/ccXOhMqQ.o
lipid-Tilt-Magnitude-thermo-cello.f90:(.text+0x81): relocation truncated to fit: R_X86_64_32S against symbol `__all_parameter_MOD_y' defined in .bss section in /tmp/ccXOhMqQ.o
lipid-Tilt-Magnitude-thermo-cello.f90:(.text+0x94): relocation truncated to fit: R_X86_64_32S against symbol `__all_parameter_MOD_z' defined in .bss section in /tmp/ccXOhMqQ.o
/tmp/ccXOhMqQ.o: In function `__all_parameter_MOD_find_mid_point_vector':
lipid-Tilt-Magnitude-thermo-cello.f90:(.text+0x126): relocation truncated to fit: R_X86_64_32S against symbol `__all_parameter_MOD_x' defined in .bss section in /tmp/ccXOhMqQ.o
lipid-Tilt-Magnitude-thermo-cello.f90:(.text+0x139): relocation truncated to fit: R_X86_64_32S against symbol `__all_parameter_MOD_y' defined in .bss section in /tmp/ccXOhMqQ.o
lipid-Tilt-Magnitude-thermo-cello.f90:(.text+0x14c): relocation truncated to fit: R_X86_64_32S against symbol `__all_parameter_MOD_z' defined in .bss section in /tmp/ccXOhMqQ.o
lipid-Tilt-Magnitude-thermo-cello.f90:(.text+0x15f): relocation truncated to fit: R_X86_64_32S against symbol `__all_parameter_MOD_x' defined in .bss section in /tmp/ccXOhMqQ.o
lipid-Tilt-Magnitude-thermo-cello.f90:(.text+0x172): additional relocation overflows omitted from the output
collect2: ld returned 1 exit status
vijay#glycosim:~/Simulation-Folder-Feb2013/chapter5-thermo-paper2-Vj/thermo2-Analysis/analysis-bcm-/23_acf-tail-tilt-angle-bcm-thermo2/chain1/acf-chain1-CH-bcm-thermo-all-layers$ gfortran lipid-Tilt-Magnitude-thermo-cello.f90
I also tried compiling this code with different values for AAA. With a value 80, the compilation goes without error. But, if the AAA is 85, then the compilation stop with error messages.
I found the AAA=82 is the limiting value. Any value of AAA more than 82, it gives error.
I can not figure out what causes the error.
Is there anyway to find solution for this issue?
Note: I am using gfortran compiler from Ubuntu 11.10 64 bit with 16 GB RAM memory.

The error you get is returned by the linker because the size of the statically-allocated block exceeds the range of what can be addressed by a 32-bit addressing instruction, which is 2 GB. This is irrelevant of whether you index your array using 32-bit or 64-bit integers - the problem is related to the total size of a statically-allocated array. This is explained in details here:
gfortran for dummies: What does mcmodel=medium do exactly?
In order to work around this, as you have noticed, you can compile your code with -mcmodel=medium or -mcmodel=large. Statically-allocated arrays larger than 2 GB are then allowed.
A better way to deal with this, but involves more work, is to dynamically allocate any large arrays.

If I remember aright, gfortran, like most current Fortran compilers, still defaults to 4-byte integers even on 64-bit hardware. This means, inter alia, that the largest array index will be 2^31 or 2^32. Since multi-rank arrays are just a convenient wrapper for rank-1 arrays it's no surprise to me (or to #MikeDunlavey) that your compiler baulks at allocating an array with so many elements as you want.
Try using 64-bit integers for array indexing. You could do this either by explicitly setting the kind for them, eg
use, intrinsic :: iso_fortran_env, only : int64
...
INTEGER(int64),PARAMETER :: totalFrames = 32000
INTEGER(int64),PARAMETER :: AAA=75
REAL,DIMENSION(45_int64:AAA,1_int64:256_int64,1_int64:totalFrames) :: CH_Angles
or by using a compiler flag to set the default size of integers to 64 bits. For gfortran this would be -fdefault-integer-8.
I won't guarantee that this will work for gfortran, which is not a compiler I use regularly, but it does for Intel Fortran.

Your array CH_Angles is pushing a gigabyte in size, so index arithmetic is going to push the 32-bit limit.
I would expect things to get a bit screwy at that size.

Related

Why GNU ld is leaving a hole in memory?

I am using GNU linker for ppc 32-bit platform.
As I look at the size of "rodata" section and try to tally it against the symbols in that section, I am seeing that there are some memory holes, which are not assigned any symbol, but contribute to the size of the section.
One such hole is seen here
ffffc970 00000050 r _ZL10RING_INDEX
ffffcb68 00000020 r _ZZ19p9_pm_check_quiesceE15SPWKUP_SRC_REGS
Though the size of symbol is 0x50, there is a gap of about 424 bytes(0xffffcb68 - 0xffffc970 - 0x50) before the next symbol in memory. Can we explain this gap? Is there a way to prevent such gaps?
It could be filled with nameless data e.g. string constants. It's hard to give a more precise answer without a reprocase.

fixing fortran common relocation truncated to fit R_X86_64_32S and modules

I have an old Fortran 77 code written around many subroutines, each subroutine in a separate file, and they make extensive use of COMMON statements. I've profiled the code, out of the 18 total include files I found two that are the heavy hitters which declare the largest static arrays.
For example, my global.par parameter file defines
C keep nodes/elements below 400000 / 600000 to prevent relocation
C truncated to fit compiler error
INTEGER MAXNODES
PARAMETER ( MAXNODES = 1000000 )
INTEGER MAXELEMS
PARAMETER ( MAXELEMS = 4000000 )
then this parameter file I now include in two re-written include files that I turned into modules. However each of these new module files does everything the same as before in regards to declaring static arrays such as
C this module file name is aa_module.f
MODULE AA
IMPLICIT NONE
INCLUDE 'global.par'
REAL NODES (3, MAXNODES)
REAL NODES2 (3, MAXNODES)
INTEGER EL1 (12, MAXELEMS)
INTEGER EL2 (12, MAXELEMS)
C and so on, many more arrays based around MAXNODES & MAXELEMS
END MODULE AA
When I compile and link the program, if I keep the MAXNODES and MAXELEMS small things will work. But I need to handle large models so when I jack up those values I still get the message
relocation truncated to fit: R_X86_64_32S against symbol... defined in COMMON section in AA_module.o.
What is the best solution to this? My knowledge of Fortran is limited.
If I create a new subroutine, called Init_big_arrays for example, and ALLOCATE all those arrays in Module AA at runtime will that solve this problem, keeping in mind there are still 16 or so other include files that declare a bunch of static integer and real arrays based on parameters in the global.par file but the worst of those is something like INTEGER ID(256,256) and CHARACTER*256 NAME(3,256)?

How do relocations work in COFF object (not image) files

What steps exactly are taken by the linker while resolving relocations in an object file before creating the final image? More specifically, how does the linker treat the value which is already stored at the relocation site? Does it always add it to the final VA/RVA, or is it sometimes ignored (e.g certain relocation types)?
I couldn't find a clear explanation in the MS PE/COFF Specfication, and after googling and experimenting for a while, all I could find out was this:
In the MS COFF spec, chapter 5.6.2 "Base Relocation Types", it is said that "The base relocation applies all 32 bits of the difference to the 32-bit field at offset", which I guess means that the relocation should take into account whatever address is already stored at the specified offset. However, chapter 5.6 (the .reloc section) is only relevant to image files, and not object files.
The dumpbin utility adds a column named "Applied To" when printing the relocations table, which seems to always (no matter the relocation type) contain the value which is stored at the relocation site.
The Relocation Directives chapter in the DJGPP COFF Specification clearly states that the value currently stored at the location should be added to the address of the symbol pointed to by the relocation table entry.
Can you point me to any (relevant) documentation which explains how relocations are handled by the linker?
The relocation section used in "image files" has a slightly different purpose from the relocation information present in "object files".
Unlike Linux Shared Libraries, Windows DLLs do not typically use position independent code. Instead they are defined relative to a fixed based address. The Windows loader, however, has the ability to relocate a DLL in the event of a conflict. To support this, DLL images contain relocation sections that specify what data needs to be modified when the image is relocated. Many intra-dll symbol references will use "eip" (or rip) relative addressing, so they may not need to be modified on DLL relocation.
Image file relocations are always specified relative to the base address of the executable image. Object file relocations are specified relative to the address (within an image, using the images preferred based address) of a symbol in a symbol table. Image files don't have a symbol table (they have an IAT, but that's not a symbol table). The set of supported relocations in object files is richer then the set supported in image files.
The details are covered in the "COFF Relocations (Object Only)" section of the PE/COFF spec (I'm looking at version 3 as I type this).

A very long boolean array/std::bitset

For some C++ code, my logic requires a boolean array containing 4*10^10 indices. I am using the STL container std::bitset. But its implementation as template < size_t N > class bitset; restricts the number of bits to the upper limit of the size_t (unsigned integral type) data type, which is 2^32-1 (or 2^64-1) {Can someone confirm this as well}.
I thought of a workaround for this issue by creating an array of bitset, as in bitset<100000000> checkSum[400];
Is this legal? I am getting the following compilation error (test.cpp is my C++ file)
/tmp/cc0gR0c6.o: In function `__static_initialization_and_destruction_0(int, int)':
test.cpp:(.text+0x35f): relocation truncated to fit: R_X86_64_32 against `.bss'
test.cpp:(.text+0x373): relocation truncated to fit: R_X86_64_32 against `.bss'
collect2: ld returned 1 exit status
Can this somehow be fixed or is there a better workaround?
I think you should use vector instead of array,just like:
vector<bitset<1000000> > checkSum;
size_t is either 32 or 64 bits, depending whether you're compiling 32 or 64 bit code. It looks like you can simply compile for a 64 bit target and solve this.

how to use macro for a unsigned long number?

Here're my codes:
#define MSK 0x0F
#define UNT 1
#define N 3000000000
unsigned char aln[1+N];
unsigned char pileup[1+N];
void set(unsigned long i)
{
if ((aln[i] & MSK) != MSK ) {
aln[i] += UNT;
}
}
int main(void) {}
When I try to compile it, the compiler complains like this:
tmp/ccJ4IgSa.o: In function `set':
bitmacs.c:(.text+0xf): relocation truncated to fit: R_X86_64_32S against symbol `aln' defined in COMMON \
section in /tmp/ccJ4IgSa.o
bitmacs.c:(.text+0x29): relocation truncated to fit: R_X86_64_32S against symbol `aln' defined in COMMON\
section in /tmp/ccJ4IgSa.o
bitmacs.c:(.text+0x32): relocation truncated to fit: R_X86_64_32S against symbol `aln' defined in COMMON\
section in /tmp/ccJ4IgSa.o
I think the reason may be the N is too big, because it can compile successfully if I change N to 2000000000. But I need 3000000000 as the value of N..
Anyone has idea about that?
Per your original question: use the integer literal suffix UL (or similar) to force the storage type of N:
#define N 3000000000UL
However, (per your comment on HLundvall's answer) the relocation truncated to fit error obviously isn't due to this - it may (as Mystical and Matt Lacey say) simply be too big to fit in the segment.
As an aside, if you ask a seperate question explaining what you're trying to accomplish with your huge arrays, someone may be able to suggest a better solution (that is more likely to fit in memory)
For example:
your sample code is only using the low nibble of each byte in the code shown: you could pack this into half the size (which is admittedly still much too large)
depending on your access patterns, you might be able to keep the array on disk and cache a working subset in memory
there may be better overall algorithms and data structures if we knew what you needed
Disregarding the "formal" problem that your numeric literal isn't of the correct type (see the other answers for the correct syntax), the key point here is that it's a very bad idea to allocate a 3 GB static/global array.
static and global1 variables on most platforms are mapped directly from the executable image, which means that your executable would have to be as big as 3 GB, which is quite big even for current day standards. Even if on some platforms this limitation may be lifted (see the comments), you don't have any control on how to handle the failure of allocation.
Most importantly, global variables are not intended for such big stuff, and you are likely to find problems with arbitrary limits imposed by the linker (such as the one you found) and the loader. Instead, you should allocate anything that's bigger than a few KBs on the heap, using malloc, new or some platform-specific function, handling gracefully the possible failure at runtime.
Still, keep in mind that for an application running under almost any 32 bit operating system it's not possible to get 3 GB of contiguous memory as you request, and it's impossible altogether to get more than one of these arrays (=more than 4 GB of contiguous memory) without resorting to platform-specific tricks (e.g. mapping only specific parts of the arrays in memory at a given moment).
Also, are you sure that you do need all that contiguous memory since your program starts to run? Isn't there some better data structure/algorithm that could avoid allocating all that memory?
In general, what the standard calls variables with static storage duration.
To enter a numeric constant of type unsigned long use:
#define N 3000000000UL
The problem is that gcc (by default) uses pc-relative accesses to get the address of static data objects on x86_64 targets, and those accesses are limited to 2^31 bytes maximum. So if the symbol ends up getting placed more than 2GB away from the code that accesses it, you'll end up getting this link error when it tries to use an offset that is too big to fit in the 32 bits of space allowed in the instruction.
You can avoid this problem by using the -mcmodel=large option to gcc. This tells it to not assume that it can use 32-bit PC relative offsets to access symbols (among other things)
Note that the type suffix of the constant literal is mostly irrelevant -- a constant literal that is too big for an int will automatically become a long (or even long long if needed) without any suffix. See 6.4.4.1.5 of the C99 spec.
Your executable is trying to put objects in memory past the 4GB mark, which is not allowed. See this link: http://www.technovelty.org/code/c/relocation-truncated.html.
From the article: "If you're seeing this and you're not hand-coding, you probably want to check out the -mmodel argument to gcc."