• Uncategorized

About gcc : How-can-I-tell-with-something-like-objdump-if-an-object-file-has-been-built-with–fPIC

Question Detail

How can I tell, with something like objdump, if an object file has been built with -fPIC?

Question Answer

The answer depends on the platform. On most platforms, if output from

readelf --relocs foo.o | egrep '(GOT|PLT|JU?MP_SLOT)'

is empty, then either foo.o was not compiled with -fPIC, or foo.o doesn’t contain any code where -fPIC matters.

I just had to do this on a PowerPC target to find which shared object (.so) was being built without -fPIC. What I did was run readelf -d libMyLib1.so and look for TEXTREL. If you see TEXTREL, one or more source files that make up your .so were not built with -fPIC. You can substitute readelf with elfdump if necessary.

E.g.,

[[email protected] lib]$ readelf -d libMyLib1.so | grep TEXT   # Bad, not -fPIC
 0x00000016 (TEXTREL)
[[email protected] lib]$ readelf -d libMyLib2.so | grep TEXT   # Good, -fPIC
[[email protected] lib]$

And to help people searching for solutions, the error I was getting when I ran my executable was this:

[email protected]:/# ./program: error while loading shared libraries: /usr/lib/libMyLi
b1.so:  R_PPC_REL24 relocation at 0x0fc5987c for symbol 'memcpy' out of range

I don’t know whether this info applies to all architectures.

Source: blogs.oracle.com/rie

I assume, what you really want to know is whether or not a shared library is composed from object files compiled with -fPIC.

As already mentioned, if there are TEXTRELs, then -fPIC was not used.

There is a great tool called scanelf which can show you the symbols that caused .text relocations.

More information can be found at HOWTO Locate and Fix .text Relocations TEXTRELs.

-fPIC means that code will be able to execute in addresses different form the address that was compile for.

To do it , disasambler will look like this….

call get_offset_from_compilation_address
get_offset_from_compilation_address: pop ax
sub ax, ax , &get_offset_from_compilation_address

now in ax we have an offset that we need to add to any access to memory.

load bx, [ax + var_address}

readelf -a *.so | grep Flags
  Flags:                             0x50001007, noreorder, pic, cpic, o32, mips32

This should work most of the time.

Another option to distinguish whether your program is generated wit -fPIC option:

provided that your code has -g3 -gdwarf-2 option enabled when compiling.

other gcc debug format may also contains the macro info:

Note the following $’..’ syntax is assumes bash

echo $' main() { printf("%d\\n", \n#ifdef __PIC__\n__PIC__\n#else\n0\n#endif\n); }' | gcc -fPIC -g3 
-gdwarf-2 -o test -x c -

readelf --debug-dump=macro ./test | grep __PIC__

such a method works because gcc manual declares that if -fpic is used, PIC is defined to 1, and
if -fPIC used, PIC is 2.

The above answers by checking the GOT is the better way. Because the prerequest of -g3 -gdwarf-2 I guess seldom being used.

From The Linux Programming Interface:

On Linux/x86-32, it is possible to create a shared library using
modules compiled without the –fPIC option. However, doing so loses
some of the benefits of shared libraries, since pages of program text
containing position-dependent memory references are not shared across
processes. On some architectures, it is impossible to build shared
libraries without the –fPIC option.

In order to determine whether an existing object file has been
compiled with the –fPIC option, we can check for the presence of the
name _GLOBAL_OFFSET_TABLE_ in the object file’s symbol table, using
either of the following commands:

$ nm mod1.o | grep _GLOBAL_OFFSET_TABLE_
$ readelf -s mod1.o | grep _GLOBAL_OFFSET_TABLE_

Conversely, if either of the following equivalent commands yields any
output, then the specified shared library includes at least one object
module that was not compiled with –fPIC:

$ objdump --all-headers libfoo.so | grep TEXTREL
$ readelf -d libfoo.so | grep TEXTREL

However, neither above quoting nor any answer of this question works for x86_64.

What I’ve observed on my x86_64 Ubuntu machine is that, whether specifying -fPIC or not, it would generate fPIC .o. That is

gcc -g -Wall -c -o my_so.o my_so.c // has _GLOBAL_OFFSET_TABLE_
gcc -g -Wall -fPIC -c -o my_so_fpic.o my_so.c // has _GLOBAL_OFFSET_TABLE_

readelf -s my_so.o > 1.txt && readelf -s my_so_fpic > 2.txt && diff 1.txt 2.txt

has no difference and both my_so.o and my_so_fpic.o can be used to create a shared library.

In order to generate non fpic object file, I found a gcc flag called -fno-pic in the first comment of How to test whether a Linux binary was compiled as position independent code? .

This works,

gcc -g —Wall -fno-pic -c -o my_so_fnopic.o my_so.c // no _GLOBAL_OFFSET_TABLE_ 

and

gcc -g -Wall -shared -o libdemo.so my_so_fnopic.o 

gives error:

/usr/bin/ld: my_so_fnopic.o: relocation R_X86_64_32 against `.rodata' can not be used when making a shared object; recompile with -fPIC
collect2: error: ld returned 1 exit status

can not create a shared library with non pic .o.

You may also like...

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.