Relocation R_X86_64_PC32

Hi,

I’m getting a strange error during compilation of a shared object. The command line I invoked is as follows:

pgc++ -DUSE_DP=1 -std=c++11 -O3 -DTARGET_HOST=1 -DNOGPU=1 -mp -Munroll -Minfo=all -Mneginfo=all -acc -ta=multicore -tp=sandybridge-64 -shared -fPIC -o moc.so host3.cpp


and I see the error

/usr/bin/ld: /opt/pgi/linux86-64/16.10/lib/initacc.o: relocation R_X86_64_PC32 against undefined symbol `__pgi_acc_preinit’ can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: final link failed: Bad value
make: *** [moc.so] Error 2

I am using PGI community edition 16.10.

If I target tesla:cc35 instead of multicore, everything compiles and links just fine.

Any guesses how to fix this?

Thanks, -Ondrej

Hi Ondrej,

This looks like a problem on our end where the “accinit” source file (it’s assembly code) wasn’t written with PIC. I’ve added problem report (TPR#24639) and sent it on to engineer to see if they can fix the problem.

Unfortunately, I don’t have a work around for you.

Thanks for the report!
Mat

I am seeing a very similar issue in version 17.9. My code worked fine in version 16.10, but using 17.9 the command

pgc++ -DUSE_DP=1 -std=c++11 -g -Mneginfo=all -Minfo=all -Munroll -fPIC -DTARGET_HOST=0 -mp -acc -ta=tesla:cc35 -tp=sandybridge-64 -shared -cudalibs -Mcuda=nordc -o mog.so gpu3.cpp host_gpu.o cuda.o -latomic

fails with the error

/usr/bin/ld: /tmp/pgcudafatEsYArdOq0Po.o: relocation R_X86_64_PC32 against undefined symbol `__pgi_uacc_set_cuda’ can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: final link failed: Bad value
pgacclnk: child process exit status 1: /usr/bin/ld

Hi Ondrej,

Looks like another bug which I’ve reported as TPR#24875.

The problem is that in 17.1 we switched OpenACC from using the default CUDA stream to a different stream. This helped to remove some unneeded synchronization. However when CUDA is linked with OpenACC we have to revert back to using the default CUDA stream. This is what the call to “__pgi_uacc_set_cuda” is doing.

To get this call into the init section of the binary, we create a small assembly file during link that gets assembled and then linked in with your final executable or in this case shared object. The problem is that our compiler engineers missed the shared object case so don’t add the “@PLT” at the end of the call so it’s not PIC.

If you don’t mind a little extra work, I do have short-term work around.

First, link your code with the verbose flag, “-v”. Towards the end you’ll see a line with the “pgimport” utility. Copy this line and change the temp assembly file name to something else. Then edit this code to add “@PLT” at the end of the call to “__pgi_uacc_set_cuda”.

% /proj/pgi/linux86-64/17.9/bin/pgimport set_cuda.s -init __pgi_uacc_set_cuda
% vi set_cuda.s
% cat set_cuda.s
        .section .init
        call    __pgi_uacc_set_cuda@PLT

Next assemble this file:

/usr/local/bin/as -o set_cuda.o set_cuda.s

Now copy the link line, starts with “ld”, and replace the temp object that begins with “/tmp/pgcudafat…o” (it should be the begging of the link line) and replace it with your “set_cuda.o” object.

I’ve tested this work-around here and was able to generate a shared object.

Apologies for not having a better work around!

-Mat

Hi Mat,

thank you very much for your reply. I tried your workaround and indeed I got the binary linked.

I needed to omit .fat file from pgimport command, because the .fat file argument did not exist in /tmp directory. The omission did not cause any linking errors.

–Ondrej

I am trying to apply the suggested steps for __pgi_acc_preinit, but without success.

The steps I followed:

pgimport preinit.s -init __pgi_uacc_preinit

Edited preinit.s with @PLT:

  .section .init
    call    __pgi_uacc_preinit@PLT

Assembled with:

as -o initacc.o preinit.s

Then I replaced the file /opt/pgi/linux86-64/17.10/lib/initacc.o with my new version.

However, when I try to compile a simple code:

int main(void) {
    return 0;
}

With:

pgc++ -ta=multicore main.c -o main

I get the error:
/opt/pgi/linux86-64/17.10/lib/initacc.o:(.init+0x1): undefined reference to `__pgi_uacc_preinit’
pgacclnk: child process exit status 1: /usr/bin/ld

With -ta=tesla it compiles fine.

Any ideas about what I am doing wrong? Or the same steps applied to __pgi_uacc_set_cuda can’t be used to __pgi_uacc_preinit?

-Guedes

Hi Guedes,

You misspelled the symbol name. It’s “__pgi_acc_preinit” (no uacc).

Also, no need to use the “pgimport” utility.

I’ll add your post to the TPR.

-Mat

Oh… Indeed. My bad. It worked!
Thanks.

Hello,

It seems I have a very much related problem, so I am posting in this thread.

I am compiling a quite extensive codebase which worked fine without the -acc flag.
With this flag I run into the following linking error:

relocation R_X86_64_PC32 against undefined symbol `__pgi_acc_preinit’ can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: final link failed: Bad value
pgacclnk: child process exit status 1: /usr/bin/ld

The complete set of flags for the pgc++ compiler version 17.10 is:
-fast -O3 -DNDEBUG -fPIC -std=c++11 -noswitcherror -Minfo=accel -acc- ta:multicore

Thanks for any help you can offer.
Cheers,
Jan

Hi Jan,

This is a known issue where one of our 17.10 runtime objects wasn’t properly built with PIC code thus causing this error. We fixed it in the 18.1 release. The next PGI Community Edition, 18.4, will be available here shortly and will include the fix as well.

-Mat

All right, thanks for the quick reply :)
Cheers,
Jan

Issue described two posts back (as well as the relocation truncation error) should be fixed with release 18.10