Both -fPIC and -s used - possibly contradictory? - gcc

In a particular project, I saw the following compiler options used all at once:
gcc foo.c -o foo.o -Icomponent1/subcomponent1 -Icomponent2/subcomponent1 -Wall -fPIC -s
Are the -fPIC and -s used together contradictory here? If not, why?

-s and -fPIC are two flags used for different purposes. They are not contradictory.
From the gcc manual
-s
Remove all symbol table and relocation information from the executable.
-fPIC
If supported for the target machine, emit position-independent code, suitable for dynamic linking and avoiding any limit on the size of the global offset table. This option makes a difference on the m68k, PowerPC and SPARC.

Related

How do I tell CMake to specify multiple linker script files to GCC?

I"m using CMake 3.17 and the GNU ARM toolchain and I'm trying to migrate a build from Eclipse to CMake. Part of the Eclipse build specifies multiple linker script files to use at link time so I set up my CMakeLists.txt file like this:
target_link_options(${application_name} PRIVATE
-mcpu=cortex-m4
-mthumb
-mfloat-abi=hard
-mfpu=fpv4-sp-d16
-fmessage-length=0
-fsigned-char
-ffunction-sections
-fdata-sections
-flto
-Wall
-Xlinker --gc-sections
-Wl,-Map,${map_file}
-T ${CMAKE_SOURCE_DIR}/ldscripts/libs.ld
-T ${CMAKE_SOURCE_DIR}/ldscripts/mem.ld
-T ${CMAKE_SOURCE_DIR}/ldscripts/sections.ld
)
But when I run make the -T option gets swallowed for the second and third files. Here's what I get when running make VERBOSE=1 after successful compilation of all sources. The linker command line followed by a warning about missing -T options:
Linking CXX executable StartupSequence.elf
/D/gcc-arm-none-eabi-9-2019-q4/bin/arm-none-eabi-g++.exe --specs=nano.specs --specs=nosys.specs -g -Og -mcpu=cortex-m4 -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16 -fmessage-length=0 -fsigned-char -ffunction-sections -fdata-sections -flto -Wall -Xlinker --gc-sections -Wl,-Map,StartupSequence.map -T C:/svn/startup_sequence/ldscripts/libs.ld C:/svn/startup_sequence/ldscripts/mem.ld C:/svn/startup_sequence/ldscripts/sections.ld #CMakeFiles/StartupSequence.dir/objects1.rsp -o StartupSequence.elf ../Drivers/CMSIS/DSP/Lib/libarm_cortexM4lf_math.a ../Middlewares/Third_Party/mbedTLS/library/libmbedcrypto.a
d:/gcc-arm-none-eabi-9-2019-q4/bin/../lib/gcc/arm-none-eabi/9.2.1/../../../../arm-none-eabi/bin/ld.exe: warning: C:/svn/startup_sequence/ldscripts/sections.ld contains output sections; did you forget -T?
Why does the -T not get sent to the command line properly for the last two files?
I've tried separating the link script specification into three separate calls to target_link_options and enclosing each script specification in double quotes but it seems to have no effect.
By default, CMake de-duplicates compile and link options. That is, multiple -T options are combined into the single one.
CMake doesn't know which options are actually bonded with the further arguments, but provides a SHELL: mechanism for define such options:
target_link_options(${application_name} PRIVATE
"SHELL:-T ${CMAKE_SOURCE_DIR}/ldscripts/libs.ld"
"SHELL:-T ${CMAKE_SOURCE_DIR}/ldscripts/mem.ld"
"SHELL:-T ${CMAKE_SOURCE_DIR}/ldscripts/sections.ld"
)
This mechanism is described in the documentation for target_link_options command.
The same mechanism works for compiler options passed to target_compile_options, see that question and my answer for it.
Because -T is interpreted as an single option. Glue -T with the path instead. Try:
-T${CMAKE_SOURCE_DIR}/ldscripts/libs.ld
-T${CMAKE_SOURCE_DIR}/ldscripts/mem.ld
-T${CMAKE_SOURCE_DIR}/ldscripts/sections.ld

How can I maximize optimization using gcc?

I made a simple quick sort algorithm using C language, named test.c
I'm trying to maximize the optimization, so I use -O3 options like belows.
gcc -S -O3 -o test.s test.c
gcc -S -O3 -o test1.s test.s
gcc -S -O3 -o test2.s test1.s
gcc -S -O3 -o test3.s test2.s
.
.
.
But strange thing happens. The more times I did above procedure, the more number of line assembly get.
I don't know why this happens, because I think that I have to get more optimized assembly file that has smaller number of line as I did above procedure.
If this is not right way, using -O3 only one time is the way of the best optimization?
Thanks
Most of the gcc optimizations operate on the representation of C source code in an intermediate language. I'm not aware of any optimization specifically operating at the assembler instruction level other than peephole. But that would also be included in -O3.
So yes, -O3 is supposed to be used only once, when turning C source into object files.

GCC equivalent of llvm-link

I use the following LLVM tools to convert a cpp project which is written in multiple files into "ONE" single assembly file.
clang *.cpp -S -emit-llvm
llvm-link *.s -S -o all.s
llc all.s -march=mips
Is there any way of doing this in GCC? In particular, is there any way of linking GCC generated assembly files into one assembly file? i.e., what is the equivalent of LLVM-LINK?
Perhaps LTO (Link Time Optimization) is what you want.
Then, compile each compilation unit with gcc -flto e.g.
gcc -flto -O -Wall -c src1.c
g++ -flto -O -Wall -c src2.cc
and use also -flto (and the same optimizations) to link them:
g++ -flto -O src1.o src2.o -lsomething
LTO works in GCC by putting, in each generated assembly file and object file, some representation of the internal GCC representations (like Gimple). See its documentation
You might want to use MELT to customize GCC (or simply use its probe to understand the Gimple, or try just gcc -fdump-tree-all).

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

How can I tell, with something like objdump, if an object file has been built with -fPIC?
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.,
[user#host lib]$ readelf -d libMyLib1.so | grep TEXT # Bad, not -fPIC
0x00000016 (TEXTREL)
[user#host lib]$ readelf -d libMyLib2.so | grep TEXT # Good, -fPIC
[user#host lib]$
And to help people searching for solutions, the error I was getting when I ran my executable was this:
root#target:/# ./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.

gcc link error occurred

I compiled with gcc
gcc -l. 'net-snmp-config --cflags'
-fPlC -shared -c -o matsu_object.o tsu_object.c
but this error occurred
gcc: -lcrypto: Because a link was
not completed, the input file of the
linker was not used
What's wrong?
Did you mistype the question? There's no way for that to output the message you write, and I would expect that the proper command is something more like
gcc -L. `net-snmp-config --cflags` -fPIC -shared -c -o matsu_object.o tsu_object.c
Notice the -L uppercase, backticks instead of single quotes, and upper-case I in PIC.
Also, you don't say what you're trying to do, but net-snmp-config should also take at least one of --libs or --agent-libs as well.
Ah, I didn't read closely enough...
-c means "compile", that is: generate from tsu_object.c, a compiled matsu_object.o.
Without -c, the compiler actually links, that is: generate from *.o, a.out or other specified file.
-shared (and linker flags like -l and -L) are only meaningful when linking. They're meaningless when compiling, as you are doing here because of -c.
Please correct the command-line in the question to accurately reflect what you're running, and give some more explanation as to what you're trying to do.
I think you are using ticks ' instead of back ticks `. Does --cflags really give linker options? I think you are at the link step here. Also what is the effect of -c at a link. I thought -c was compile only and not attempt to link.
You used single quotes instead of backquotes.
Instead of this:
gcc -l. 'net-snmp-config --cflags' -fPlC -shared -c -o matsu_object.o tsu_object.c
You should type:
gcc -l. `net-snmp-config --cflags`-fPlC -shared -c -o matsu_object.o tsu_object.c
net-snmp-config is a program. When you run it with --cflags, it evaluates to the correct cflags that you should be using to compile your program.
But you know what? You should be using autoconf. Even for something this small, it usually makes sense to do the work. Most people I know need to compile on more than one platform...

Resources