When compiling for arm cortex-m3 with options -fpic and -msingle-pic-base it creates a global offset table, However static variables, global or local, are not included in the global offset table, and have absolute addresses. is this a bug or a feature, or am I missing an extra option?
Related
I am compiling a static library, which leverages some inline assembly code.
I notice that when I use labels for the jmp instruction:
int foo(){
asm volatile
(
"mov 0x60(%r8),%r11d\n\t"
"jmp *S_401a70\n\t"
...
"S_401a70: xor %rax, %rax\n\t"
...
)
}
and compile the code into a static library with the following flags:
-Wl,--no-undefined -nostdlib -nodefaultlibs -nostartfiles -L$(SOME_LIBRARY_PATH) \
-Wl,--whole-archive -l$(SOME_Library_Name) -Wl,--no-whole-archive \
-Wl,-Bstatic -Wl,-Bsymbolic -Wl,--no-undefined \
-Wl,-pie,-eenclave_entry -Wl,--export-dynamic \
-Wl,--defsym,__ImageBase=0
I would get some errors like:
/usr/bin/ld: Enclave/libtest.o: relocation R_X86_64_32S against `.text' can not be used when making a shared object; recompile with -fPIC
However, since I am compiling into a static library, I don't think -fPIC would make sense. I tried so, but it doesn't work at all.
This seems like an issue with the gcc assembly extension, but I am not sure. Could anyone shed some lights on this? Thank you!
It is not a tool issue. First of all -fPIC affects only C code. And affects it in such way that generated code won't contain absolute addresses of referred data/code and won't rely on its own address in memory (it is a somewhat simplified explanation). Next - it has nothing to do with assembly inlines. Since here code was generated by programmer. And if it is written in a way that introduces absolute addresses or some stuff that introduces dependency on its memory location - compiler can't help with it.
P.S. You may built static library even with position-dependent code but it won't be accepted by linker if someone will try to link it into shared library, since resulting shared library should be position-independent.
I've tried passing -ffunction-sections -fdata-sections for the compiler, but that doesn't seem to have the desired effect. As far as I understand, I also have to pass -Wl,--gc-sections to the linker, but I'm not linking the files at this point. I just want to have a .a library file as small as possible, with minimal redundant code/data.
The compiler performs optimization based on the knowledge it has of the program. Optimization levels -O2 and above, in particular, enable unit-at-a-time mode, which allows the compiler to consider information gained from later functions in the file when compiling a function. Compiling multiple files at once to a single output file in unit-at-a-time mode allows the compiler to use information gained from all of the files when compiling each of them.
Not all optimizations are controlled directly by a flag.
-ffunction-sections
-fdata-sections
Place each function or data item into its own section in the output file if the target supports arbitrary sections. The name of the function or the name of the data item determines the section's name in the output file.
Use these options on systems where the linker can perform optimizations to improve locality of reference in the instruction space. Most systems using the ELF object format and SPARC processors running Solaris 2 have linkers with such optimizations. AIX may have these optimizations in the future.
Only use these options when there are significant benefits from doing so. When you specify these options, the assembler and linker will create larger object and executable files and will also be slower. You will not be able to use gprof on all systems if you specify this option and you may have problems with debugging if you specify both this option and -g.
U can use the following link for more details..:-)
http://gcc.gnu.org/onlinedocs/gcc-4.0.4/gcc/Optimize-Options.html
The following will reduce the size of your compiled objects (and thus the static library)
-Os -g0 -fvisibility=hidden -fomit-frame-pointer -mno-accumulate-outgoing-args -finline-small-functions -fno-unwind-tables -fno-asynchronous-unwind-tables -s
The following will increase the size of objects (though they may make the binary smaller)
-ffunction-sections -fdata-sections -flto -g -g1 -g2 -g3
The only way to really make a static library smaller is to remove the unneeded code by compiling the static library with -ffunction-sections -fdata-sections and linking the final product with -Wl,--gc-sections,--print-gc-sections to find out what parts are cruft. Then go back and remove those functions/variables (this also works for making smaller shared libraries - see http://libraryopt.sf.net)
Compare the size of the library if you -g in the compiler flags, vs not having it. I can easily imagine you double the size of a static library if it includes debug information in. If that was what you saw, chances are you already stripped the library of debug symbols, and hence cannot significantly shrink the library file more. This could explain your memory of cutting the size in half at some point.
I was using a Microtek toolchain to generate an executable binary with relocatable code (pc-relative) and data from a fixed address (Absolute data). Today, this toolchain does not work on Windows 7 64 bits. The idea is to replace Microtek toolchain for 68000 with the GNU toolchain (GCC 4.8.0).
But I can not find the same options on the gcc compiler:
Microtec compiler "MCC68K" with:
"-Mcp": Directs the compiler to use PC-relative addressing for all code references.
"-Mda": Directs the compiler to use absolute addressing for all data references.
Gcc (m68k-elf-gcc) with:
-mpcrel
Unable to build with gcc relocatable code with no relocatable data as the Microteck compiler. With "-mpcrel", all is relocatable (code and data).
do you have an idea?
Sorry for my bad english.
Thanks.
As far as I know, there is no way to achieve the same result with the GNU m68k toolchain.
-mpcrel will generate fully position-independent code with
pc-relative adressing for code as well as for data, resulting in a
limited program/data size (pc-relative offsets cannot exceed 16 bits).
-fpic and -fPIC will generate position independent code with
relocatable binaries but will require a special loader that does the in-place relocation
From gcc docs
-fpic Generate position-independent code (PIC) suitable for use in a shared library,...
-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.
Also try to search
I'm trying to understand more about the "common" section of an executable and I noticed that when doing an objdump on compiled code, I can see variables placed in the common code only on object files (*.o) not on executables.
Why is that?
//test.c
int i[1000];
int main(){return 0;}
build command:
> gcc -g0 -fcommon -c test.c
> gcc -g0 -fcommon test.c
objdump shows i in the common section in the symbol table:
> objdump -x test.o
...
SYMBOL TABLE:
...
00000fa0 O *COM* 00000020 i
Unless I run it on the executable:
> objdump -x a.out
...
SYMBOL TABLE:
...
0804a040 g O .bss 00000fa0 i
If I rebuild the object file with the -fno-common flag instead it shows up in the .bss segment just like it does on the executable. Does the final executable not have this "COMMON" section?
The common section is something that the linker knows about. It basically puts all the common content into one of the three or four actual sections that [a typical] executable has (code or text, data, bss - sometimes there is a rodata as well).
So, your variable ends up in .bss in this case, as they are not initialized.
From gcc manual on -fcommon/-fno-common
In C code, controls the placement of uninitialized global variables.
Unix C compilers have traditionally permitted multiple definitions of
such variables in different compilation units by placing the variables
in a common block. This is the behavior specified by -fcommon, and is
the default for GCC on most targets. On the other hand, this behavior
is not required by ISO C, and on some targets may carry a speed or
code size penalty on variable references. The -fno-common option
specifies that the compiler should place uninitialized global
variables in the data section of the object file, rather than
generating them as common blocks. This has the effect that if the same
variable is declared (without extern) in two different compilations,
you get a multiple-definition error when you link them. In this case,
you must compile with -fcommon instead. Compiling with -fno-common is
useful on targets for which it provides better performance, or if you
wish to verify that the program will work on other systems that always
treat uninitialized variable declarations this way.
So, -fno-common or -fcommon will only make a difference if there is more than one global variable called i [and they should be of the same size, or your program becomes invalid, which is one grade worse than undefined behaviour!]
I'm looking for ways to restrict the number of C symbols exported to a Linux static library (archive). I'd like to limit these to only those symbols that are part of the official API for the library. I already use 'static' to declare most functions as static, but this restricts them to file scope. I'm looking for a way to restrict to scope to the library.
I can do this for shared libraries using the techniques in Ulrich Drepper's How to Write Shared Libraries, but I can't apply these techniques to static archives. In his earlier Good Practices in Library Design paper, he writes:
The only possibility is to combine all object files which need
certain internal resources into one using 'ld -r' and then restrict the symbols
which are exported by this combined object file. The GNU linker has options to
do just this.
Could anyone help me discover what these options might be? I've had some success with 'strip -w -K prefix_*', but this feels brutish. Ideally, I'd like a solution that will work with both GCC 3 and 4.
Thanks!
I don't believe GNU ld has any such options; Ulrich must have meant objcopy, which has many such options: --localize-hidden, --localize-symbol=symbolname, --localize-symbols=filename.
The --localize-hidden in particular allows one to have a very fine control over which symbols are exposed. Consider:
int foo() { return 42; }
int __attribute__((visibility("hidden"))) bar() { return 24; }
gcc -c foo.c
nm foo.o
000000000000000b T bar
0000000000000000 T foo
objcopy --localize-hidden foo.o bar.o
nm bar.o
000000000000000b t bar
0000000000000000 T foo
So bar() is no longer exported from the object (even though it is still present and usable for debugging). You could also remove bar() all together with objcopy --strip-unneeded.
Static libraries can not do what you want for code compiled with either GCC 3.x or 4.x.
If you can use shared objects (libraries), the GNU linker does what you need with a feature called a version script. This is usually used to provide version-specific entry points, but the degenerate case just distinguishes between public and private symbols without any versioning. A version script is specified with the --version-script= command line option to ld.
The contents of a version script that makes the entry points foo and bar public and hides all other interfaces:
{ global: foo; bar; local: *; };
See the ld doc at: http://sourceware.org/binutils/docs/ld/VERSION.html#VERSION
I'm a big advocate of shared libraries, and this ability to limit the visibility of globals is one their great virtues.
A document that provides more of the advantages of shared objects, but written for Solaris (by Greg Nakhimovsky of happy memory), is at http://developers.sun.com/solaris/articles/linker_mapfiles.html
I hope this helps.
The merits of this answer will depend on why you're using static libraries. If it's to allow the linker to drop unused objects later then I have little to add. If it's for the purpose of organisation - minimising the number of objects that have to be passed around to link applications - this extension of Employed Russian's answer may be of use.
At compile time, the visibility of all symbols within a compilation unit can be set using:
-fvisibility=hidden
-fvisibility=default
This implies one can compile a single file "interface.c" with default visibility and a larger number of implementation files with hidden visibility, without annotating the source. A relocatable link will then produce a single object file where the non-api functions are "hidden":
ld -r interface.o implementation0.o implementation1.o -o relocatable.o
The combined object file can now be subjected to objcopy:
objcopy --localize-hidden relocatable.o mylibrary.o
Thus we have a single object file "library" or "module" which exposes only the intended API.
The above strategy interacts moderately well with link time optimisation. Compile with -flto and perform the relocatable link by passing -r to the linker via the compiler:
gcc -fuse-linker-plugin -flto -nostdlib -Wl,-r {objects} -o relocatable.o
Use objcopy to localise the hidden symbols as before, then call the linker a final time to strip the local symbols and whatever other dead code it can find in the post-lto object. Sadly, relocatable.o is unlikely to have retained any lto related information:
gcc -nostdlib -Wl,-r,--discard-all relocatable.o mylibrary.o
Current implementations of lto appear to be active during the relocatable link stage. With lto on, the hidden=>local symbols were stripped by the final relocatable link. Without lto, the hidden=>local symbols survived the final relocatable link.
Future implementations of lto seem likely to preserve the required metadata through the relocatable link stage, but at present the outcome of the relocatable link appears to be a plain old object file.
This is a refinement of the answers from EmployedRussian and JonChesterfield, which may be helpful if you're generating both dynamic and static libraries.
Start with the standard mechanism for hiding symbols in DSOs (the dynamic version of your lib). Compile all files with -fvisibility=hidden. In the header file which defines your API, change the declarations of the classes and functions you want to make public:
#define DLL_PUBLIC __attribute__ ((visibility ("default")))
extern DLL_PUBLIC int my_api_func(int);
See here for details. This works for both C and C++. This is sufficient for DSOs, but you'll need to add these build steps for static libraries:
ld -r obj1.o obj2.o ... objn.o -o static1.o
objcopy --localize-hidden static1.o static2.o
ar -rcs mylib.a static2.o
The ar step is optional - you can just link against static2.o.
My way of doing it is to mark everything that is not to be exported with INTERNAL,
include guard all .h files, compile dev builds with -DINTERNAL= and compile release builds with a single .c file that includes all other library .c files with -DINTERNAL=static.