Dhiraj
Dhiraj

Reputation: 61

MingW Windows GCC cant compile c program with 2gb global data

GCC/G++ of MingW gives Relocation Errors when Building Applications with Large Global or Static Data.

Understanding the x64 code models

References to both code and data on x64 are done with instruction-relative (RIP-relative in x64 parlance) addressing modes. The offset from RIP in these instructions is limited to 32 bits.

small code model promises to the compiler that 32-bit relative offsets should be enough for all code and data references in the compiled object. The large code model, on the other hand, tells it not to make any assumptions and use absolute 64-bit addressing modes for code and data references. To make things more interesting, there's also a middle road, called the medium code model.

For the below example program, despite adding options-mcmodel=medium or -mcmodel=large the code fails to compile

#define SIZE 16384
float a[SIZE][SIZE], b[SIZE][SIZE];

int main(){
return 0;
}

gcc -mcmodel=medium example.c fails to compile  on MingW/Cygwin Windows, Intel windows /MSVC

Upvotes: 0

Views: 804

Answers (1)

Daniel Santos
Daniel Santos

Reputation: 3295

You are limited to 32-bits for an offset, but this is a signed offset. So in practice, you are actually limited to 2GiB. You asked why this is not possible, but your array alone is 2GiB in size and there are things in the data segment other than just your array. C is a high level language. You get the ease of just being able to define a main function and you get all of these other things for free -- a standard in and output, etc. The C runtime implements this for you and all of this consumes stack space and room in your data segment. For example, if I build this on x86_64-pc-linux-gnu my .bss size is 0x80000020 in size -- an additional 32 bytes. (I've erased PE information from my brain, so I don't remember how those are laid out.)

I don't remember much about the various machine models, but it's probably helpful to note that the x86_64 instruction set doesn't even contain instructions (that I'm aware of, although I'm not an x86 assembly expert) to access any register-relative address beyond a signed 32-bit value. For example, when you want to cram that much stuff on the stack, gcc has to do weird things like this stack pointer allocation:

    movabsq $-10000000016, %r11
    addq    %r11, %rsp

You can't addq $-10000000016, %rsp because it's more than a signed 32-bit offset. The same applies to RIP-relative addressing:

    movq $10000000016(%rip), %rax   # No such addressing mode

Upvotes: 2

Related Questions