Objective-C has a runtime that translates its syntax into functions that are organized and compiled. Does C have a runtime library? Also, if anyone can answer the question, what are the steps GCC takes during C compilation? e.g. main.c >> main.s >> main.bin
Yes, the C language features a standard library; that is, a number of standard macros, routines and types one can use in his programs, apart from any in the core language itself.
In popular implementations, there is a separate library file containing the code for the C standard library. For example, in GNU/Linux environments, the GNU C library (libc) is almost always present. Microsoft provides the msvcrt.dll runtime library for the Windows system, and so on.
Also, the C standard library might not be available in freestanding implementations. Sometimes it is possible to compile a program without linking against the C standard library from your system. As an example, the Windows API is well known for behaving as a freestanding C programming environment (although one might need to link against other system libraries specific to Windows).
Regarding GCC, the following illustrates briefly the compilation pipeline:
The input source is preprocessed with GNU cpp, resulting in a translation unit. (Actually, as Basile pointed out, nowadays no cpp process is created; the entire preprocessing work is done within cc1. Nevertheless, the resulting behavior is most likely the same as with cpp.)
The translation unit is then interpreted and compiled to assembly source with GCC cc1;
The assembly source is then assembled into object code with GNU as;
Finally, object files and libraries are linked together to produce a binary image with GNU ld.
Naturally, each of these steps may be altered or not executed at all depending on the driver options; the above is just a rough explanation of the overall process.
C has a standard library (libc on Linux, which provides standard functions like those in <stdio.h> such as fprintf and in <stdlib.h> such as malloc and also all the system calls), and even when you use gcc in free standing mode with gcc -ffreestanding (e.g. to compile a libc or some kernel) it links a tiny libgcc library which provides the functionality built-in the language (e.g. 64 bits addition on 32 bits platforms).
To learn what the gcc command is doing, pass it the -v flag. (Don't forget to take the habit to always compile with -Wall to get warnings and -g to get the debug information), e.g.
% gcc -v -g -Wall hello.c -o hello
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/4.7/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Debian 4.7.2-4' --with-bugurl=file:///usr/share/doc/gcc-4.7/README.Bugs --enable-languages=c,c++,go,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.7 --enable-shared --enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.7 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --enable-plugin --enable-objc-gc --with-arch-32=i586 --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 4.7.2 (Debian 4.7.2-4)
COLLECT_GCC_OPTIONS='-v' '-g' '-Wall' '-o' 'hello' '-mtune=generic' '-march=x86-64'
/usr/lib/gcc/x86_64-linux-gnu/4.7/cc1 -quiet -v -imultiarch x86_64-linux-gnu hello.c -quiet -dumpbase hello.c -mtune=generic -march=x86-64 -auxbase hello -g -Wall -version -o /tmp/ccsWt3UC.s
GNU C (Debian 4.7.2-4) version 4.7.2 (x86_64-linux-gnu)
compiled by GNU C version 4.7.2, GMP version 5.0.5, MPFR version 3.1.0-p10, MPC version 0.9
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
ignoring nonexistent directory "/usr/local/include/x86_64-linux-gnu"
ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../../x86_64-linux-gnu/include"
#include "..." search starts here:
#include <...> search starts here:
/usr/lib/gcc/x86_64-linux-gnu/4.7/include
/usr/local/include
/usr/lib/gcc/x86_64-linux-gnu/4.7/include-fixed
/usr/include/x86_64-linux-gnu
/usr/include
End of search list.
GNU C (Debian 4.7.2-4) version 4.7.2 (x86_64-linux-gnu)
compiled by GNU C version 4.7.2, GMP version 5.0.5, MPFR version 3.1.0-p10, MPC version 0.9
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
Compiler executable checksum: c5f63dedeacd449634699df94fe3d914
COLLECT_GCC_OPTIONS='-v' '-g' '-Wall' '-o' 'hello' '-mtune=generic' '-march=x86-64'
as -v --64 -o /tmp/ccO5i3pU.o /tmp/ccsWt3UC.s
GNU assembler version 2.22 (x86_64-linux-gnu) using BFD version (GNU Binutils for Debian) 2.22
COMPILER_PATH=/usr/lib/gcc/x86_64-linux-gnu/4.7/:/usr/lib/gcc/x86_64-linux-gnu/4.7/:/usr/lib/gcc/x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/4.7/:/usr/lib/gcc/x86_64-linux-gnu/
LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/4.7/:/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../../lib/:/lib/x86_64-linux-gnu/:/lib/../lib/:/usr/lib/x86_64-linux-gnu/:/usr/lib/../lib/:/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../:/lib/:/usr/lib/
COLLECT_GCC_OPTIONS='-v' '-g' '-Wall' '-o' 'hello' '-mtune=generic' '-march=x86-64'
/usr/lib/gcc/x86_64-linux-gnu/4.7/collect2 --sysroot=/ --build-id --no-add-needed --eh-frame-hdr -m elf_x86_64 --hash-style=both -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o hello /usr/lib/gcc/x86_64-linux-gnu/4.7/../../../x86_64-linux-gnu/crt1.o /usr/lib/gcc/x86_64-linux-gnu/4.7/../../../x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/4.7/crtbegin.o -L/usr/lib/gcc/x86_64-linux-gnu/4.7 -L/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../x86_64-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../../lib -L/lib/x86_64-linux-gnu -L/lib/../lib -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/4.7/../../.. /tmp/ccO5i3pU.o -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc/x86_64-linux-gnu/4.7/crtend.o /usr/lib/gcc/x86_64-linux-gnu/4.7/../../../x86_64-linux-gnu/crtn.o
Notice that collect2 is the linker wrapped to do additional things, and that libc.so gets used by almost every Linux executable (because it is wrapping syscalls).
C has a standard library (e.g., strlen, malloc, etc.)
The steps are: compile your code that uses the standard library, then link your code to the standard library. libc can be contained in either a static library or a dynamic library, depending; usually both are available.
Related
let me start by saying that this is my first time really meddling with GCC, so I apologize if this question is not very constructive or has been answered before.
I have two static libraries:
"L1.h"
void __attribute__((weak)) Logger_Init(void) { // Invalid... }
"L2.h"
void Logger_Init(void);
"L2.c"
void Logger_Init(void)
{
// Do stuff...
}
My goal is for certain executables to include "L2" into the compilation process and override "L1"'s implementation of Logger_Init.
I read here that you cannot link two static libraries, but I do the check of whether to even call Logger_Init at runtime, so I need the declaration of the function during compilation.
In the executable project, there is an option to add library paths and names, in which I added both of these libraries. My first question is, does the order matter here? I played with these two commands below and it made no difference (they're trimmed up quite a bit, but I assume that this is the relevant part).
gcc -L(L1_PATH) -L(L2_PATH) -l(L1_NAME) -l(L2_NAME)
gcc -L(L2_PATH) -L(L1_PATH) -l(L2_NAME) -l(L1_NAME)
My main question here though, is how to tell the linker(?) that there is a strong definition of the function in another static library, or something along those lines?
I've also read that using the __attribute__((weak)) is not very helpful for static libraries, but I'm not really understanding why, it seems like it does exactly what I am trying to achieve.
I can compile and run everything here, however "L2" implementation of Logger_Init doesn't get called.
I am working in an embedded environment, so using dynamic/shared libraries is out of the question.
EDIT:
Per request, Bodo, here is the entire list of command. I am not writing these commands, they're all auto-generated by Vitis. This is where I'm running my code. I turned verbose on and let it rip. Over half of this stuff is gibberish to me, I am sorry for the bloat. Towards the very bottom is the useful stuff.
make all
make --no-print-directory pre-build
a9-linaro-pre-build-step
' '
make --no-print-directory main-build
'Building file: ../src/main.c'
'Invoking: ARM v7 gcc compiler'
arm-none-eabi-gcc -Wall -O0 -g3 -c -fmessage-length=0 -MT"src/main.o"
-mcpu=cortex-a9 -mfpu=vfpv3 -mfloat-abi=hard -v -IC:/Projects/Xilinx/Experiment/PicoZed/PicoZed.vitis/PicoZed/export/PicoZed/sw/PicoZed/standalone_domain/bspinclude/include
-MMD -MP -MF"src/main.d" -MT"src/main.o" -o "src/main.o" "../src/main.c"
Using built-in specs.
COLLECT_GCC=C:\Xilinx\Vitis\2020.2\gnu\aarch32\nt\gcc-arm-none-eabi\bin\\..\x86_64-oesdk-mingw32\usr\bin\arm-xilinx-eabi\arm-xilinx-eabi-gcc.exe
Target: arm-xilinx-eabi
Configured with: ../../../../../../work-shared/gcc-9.2.0-r0/gcc-9.2.0/configure
--build=x86_64-linux --host=x86_64-oesdk-mingw32 --target=arm-xilinx-eabi --prefix=/usr/local/oecore-x86_64/sysroots/x86_64-oesdk-mingw32/usr --exec_prefix=/usr/local/oecore-x86_64/sysroots/x86_64-oesdk-mingw32/usr
--bindir=/usr/local/oecore-x86_64/sysroots/x86_64-oesdk-mingw32/usr/bin/arm-xilinx-eabi
--sbindir=/usr/local/oecore-x86_64/sysroots/x86_64-oesdk-mingw32/usr/bin/arm-xilinx-eabi
--libexecdir=/usr/local/oecore-x86_64/sysroots/x86_64-oesdk-mingw32/usr/libexec/arm-xilinx-eabi
--datadir=/usr/local/oecore-x86_64/sysroots/x86_64-oesdk-mingw32/usr/share
--sysconfdir=/usr/local/oecore-x86_64/sysroots/x86_64-oesdk-mingw32/etc --sharedstatedir=/usr/local/oecore-x86_64/sysroots/x86_64-oesdk-mingw32/com
--localstatedir=/usr/local/oecore-x86_64/sysroots/x86_64-oesdk-mingw32/var
--libdir=/usr/local/oecore-x86_64/sysroots/x86_64-oesdk-mingw32/usr/lib/arm-xilinx-eabi
--includedir=/usr/local/oecore-x86_64/sysroots/x86_64-oesdk-mingw32/us r/include
--oldincludedir=/usr/local/oecore-x86_64/sysroots/x86_64-oesdk-mingw32/usr/include
--infodir=/usr/local/oecore-x86_64/sysroots/x86_64-oesdk-mingw32/usr/share/info --mandir=/usr/local/oecore-x86_64/sysroots/x86_64-oesdk-mingw32/usr/share/man
--disable-silent-rules --disable-dependency-tracking --with-libtool-sysroot=/scratch/mhatle/baremetal-toolchains/20200708-172230/build/aarch32-tc-x86_64-mingw32/work/x86_64-nativesdk-mingw32-oesdk-mingw32/gcc-cross-canadian-arm/9.2.0-r0/recipe-sysroot
--enable-clocale=generic --with-gnu-ld --enable-shared --enable-languages=c,c++ --enable-threads=posix --enable-multilib --enable-c99 --enable-long-long --enable-libstdcxx-pch --program-prefix=arm-xilinx-eabi- --without-local-prefix --enable-lto --disable-libssp --enable-libitm --disable-bootstrap --disable-libmudflap --with-system-zlib --enable-linker-build-id --with-ppl=no --with-cloog=no --enable-checking=release --enable-cheaders=c_global --without-isl --with-gxx-include-dir=/not/exist/usr/include/c++/9.2.0 --wi th-build-time-tools=/scratch/mhatle/baremetal-toolchains/20200708-172230/build/aarch32-tc-x86_64-mingw32/work/x86_64-nativesdk-mingw32-oesdk-mingw32/gcc-cross-canadian-arm/9.2.0-r0/recipe-sysroot-native/usr/arm-xilinx-eabi/bin
--with-build-sysroot=/scratch/mhatle/baremetal-toolchains/20200708-172230/build/aarch32-tc-x86_64-mingw32/work/x86_64-nativesdk-mingw32-oesdk-mingw32/gcc-cross-canadian-arm/9.2.0-r0/recipe-sysroot
--enable-poison-system-directories --disable-nls --enable-initfini-array --without-headers --with-newlib --disable-libstdcxx-pch --with-newlib --disable-threads --enable-plugins --with-gnu-as --disable-libitm --with-multilib-list=aprofile --enable-multilib --disable-nls --enable-mingw-wildcard --with-sysroot=/not/exist
Thread model: single
gcc version 9.2.0 (GCC)
COLLECT_GCC_OPTIONS='--sysroot=C:\Xilinx\Vitis\2020.2\gnu\aarch32\nt\gcc-arm-none-eabi\bin\\..\aarch32-xilinx-eabi' '-Wall' '-O0' '-g3' '-c' '-fmessage-length=0' '-MT' 'src/main.o' '-mcpu=cortex-a9' '-mfpu=vfpv3' '-mfloat-abi=hard' '-v' '-I' 'C:/Projects/Xilinx/Experiment/PicoZed/PicoZed.vitis/PicoZed/export/PicoZed/sw/PicoZed/standalone_domain/bspinclude/include' '-MMD' '-MP' '-MF' 'src/main.d' '-MT' 'src/main.o' '-o' 'src/main.o' '-marm' '-march=armv7-a+mp+sec+vfpv3'
c:/xilinx/vitis/2020.2/gnu/aarch32/nt/gcc-arm-none-eabi/x86_64-oesdk-mingw32/usr/bin/arm-xilinx-eabi/../../libexec/arm-xilinx-eabi/gcc/arm-xilinx-eabi/9.2.0/cc1.exe
-quiet -v -I C:/Projects/Xilinx/Experiment/PicoZed/PicoZed.vitis/PicoZed/export/PicoZed/sw/PicoZed/standalone_domain/bspinclude/include
-imultilib thumb/v7-a+fp/hard -iprefix c:\xilinx\vitis\2020.2\gnu\aarch32\nt\gcc-arm-none-eabi\x86_64-oesdk-mingw32\usr\bin\arm-xilinx-eabi\../../lib/arm-xilinx-eabi/gcc/arm-xilinx-eabi/9.2.0/
-isysroot C:\Xilinx\Vitis\2020.2\gnu\aarch32\nt\gcc-arm-none-eabi\bin\\..\aarch32-xilinx-eabi
-MMD src/main.d -MF src/main.d -MP -MT src/main.o -MT src/main.o -dD -D__USES_INITFINI__ ../src/main.c -quiet -dumpbase main.c -mcpu=cortex-a9 -mfpu=vfpv3 -mfloat-abi=hard -marm -march=armv7-a+mp+sec+vfpv3 -auxbase-strip src/main.o -g3 -O0 -Wall -version -fmessage-length=0 -o C:\Users\M257B~1.BLA\AppData\Local\Temp\ccOuqloW.s
GNU C17 (GCC) version 9.2.0 (arm-xilinx-eabi)
compiled by GNU C version 9.2.0, GMP version 6.1.2, MPFR version
4.0.2, MPC version 1.1.0, isl version none
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
ignoring nonexistent directory "c:\xilinx\vitis\2020.2\gnu\aarch32\nt\gcc-arm-none-eabi\x86_64-oesdk-mingw32\usr\bin\arm-xilinx-eabi\../../lib/arm-xilinx-eabi/gcc/arm-xilinx-eabi/9.2.0/../../../../../arm-xilinx-eabi/include"
ignoring duplicate directory "c:/xilinx/vitis/2020.2/gnu/aarch32/nt/gcc-arm-none-eabi/x86_64-oesdk-mingw32/usr/lib/arm-xilinx-eabi/gcc/../../../lib/arm-xilinx-eabi/gcc/arm-xilinx-eabi/9.2.0/include"
ignoring nonexistent directory "C:\Xilinx\Vitis\2020.2\gnu\aarch32\nt\gcc-arm-none-eabi\bin\\..\aarch32-xilinx-eabi/usr/lib/arm-xilinx-eabi/9.2.0/include"
ignoring nonexistent directory "C:\Xilinx\Vitis\2020.2\gnu\aarch32\nt\gcc-arm-none-eabi\bin\\..\aarch32-xilinx-eabi/usr/local/oecore-x86_64/sysroots/x86_64-oesdk-mingw32/usr/lib/arm-xilinx-eabi/gcc/arm-xilinx-eabi/9.2.0/../../../../include"
ignoring duplicate directory "c:/xilinx/vitis/2020.2/gnu/aarch32/nt/gcc-arm-none-eabi/x86_64-oesdk-mingw32/usr/lib/arm-xilinx-eabi/gcc/../../../lib/arm-xilinx-eabi/gcc/arm-xilinx-eabi/9.2.0/include-fixed"
ignoring nonexistent directory "c:/xilinx/vitis/2020.2/gnu/aarch32/nt/gcc-arm-none-eabi/x86_64-oesdk-mingw32/usr/lib/arm-xilinx-eabi/gcc/../../../lib/arm-xilinx-eabi/gcc/arm-xilinx-eabi/9.2.0/../../../../../arm-xilinx-eabi/include"
#include "..." search starts here:
#include <...> search starts here:
C:/Projects/Xilinx/Experiment/PicoZed/PicoZed.vitis/PicoZed/export/PicoZed/sw/PicoZed/standalone_domain/bspinclude/include
c:\xilinx\vitis\2020.2\gnu\aarch32\nt\gcc-arm-none-eabi\x86_64-oesdk-mingw32\usr\bin\arm-xilinx-eabi\../../lib/arm-xilinx-eabi/gcc/arm-xilinx-eabi/9.2.0/include
c:\xilinx\vitis\2020.2\gnu\aarch32\nt\gcc-arm-none-eabi\x86_64-oesdk-mingw32\usr\bin\arm-xilinx-eabi\../../lib/arm-xilinx-eabi/gcc/arm-xilinx-eabi/9.2.0/include-fixed
C:\Xilinx\Vitis\2020.2\gnu\aarch32\nt\gcc-arm-none-eabi\bin\\..\aarch32-xilinx-eabi/usr/include
End of search list.
GNU C17 (GCC) version 9.2.0 (arm-xilinx-eabi)
compiled by GNU C version 9.2.0, GMP version 6.1.2, MPFR version
4.0.2, MPC version 1.1.0, isl version none
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
Compiler executable checksum: 2516cb1a757555b312b0344a413e7d9c
COLLECT_GCC_OPTIONS='--sysroot=C:\Xilinx\Vitis\2020.2\gnu\aarch32\nt\gcc-arm-none-eabi\bin\\..\aarch32-xilinx-eabi' '-Wall' '-O0' '-g3' '-c' '-fmessage-length=0' '-MT' 'src/main.o' '-mcpu=cortex-a9' '-mfpu=vfpv3' '-mfloat-abi=hard' '-v' '-I' 'C:/Projects/Xilinx/Experiment/PicoZed/PicoZed.vitis/PicoZed/export/PicoZed/sw/PicoZed/standalone_domain/bspinclude/include' '-MMD' '-MP' '-MF' 'src/main.d' '-MT' 'src/main.o' '-o' 'src/main.o' '-marm' '-march=armv7-a+mp+sec+vfpv3'
c:/xilinx/vitis/2020.2/gnu/aarch32/nt/gcc-arm-none-eabi/x86_64-oesdk-mingw32/usr/bin/arm-xilinx-eabi/../../libexec/arm-xilinx-eabi/gcc/arm-xilinx-eabi/9.2.0/as.exe
-v -I C:/Projects/Xilinx/Experiment/PicoZed/PicoZed.vitis/PicoZed/export/PicoZed/sw/PicoZed/standalone_domain/bspinclude/include
-march=armv7-a+mp+sec -mfloat-abi=hard -mfpu=vfpv3 -meabi=5 -o src/main.o C:\Users\M257B~1.BLA\AppData\Local\Temp\ccOuqloW.s
GNU assembler version 2.32.0 (arm-xilinx-eabi) using BFD version (GNU Binutils) 2.32.0.20190204
COMPILER_PATH=c:/xilinx/vitis/2020.2/gnu/aarch32/nt/gcc-arm-none-eabi/x86_64-oesdk-mingw32/usr/bin/arm-xilinx-eabi/../../libexec/arm-xilinx-eabi/gcc/arm-xilinx-eabi/9.2.0/;c:/xilinx/vitis/2020.2/gnu/aarch32/nt/gcc-arm-none-eabi/x86_64-oesdk-mingw32/usr/bin/arm-xilinx-eabi/../../libexec/arm-xilinx-eabi/gcc/
LIBRARY_PATH=C:/Xilinx/Vitis/2020.2/gnu/aarch32/nt/gcc-arm-none-eabi/bin//../aarch32-xilinx-eabi/usr/lib/thumb/v7-a+fp/hard/;c:/xilinx/vitis/2020.2/gnu/aarch32/nt/gcc-arm-none-eabi/x86_64-oesdk-mingw32/usr/bin/arm-xilinx-eabi/../../lib/arm-xilinx-eabi/gcc/arm-xilinx-eabi/9.2.0/;c:/xilinx/vitis/2020.2/gnu/aarch32/nt/gcc-arm-none-eabi/x86_64-oesdk-mingw32/usr/bin/arm-xilinx-eabi/../../lib/arm-xilinx-eabi/gcc/;C:/Xilinx/Vitis/2020.2/gnu/aarch32/nt/gcc-arm-none-eabi/bin//../aarch32-xilinx-eabi/usr/lib/arm-xilinx-eabi/9.2.0/;C:/Xilinx/Vitis/2020.2/gnu/aarch32/nt/gcc-arm-none-eabi/bin//../aarch32-xilinx-eabi/usr/lib/
COLLECT_GCC_OPTIONS='--sysroot=C:\Xilinx\Vitis\2020.2\gnu\aarch32\nt\gcc-arm-none-eabi\bin\\..\aarch32-xilinx-eabi' '-Wall' '-O0' '-g3' '-c' '-fmessage-length=0' '-MT' 'src/main.o' '-mcpu=cortex-a9' '-mfpu=vfpv3' '-mfloat-abi=hard' '-v' '-I' 'C:/Projects/Xilinx/Experiment/PicoZed/PicoZed.vitis/PicoZed/export/PicoZed/sw/PicoZed/standalone_domain/bspinclude/include' '-MMD' '-MP' '-MF' 'src/main.d' '-MT' 'src/main.o' '-o' 'src/main.o' '-marm' '-march=armv7-a+mp+sec+vfpv3'
'Finished building: ../src/main.c'
' '
'Building target: PicoZed_Main.elf'
'Invoking: ARM v7 gcc linker'
arm-none-eabi-gcc
-L"C:\Projects\Xilinx\Experiment\PicoZed\PicoZed.vitis\Library1\Debug" -L"C:\Projects\Xilinx\Experiment\PicoZed\PicoZed.vitis\Library2\Debug" -mcpu=cortex-a9 -mfpu=vfpv3 -mfloat-abi=hard -Wl,-build-id=none -specs=Xilinx.spec -Wl,-T -Wl,../src/lscript.ld -LC:/Projects/Xilinx/Experiment/PicoZed/PicoZed.vitis/PicoZed/export/PicoZed/sw/PicoZed/standalone_domain/bsplib/lib
-o "PicoZed_Main.elf" ./src/main.o -lLibrary1 -lLibrary2 -Wl,--start-group,-lxil,-lgcc,-lc,--end-group
'Finished building target: PicoZed_Main.elf'
' '
'Invoking: ARM v7 Print Size'
arm-none-eabi-size PicoZed_Main.elf |tee "PicoZed_Main.elf.size"
text data bss dec hex filename
18736 1144 22568 42448 a5d0 PicoZed_Main.elf
'Finished building: PicoZed_Main.elf.size'
' '
My first question is, does the order matter here?
Yes, literally from gcc documentation:
-l library
...
It makes a difference where in the command you write this option; the linker searches and processes libraries and object files in the order they are specified. Thus, ‘foo.o -lz bar.o’ searches library ‘z’ after file foo.o but before bar.o. If bar.o refers to functions in ‘z’, those functions may not be loaded.
how to tell the linker(?) that there is a strong definition of the function in another static library, or something along those lines?
Typically in modern embedded:
-Wl,--whole-archive -l(L1_NAME) -l(L2_NAME) -Wl,--no-whole-archive
Another alternative is to unpack both libraries and pass object files to gcc.
but I'm not really understanding why
Linker searches up until the first symbol in libraries, in order. So whichever you put first - the library with weak or with strong - that symbol will be used and all following same symbols will just be ignored.
I can compile and run everything here, however "L2" implementation of Logger_Init doesn't get called.
That's odd, because -l(L2_NAME) -l(L1_NAME) that is in your post should result in l2 implementation called. An MCVE:
cat >Makefile <<EOF
all: l1.a l2.a main.o
gcc main.o l1.a l2.a
./a.out
gcc main.o l2.a l1.a
./a.out
l2.a: l2.o
ar rcs $# $<
l1.a: l1.o
ar rcs $# $<
EOF
cat >main.c <<EOF
int main() {
void Logger_Init();
Logger_Init();
}
EOF
cat >l1.c <<EOF
void __attribute__((weak)) Logger_Init(void) {
puts("I am weak");
}
EOF
cat >l2.c <<EOF
void Logger_Init(void)
{
puts("I am strong");
}
EOF
results in:
$ make
...
gcc main.o l1.a l2.a
./a.out
I am weak
gcc main.o l2.a l1.a
./a.out
I am strong
ie. whichever is first, is first. I tested it also with -L. -ll2 -ll1 and renamed libraries to libl*.a - same result. I suspect your method of checking was flawed.
Make has 44 years, it's a grandpa with a long beard. Use something modern, like cmake.
Using weak attribute may lead to very bad spaghetti code that is very, very hard to fix and refactor later. Consider just using a function pointer with get/set accessors.
Can you tell us more about why you think weak functions are bad? #Bktero
Opinion based:
Disadvantages:
Compiler specific syntax, non-portable code, non-standard.
If non-reentrant, hard to patch to allow to pass user specified context.
You can overwrite the function from anywhere in the code. It's basically a hot sauce for your spaghetti code.
IDE is confused and do not know where to jump to definition, because there are two.
Hard to unit test, because:
one executable can provide one overload of the function, so:
unit testing with multiple executables requires more writing
which makes it really horrible to use an IDE "go to definition" feature, because then you'll get more and more definitions of the same function
unit testing with a wrapper with a settable function pointer is the solution, which... it could be just implemented as the callback itself.
If it's meant to be a callback from the library/subsystem:
allows basically for one instance of that library
as programming grows, multiple instances of the same library are needed
which requires writing/merging a single entrypoint a single place from multiple code places.
Merging multiple projects is hard, because:
imagine a library with a weak callback
two libraries that are using that library and overwriting that weak callback
then you can't use those two libraries together, you'll get just a duplicated definition of a function.
It requires patching or selective compiling of that libraries.
It requires a single entry point with a dispatch table from which library it was called.
Spaghetti code.
As noted by OP - problems with linking static libraries related to order, needed to be solved with compiler specific syntax --whole-archive. Because it depends on order, it can be surprising, sometimes work and sometimes not, resulting in surprising and unexpected bugs, because you only change the order of libraries and oops - your application does not work.
Similar problems to global variables. Basically same problems as with signals. Same solution as to signals - using function pointers. Just like using SA_SIGINFO with sigaction allows to pass a custom function pointer with custom void *context pointer.
Advantages:
faster code
less typing
Any experience to share?
Well, I used and researched weak (or undefined) functions as callback from libraries and it resulted in code that is hard to merge and hard to refactor.
STM32 HAL libraries were implemented with weak functions, they optionally enabled function pointers later, now there is a #if (USE_HAL_*_REGISTER_CALLBACKS == 1) stuff in their sources, see ex stm32l0xx_hal_uart.h#L248
I recently installed MSYS2 following Steely Wing's answer on this thread: How to install MinGW-w64 and MSYS2?
The final goal is to compile a project on Windows in order to create an executable that I can use with an installer.
But here comes the problem: when I use make, gcc does not find err.h:
src/debug/error_handler.c:2:10: fatal error: err.h: No such file or directory
2 | #include <err.h>
| ^~~~~~~
compilation terminated.
make: *** [Makefile:26: imagin] Interrupt
After some searching I found out that it could come from the MinGW's default Include path. Thus following this: http://mingw.org/wiki/IncludePathHOWTO, I created an empty foo.c and executed gcc -v foo.c:
Configured with: ../gcc-9.2.0/configure --prefix=/mingw64 --with-local-prefix=/mingw64/local --build=x86_64-w64-mingw32 --host=x86_64-w64-mingw32 --target=x86_64-w64-mingw32 --with-native-system-header-dir=/mingw64/x86_64-w64-mingw32/include --libexecdir=/mingw64/lib --enable-bootstrap --with-arch=x86-64 --with-tune=generic --enable-languages=c,lto,c++,fortran,ada,objc,obj-c++ --enable-shared --enable-static --enable-libatomic --enable-threads=posix --enable-graphite --enable-fully-dynamic-string --enable-libstdcxx-filesystem-ts=yes --enable-libstdcxx-time=yes --disable-libstdcxx-pch --disable-libstdcxx-debug --disable-isl-version-check --enable-lto --enable-libgomp --disable-multilib --enable-checking=release --disable-rpath --disable-win32-registry --disable-nls --disable-werror --disable-symvers --enable-plugin --with-libiconv --with-system-zlib --with-gmp=/mingw64 --with-mpfr=/mingw64 --with-mpc=/mingw64 --with-isl=/mingw64 --with-pkgversion='Rev2, Built by MSYS2 project' --with-bugurl=https://sourceforge.net/projects/msys2 --with-gnu-as --with-gnu-ld
Thread model: posix
gcc version 9.2.0 (Rev2, Built by MSYS2 project)
COLLECT_GCC_OPTIONS='-v' '-mtune=generic' '-march=x86-64'
C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/9.2.0/cc1.exe -quiet -v -iprefix C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/9.2.0/ -D_REENTRANT foo.c -quiet -dumpbase foo.c -mtune=generic -march=x86-64 -auxbase foo -version -o C:\msys64\tmp\ccXlDSUc.s
GNU C17 (Rev2, Built by MSYS2 project) version 9.2.0 (x86_64-w64-mingw32)
compiled by GNU C version 9.2.0, GMP version 6.1.2, MPFR version 4.0.2, MPC version 1.1.0, isl version isl-0.21-GMP
warning: GMP header version 6.1.2 differs from library version 6.2.0.
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
ignoring duplicate directory "C:/msys64/mingw64/lib/gcc/../../lib/gcc/x86_64-w64-mingw32/9.2.0/include"
ignoring nonexistent directory "C:/building/msys64/mingw64/include"
ignoring nonexistent directory "/mingw64/include"
ignoring duplicate directory "C:/msys64/mingw64/lib/gcc/../../lib/gcc/x86_64-w64-mingw32/9.2.0/include-fixed"
ignoring duplicate directory "C:/msys64/mingw64/lib/gcc/../../lib/gcc/x86_64-w64-mingw32/9.2.0/../../../../x86_64-w64-mingw32/include"
ignoring nonexistent directory "C:/building/msys64/mingw64/x86_64-w64-mingw32/include"
#include "..." search starts here:
#include <...> search starts here:
C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/9.2.0/include
C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/9.2.0/../../../../include
C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/9.2.0/include-fixed
C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/9.2.0/../../../../x86_64-w64-mingw32/include
End of search list.
GNU C17 (Rev2, Built by MSYS2 project) version 9.2.0 (x86_64-w64-mingw32)
compiled by GNU C version 9.2.0, GMP version 6.1.2, MPFR version 4.0.2, MPC version 1.1.0, isl version isl-0.21-GMP
warning: GMP header version 6.1.2 differs from library version 6.2.0.
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
Compiler executable checksum: 3bcdf03344e3ad7cb057c2ec82f696e6
COLLECT_GCC_OPTIONS='-v' '-mtune=generic' '-march=x86-64'
C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/9.2.0/../../../../x86_64-w64-mingw32/bin/as.exe -v -o C:\msys64\tmp\cckgYpTe.o C:\msys64\tmp\ccXlDSUc.s
GNU assembler version 2.33.1 (x86_64-w64-mingw32) using BFD version (GNU Binutils) 2.33.1
COMPILER_PATH=C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/9.2.0/;C:/msys64/mingw64/bin/../lib/gcc/;C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/9.2.0/../../../../x86_64-w64-mingw32/bin/
LIBRARY_PATH=C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/9.2.0/;C:/msys64/mingw64/bin/../lib/gcc/;C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/9.2.0/../../../../x86_64-w64-mingw32/lib/../lib/;C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/9.2.0/../../../../lib/;C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/9.2.0/../../../../x86_64-w64-mingw32/lib/;C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/9.2.0/../../../
COLLECT_GCC_OPTIONS='-v' '-mtune=generic' '-march=x86-64'
C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/9.2.0/collect2.exe -plugin C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/9.2.0/liblto_plugin-0.dll -plugin-opt=C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/9.2.0/lto-wrapper.exe -plugin-opt=-fresolution=C:\msys64\tmp\cch1aQIi.res -plugin-opt=-pass-through=-lmingw32 -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_eh -plugin-opt=-pass-through=-lmoldname -plugin-opt=-pass-through=-lmingwex -plugin-opt=-pass-through=-lmsvcrt -plugin-opt=-pass-through=-lpthread -plugin-opt=-pass-through=-ladvapi32 -plugin-opt=-pass-through=-lshell32 -plugin-opt=-pass-through=-luser32 -plugin-opt=-pass-through=-lkernel32 -plugin-opt=-pass-through=-lmingw32 -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_eh -plugin-opt=-pass-through=-lmoldname -plugin-opt=-pass-through=-lmingwex -plugin-opt=-pass-through=-lmsvcrt -m i386pep -Bdynamic C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/9.2.0/../../../../x86_64-w64-mingw32/lib/../lib/crt2.o C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/9.2.0/crtbegin.o -LC:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/9.2.0 -LC:/msys64/mingw64/bin/../lib/gcc -LC:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/9.2.0/../../../../x86_64-w64-mingw32/lib/../lib -LC:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/9.2.0/../../../../lib -LC:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/9.2.0/../../../../x86_64-w64-mingw32/lib -LC:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/9.2.0/../../.. C:\msys64\tmp\cckgYpTe.o -lmingw32 -lgcc -lgcc_eh -lmoldname -lmingwex -lmsvcrt -lpthread -ladvapi32 -lshell32 -luser32 -lkernel32 -lmingw32 -lgcc -lgcc_eh -lmoldname -lmingwex -lmsvcrt C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/9.2.0/../../../../x86_64-w64-mingw32/lib/../lib/default-manifest.o C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/9.2.0/crtend.o
C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/9.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/9.2.0/../../../../x86_64-w64-mingw32/lib/../lib/libmingw32.a(lib64_libmingw32_a-crt0_c.o): in function `main':
D:/mingwbuild/mingw-w64-crt-git/src/mingw-w64/mingw-w64-crt/crt/crt0_c.c:18: undefined reference to `WinMain'
collect2.exe: error: ld returned 1 exit status
This is a bit messy but I think the interesting part is there:
#include "..." search starts here:
#include <...> search starts here:
C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/9.2.0/include
C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/9.2.0/../../../../include
C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/9.2.0/include-fixed
C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/9.2.0/../../../../x86_64-w64-mingw32/include
Considering the fact that err.h comes from openssl that I installed using https://packages.msys2.org/package/mingw-w64-x86_64-openssl, openssl folder is included in /mingw64/include. But gcc does not find it.
I tried to use -I/mingw64/include in my CFLAGS, but it did not work. I tried with -I/mingw64/include/openssl and it worked, but now gcc considers errx function as unititialized, as if, before, gcc never went in the openssl folder. I tried to add -L/mingw64/lib but it did not work.
Any help is appreciated, thank's by advance. DO NOT hesitate to ask for any precision I could have miss here.
After hours of searching I found out that there was no err.h on MSYS2, see https://github.com/cliffordwolf/icestorm/issues/85 and resolved my case by replacing all my errx() function calls following these method https://github.com/cliffordwolf/icestorm/pull/88/commits/9acaac752ac53b51b9b33290394b7811048221fa.
I am trying to compile a large C file (specifically for MATLAB mexing). The C file is around 20 MB (available from the GCC bug tracker if you want to play around with it).
Here is the command I am running and the output to screen, below. This has been running for hours, and as you can see, optimization is already disabled (-O0). Why is this so slow? Is there a way I can make this faster?
(For reference: Ubuntu 12.04 (Precise Pangolin) 64 bit and GCC 4.7.3)
/usr/bin/gcc -c -DMX_COMPAT_32 -D_GNU_SOURCE -DMATLAB_MEX_FILE -I"/usr/local/MATLAB/R2015a/extern/include" -I"/usr/local/MATLAB/R2015a/simulink/include" -ansi -fexceptions -fPIC -fno-omit-frame-pointer -pthread -O0 -DNDEBUG path/to/test4.c -o /tmp/mex_198714460457975_3922/test4.o -v
Using built-in specs.
COLLECT_GCC=/usr/bin/gcc
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu/Linaro 4.7.3-2ubuntu1~12.04' --with-bugurl=file:///usr/share/doc/gcc-4.7/README.Bugs --enable-languages=c,c++,go,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.7 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.7 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --enable-plugin --with-system-zlib --enable-objc-gc --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64 --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 4.7.3 (Ubuntu/Linaro 4.7.3-2ubuntu1~12.04)
COLLECT_GCC_OPTIONS='-c' '-D' 'MX_COMPAT_32' '-D' '_GNU_SOURCE' '-D' 'MATLAB_MEX_FILE' '-I' '/usr/local/MATLAB/R2015a/extern/include' '-I' '/usr/local/MATLAB/R2015a/simulink/include' '-ansi' '-fexceptions' '-fPIC' '-fno-omit-frame-pointer' '-pthread' '-O0' '-D' 'NDEBUG' '-o' '/tmp/mex_198714460457975_3922/test4.o' '-v' '-mtune=generic' '-march=x86-64'
/usr/lib/gcc/x86_64-linux-gnu/4.7/cc1 -quiet -v -I /usr/local/MATLAB/R2015a/extern/include -I /usr/local/MATLAB/R2015a/simulink/include -imultilib . -imultiarch x86_64-linux-gnu -D_REENTRANT -D MX_COMPAT_32 -D _GNU_SOURCE -D MATLAB_MEX_FILE -D NDEBUG path/to/test4.c -quiet -dumpbase test4.c -mtune=generic -march=x86-64 -auxbase-strip /tmp/mex_198714460457975_3922/test4.o -O0 -ansi -version -fexceptions -fPIC -fno-omit-frame-pointer -fstack-protector -o /tmp/ccxDOA5f.s
GNU C (Ubuntu/Linaro 4.7.3-2ubuntu1~12.04) version 4.7.3 (x86_64-linux-gnu)
compiled by GNU C version 4.7.3, GMP version 5.0.2, MPFR version 3.1.0-p3, MPC version 0.9
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
ignoring nonexistent directory "/usr/local/include/x86_64-linux-gnu"
ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../../x86_64-linux-gnu/include"
#include "..." search starts here:
#include <...> search starts here:
/usr/local/MATLAB/R2015a/extern/include
/usr/local/MATLAB/R2015a/simulink/include
/usr/lib/gcc/x86_64-linux-gnu/4.7/include
/usr/local/include
/usr/lib/gcc/x86_64-linux-gnu/4.7/include-fixed
/usr/include/x86_64-linux-gnu
/usr/include
End of search list.
GNU C (Ubuntu/Linaro 4.7.3-2ubuntu1~12.04) version 4.7.3 (x86_64-linux-gnu)
compiled by GNU C version 4.7.3, GMP version 5.0.2, MPFR version 3.1.0-p3, MPC version 0.9
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
Compiler executable checksum: c119948b394d79ea05b6b3986ab084cf
EDIT: a follow-on: I followed chqrlie's advice and tcc compiled my function in <5 seconds (I had to remove the -ansi flag only and turn "gcc" to "tcc"), which is pretty remarkable, really. I can only imagine the complexity of GCC.
When trying to then mex it, however, there is one other command mex typically needs. The second command is typically:
/usr/bin/gcc -pthread -Wl,--no-undefined -Wl,-rpath-link,/usr/local/MATLAB/R2015a/bin/glnxa64 -shared -O -Wl,--version-script,"/usr/local/MATLAB/R2015a/extern/lib/glnxa64/mexFunction.map" /tmp/mex_61853296369424_4031/test4.o -L"/usr/local/MATLAB/R2015a/bin/glnxa64" -lmx -lmex -lmat -lm -lstdc++ -o test4.mexa64
I cannot run this with tcc as some of these flags are not compatible. If I try to run this second compilation step with GCC, I get:
/usr/bin/ld: test4.o: relocation R_X86_64_PC32 against undefined symbol `mxGetPr' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: final link failed: Bad value
collect2: error: ld returned 1 exit status
EDIT: The solution appears to be clang. tcc can compile the file, but the arguments in the second step in mexing are incompatible with tcc's argument options. Clang is very fast and produces a nice, small, optimized file.
Nearly the entire file is one expression, the assignment to double f[24] = .... That's going to generate a gigantic abstract syntax tree tree. I'd be surprised if anything but a specialized compiler could handle that efficiently.
The 20 megabyte file itself may be fine, but the one giant expression may be what is causing the issue. Try as a preliminary step, splitting the line into double f[24] = {0} and then 24 assignments of f[0] = ...; f[1] = ... and see what happens. Worst case, you can split the 24 assignments into 24 functions, each in its own .c file, and compile them separately. This won't reduce the size of the AST, it will just reorganize it, but GCC is probably more optimized at handling many statements which together add up to a lot of code, vs. one huge expression.
The ultimate approach would be to generate the code in a more optimized manner. If I search for s4*s5*s6, for example, I get 77,783 hits. These s[4-6] variables don't change. You should generate a temporary variable, double _tmp1 = s4*s5*s6; and then use that instead of repeating the expression. You've just eliminated 311,132 nodes from your abstract syntax tree (assuming s4*s5*s6 is 5 nodes and _tmp1 is one node). That's that much less processing GCC has to do. This should also generate faster code (you won't repeat the same multiplication 77,783 times).
If you do this in a smart way in a recursive manner (e.g. s4*s5*s6 --> _tmp1, (c4*c6+s4*s5*s6) --> (c4*c6+_tmp1) --> _tmp2, c5*s6*(c4*c6+s4*s5*s6) --> c5*s6*_tmp2 -> _tmp3, etc...), you can probably eliminate most of the size of the generated code.
Upon testing, I found that the Clang compiler seems to have less problems compiling large files. Although Clang consumed almost a gigabyte of memory during compilation, it successfully turned OP's source code form into a 70 kB object file. This works for all optimization levels I tested.
gcc was also able to compile this file quickly and without consuming too much memory if optimization is turned on. This bug in gcc comes from the large expression in OPs code which places a huge burden on the register allocator. With optimizations turned on, the compiler performs an optimization called common subexpression elimination which is able to remove a lot of redundancy from OPs code, reducing both compilation time and object file size to manageable values.
Here are some tests with the testcase from the aforementioned bug report:
$ time gcc5 -O3 -c -o testcase.gcc5-O3.o testcase.c
real 0m39,30s
user 0m37,85s
sys 0m1,42s
$ time gcc5 -O0 -c -o testcase.gcc5-O0.o testcase.c
real 23m33,34s
user 23m27,07s
sys 0m5,92s
$ time tcc -c -o testcase.tcc.o testcase.c
real 0m2,60s
user 0m2,42s
sys 0m0,17s
$ time clang -O3 -c -o testcase.clang-O3.o testcase.c
real 0m13,71s
user 0m12,55s
sys 0m1,16s
$ time clang -O0 -c -o testcase.clang-O0.o testcase.c
real 0m17,63s
user 0m16,14s
sys 0m1,49s
$ time clang -Os -c -o testcase.clang-Os.o testcase.c
real 0m14,88s
user 0m13,73s
sys 0m1,11s
$ time clang -Oz -c -o testcase.clang-Oz.o testcase.c
real 0m13,56s
user 0m12,45s
sys 0m1,09
This is the resulting object file size:
text data bss dec hex filename
39101286 0 0 39101286 254a366 testcase.clang-O0.o
72161 0 0 72161 119e1 testcase.clang-O3.o
72087 0 0 72087 11997 testcase.clang-Os.o
72087 0 0 72087 11997 testcase.clang-Oz.o
38683240 0 0 38683240 24e4268 testcase.gcc5-O0.o
87500 0 0 87500 155cc testcase.gcc5-O3.o
78239 0 0 78239 1319f testcase.gcc5-Os.o
69210504 3170616 0 72381120 45072c0 testcase.tcc.o
Try Fabrice Bellard's tiny C compiler tcc from http://tinycc.org:
chqrlie$ time tcc -c test4.c
real 0m1.336s
user 0m1.248s
sys 0m0.084s
chqrlie$ size test4.o
text data bss dec hex filename
38953877 3170632 0 42124509 282c4dd test4.o
Yes, that's 1.336 seconds on a pretty basic PC!
Of course I cannot test the resulting executable, but the object file should be linkable with the rest of your program and libraries.
For this test, I used a dummy version of file mex.h:
typedef struct mxArray mxArray;
double *mxGetPr(const mxArray*);
enum { mxREAL = 0 };
mxArray *mxCreateDoubleMatrix(int nx, int ny, int type);
gcc still has not finished compiling...
EDIT: gcc managed to hog my Linux box so badly I cannot connect to it anymore:(
I tried to replace char** in main argument to long **. However, the compiler complains about it with the following warning :
> add2.c:3:5: error: second parameter of 'main' (argument array) must be
> of type 'char **' int main(int i, long **a) {
Is there anyway that I can compile this code by adding some gcc flags?
As this post is receiving too many negative votes, I would like to explain more about why I am asking this question. I have this question because Im facing this problem in a CTF (Capture the flag) practice competition. I reckon this maybe worth asking because
1. It may let people know more about the arguments in C main function
I have googled around and never seen this problem being asked before( Everyone just accept char** as an argument for C main function)
We maybe able to disable the checking using GCC flags, this may help others to learn more about how much GCC can do too
I am sorry that this question receiving so many downvotes and I have no idea why people downvoting this. I still think this question is worth to discuss.
I ran this code on the server SUCCESSFULLY and I have posted my result as an answer here. If anyone knows how to make this work, I would be so happy to hear that.
level3#io64:/tmp$ cat add2.c
#include <unistd.h>
int main(int i, long **a) {
if(*a[1] * 0xabcdabcdabcdu == 0x123412341234u)
execl("/bin/sh", "sh", 0);
return 0;
}
level3#io64:/tmp$ gcc -o a add2.c
/usr/bin/ld: cannot open output file a: Permission denied
collect2: error: ld returned 1 exit status
level3#io64:/tmp$ gcc add2.c
/usr/bin/ld: cannot open output file a.out: Permission denied
collect2: error: ld returned 1 exit status
level3#io64:/tmp$ gcc -o abc add2.c
level3#io64:/tmp$ gcc -v -o abcd add2.c
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/4.7/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Debian 4.7.2-5' --with-bugurl=file:///usr/share/doc/gcc-4.7/README.Bugs --enable-languages=c,c++,go,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.7 --enable-shared --enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.7 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --enable-plugin --enable-objc-gc --with-arch-32=i586 --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 4.7.2 (Debian 4.7.2-5)
COLLECT_GCC_OPTIONS='-v' '-o' 'abcd' '-mtune=generic' '-march=x86-64'
/usr/lib/gcc/x86_64-linux-gnu/4.7/cc1 -quiet -v -imultiarch x86_64-linux-gnu add2.c -quiet -dumpbase add2.c -mtune=generic -march=x86-64 -auxbase add2 -version -o ./ccyNP1XF.s
GNU C (Debian 4.7.2-5) version 4.7.2 (x86_64-linux-gnu)
compiled by GNU C version 4.7.2, GMP version 5.0.5, MPFR version 3.1.0-p10, MPC version 0.9
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=100000
ignoring nonexistent directory "/usr/local/include/x86_64-linux-gnu"
ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../../x86_64-linux-gnu/include"
#include "..." search starts here:
#include <...> search starts here:
/usr/lib/gcc/x86_64-linux-gnu/4.7/include
/usr/local/include
/usr/lib/gcc/x86_64-linux-gnu/4.7/include-fixed
/usr/include/x86_64-linux-gnu
/usr/include
End of search list.
GNU C (Debian 4.7.2-5) version 4.7.2 (x86_64-linux-gnu)
compiled by GNU C version 4.7.2, GMP version 5.0.5, MPFR version 3.1.0-p10, MPC version 0.9
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=100000
Compiler executable checksum: 7fa7c2a970be5e19ce72b2057c14800d
COLLECT_GCC_OPTIONS='-v' '-o' 'abcd' '-mtune=generic' '-march=x86-64'
as -v --64 -o ./ccJEfzc6.o ./ccyNP1XF.s
GNU assembler version 2.22 (x86_64-linux-gnu) using BFD version (GNU Binutils for Debian) 2.22
COMPILER_PATH=/usr/lib/gcc/x86_64-linux-gnu/4.7/:/usr/lib/gcc/x86_64-linux-gnu/4.7/:/usr/lib/gcc/x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/4.7/:/usr/lib/gcc/x86_64-linux-gnu/
LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/4.7/:/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../../lib/:/lib/x86_64-linux-gnu/:/lib/../lib/:/usr/lib/x86_64-linux-gnu/:/usr/lib/../lib/:/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../:/lib/:/usr/lib/
COLLECT_GCC_OPTIONS='-v' '-o' 'abcd' '-mtune=generic' '-march=x86-64'
/usr/lib/gcc/x86_64-linux-gnu/4.7/collect2 --sysroot=/ --build-id --no-add-needed --eh-frame-hdr -m elf_x86_64 --hash-style=both -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o abcd /usr/lib/gcc/x86_64-linux-gnu/4.7/../../../x86_64-linux-gnu/crt1.o /usr/lib/gcc/x86_64-linux-gnu/4.7/../../../x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/4.7/crtbegin.o -L/usr/lib/gcc/x86_64-linux-gnu/4.7 -L/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../x86_64-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../../lib -L/lib/x86_64-linux-gnu -L/lib/../lib -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/4.7/../../.. ./ccJEfzc6.o -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc/x86_64-linux-gnu/4.7/crtend.o /usr/lib/gcc/x86_64-linux-gnu/4.7/../../../x86_64-linux-gnu/crtn.o
These are the only allowed main declarations, there is no int main(int i, long **a) and we cannot invent one as it is simply not supported.
From C++ Standard,
3.6.1 Main function
An implementation shall not predefine the main function. This function
shall not be overloaded. It shall have a return type of type int, but
otherwise its type is implementation-defined. All implementations
shall allow both
— a function of () returning int and
— a function of (int, pointer to pointer to char) returning int
It depends on what system you are compiling this for. In a hosted environment, you are usually not allowed to change the parameters of main. In case you are changing them, the compiler must support it and document how.
GCC does not support non-standard arguments of main() in any gcc port I know of.
There exists no compiler which allows the programmer to invent their own, crazy format of main(). If such a compiler existed, it would not follow the C and C++ standards.
Complete reference for the allowed forms of main in C and C++.
The operating system, the shell, the compiler, and the startup code all work together to pass a char ** as the second parameter to main, in accordance with the C and C++ specifications.
If you want to change the second parameter to main, you need to write
your own operating system
your own shell
your own compiler, and
your own startup code
Good luck with that! We'll see you in 50 years when you're done.
I tested this on the server (I AM NOT ABLE TO RUN THIS CODE ON MY MACHINE). And apparently, the parameter a is stored in stack like char.
If I am calling my program like this
./a 12345678
and print out *a[1] as long in hex format, I got the value 0x3837363534333231 I will say that the program did not consider my input as long even the argument type is long.
The usual way to do this is set argv as char** type and cast it back to long using pointer.
I hope this can help someone who face the same problem and please let me know if you have ideas why this code can be compiled.
According to all the answers/comments/c spec provided, it seems like it is impossible to do that.
I'm trying to compile a simple C program, but apparently the program is not linking properly.
hello.c
/* Simple C program. */
#include<stdio.h>
int main() {
printf("Hello MIPS! \n");
return 0;
}
I am trying to compile the program with the following command, mips-gcc -v hello.c -o hello
The output I'm getting when I try to compile / link the program,
Using built-in specs.
COLLECT_GCC=bin/mips-gcc
COLLECT_LTO_WRAPPER=/opt/cross/gcc-mips/libexec/gcc/mips/4.8.2/lto-wrapper
Target: mips
Configured with: ../gcc-4.8.2/configure --target=mips --prefix=/opt/cross/gcc-mips --enable-interwork --enable-multilib --enable-languages=c --with-newlib --with-headers=/opt/cross/src/newlib-2.1.0/newlib/libc/include/ --disable-libssp --disable-nls
Thread model: single
gcc version 4.8.2 (GCC)
COLLECT_GCC_OPTIONS='-v' '-o' 'hello'
/opt/cross/gcc-mips/libexec/gcc/mips/4.8.2/cc1 -quiet -v hello.c -quiet -dumpbase hello.c -auxbase hello -version -o /var/folders/1z/k_by6wd95tsccc6s1_tkttpr0000gn/T//ccqPwmTq.s
GNU C (GCC) version 4.8.2 (mips)
compiled by GNU C version 4.2.1 Compatible Apple LLVM 5.1 (clang-503.0.38), GMP version 4.3.2, MPFR version 2.4.2, MPC version 0.8.1
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
#include "..." search starts here:
#include <...> search starts here:
/opt/cross/gcc-mips/lib/gcc/mips/4.8.2/include
/opt/cross/gcc-mips/lib/gcc/mips/4.8.2/include-fixed
/opt/cross/gcc-mips/lib/gcc/mips/4.8.2/../../../../mips/sys-include
/opt/cross/gcc-mips/lib/gcc/mips/4.8.2/../../../../mips/include
End of search list.
GNU C (GCC) version 4.8.2 (mips)
compiled by GNU C version 4.2.1 Compatible Apple LLVM 5.1 (clang-503.0.38), GMP version 4.3.2, MPFR version 2.4.2, MPC version 0.8.1
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
Compiler executable checksum: e28a4def2fba399e5af333f18f473404
COLLECT_GCC_OPTIONS='-v' '-o' 'hello'
/opt/cross/gcc-mips/lib/gcc/mips/4.8.2/../../../../mips/bin/as -EB -O1 -no-mdebug -mabi=32 -o /var/folders/1z/k_by6wd95tsccc6s1_tkttpr0000gn/T//ccgd49A6.o /var/folders/1z/k_by6wd95tsccc6s1_tkttpr0000gn/T//ccqPwmTq.s
COMPILER_PATH=/opt/cross/gcc-mips/libexec/gcc/mips/4.8.2/:/opt/cross/gcc-mips/libexec/gcc/mips/4.8.2/:/opt/cross/gcc-mips/libexec/gcc/mips/:/opt/cross/gcc-mips/lib/gcc/mips/4.8.2/:/opt/cross/gcc-mips/lib/gcc/mips/:/opt/cross/gcc-mips/lib/gcc/mips/4.8.2/../../../../mips/bin/
LIBRARY_PATH=/opt/cross/gcc-mips/lib/gcc/mips/4.8.2/:/opt/cross/gcc-mips/lib/gcc/mips/4.8.2/../../../../mips/lib/
COLLECT_GCC_OPTIONS='-v' '-o' 'hello'
/opt/cross/gcc-mips/libexec/gcc/mips/4.8.2/collect2 -EB -o hello /opt/cross/gcc-mips/lib/gcc/mips/4.8.2/crti.o /opt/cross/gcc-mips/lib/gcc/mips/4.8.2/crtbegin.o -L/opt/cross/gcc-mips/lib/gcc/mips/4.8.2 -L/opt/cross/gcc-mips/lib/gcc/mips/4.8.2/../../../../mips/lib /var/folders/1z/k_by6wd95tsccc6s1_tkttpr0000gn/T//ccgd49A6.o -lgcc -lgcc /opt/cross/gcc-mips/lib/gcc/mips/4.8.2/crtend.o /opt/cross/gcc-mips/lib/gcc/mips/4.8.2/crtn.o
/opt/cross/gcc-mips/lib/gcc/mips/4.8.2/../../../../mips/bin/ld: warning: cannot find entry symbol _start; defaulting to 0000000000400038
/var/folders/1z/k_by6wd95tsccc6s1_tkttpr0000gn/T//ccgd49A6.o: In function `main':
(.text+0x18): undefined reference to `puts'
collect2: error: ld returned 1 exit status
Stop passing -v; it just produces a crazy amount of debug output that doesn't relate to your problem.
mips-gcc -o hello hello.c produces something like
ld: warning: cannot find entry symbol _start; defaulting to 0000000000400038
ccgd49A6.o: In function `main': (.text+0x18): undefined reference to `puts'
The second error indicates that you need -lc on the end of your command line to pull in the libc library (which provides puts). The first error indicates that you also need a crt0.o from somewhere (to provide _start). In other words, you're invoking the compiler in some kind of "bare-metal" mode, where it assumes you're writing code to run directly on the machine instead of in a hosted C environment (where you'd have access to command-line arguments, and a standard library, and a filesystem, and so on).
Your problem seems similar to this guy's in 2006: http://osdir.com/ml/lib.newlib/2006-07/msg00029.html
The solution there was to use -T nullmon.ld to specify a linker directive file that included crt0.o; and also perhaps to use mips-elf-gcc instead of mips-gcc.
However, programming for bare metal usually requires that you start very low-level and not try anything as complicated as C until you've already gotten familiar with assembly. See the answers to Bare metal cross compilers input for more information (and it even talks specifically about MIPS!).