How to compile C++ freestanding / baremetal with g++?
C++ has many aspects, included by default, that are not desirable or even functional on embedded bare metal / free standing platforms.
How can I configure g++ to compile C++ in a manner suitable for embedded bare-metal / freestanding?
1 answer
-
answered 2022-03-14 09:48
Lundin
The compiler option
-ffreestanding
is explicitly there for this purpose. It enables implementation-defined forms of main and it will disable various assumptions about standard library functions, optimizing code a bit differently in some situations.Unfortunately in terms of of
main()
, C++ explicitly doesn't allowvoid main (void)
as an implementation-defined form, unlike C. There is no sensible solution to this, it's a language flaw. Name itmain_
or some such.However, this doesn't disable or block any dangerous and unsuitable C++ features from being used - that burden lies on the programmer who picked C++. You have to manually ensure that things like heap allocation, RTTI, exceptions and so on aren't present. Removing the entire heap segment from your linker script is a sensible thing to do - it should block things like
std::vector
orstd::string
from linking.Then depending on target, there might be certain suitable gcc compiler ports. Such as in case of ARM where one compiler port is called "gcc-none-eabi", which would be the suitable one for bare metal Cortex M microcontrollers.
At a minimum, you'll need a "C run-time" (CRT) for the target - either use one provided by the tool chain (generally recommended) or create one yourself (compile with
-nostdlib
). It's not a beginner task to create one, particularly not for targets with advanced MMUs. Some general advise of how to do so here. Creating one for C++ is slightly more intricate than for C, since it also has to include all constructor calls to static storage duration objects.
do you know?
how many words do you know
See also questions close to this topic
-
C++ increment with macro
I have the following code and I want to use increment with macro:
#include <iostream> #define ABS(x) ((x) < 0 ? -(x) : (x)) int main(int argc, char** argv) { int x = 5; const int result = ABS(x++); std::cout << "R: " << result << std::endl; std::cout << "X: " << x << std::endl; return EXIT_SUCCESS; }
But output will be incorrect:
R: 6 X: 7
Is it possible to somehow use macros with an increment, or should this be abandoned altogether?
-
Can anyone pls tell me whats wrong with my code ? im stuck for the last 3 hours ,this question is bipartite graph in c++
idk why im getting error ,can someone help ? im trying to prove if a graph is bipartite or not in c++
bool isBipartite(vector<int> graph[],int V) { vector<int> vis(V,0); vector<int> color(V,-1); color[0]=1; queue <int> q; q.push(0); while (!q.empty()) { int temp = q.front(); q.pop(); for (int i=0;i<V;i++) { if (!vis[i] && color[i] == -1) "if there is an edge, and colour is not assigned" { color[i] = 1 - color[temp]; q.push(i); vis[i]=1; } else if (!vis[i] && color[i] == color[temp] "if there is an edge and both vertices have same colours" { vis[i]=1; return 0; // graph is not bipartite } } } return 1; }
it gives output "no" for whatever i enter
-
How to assign two or more values to a QMap Variable in Qt
I am getting confused of how to store the values assigned from 3 different functions and storing them in a single map variable
QMap<QString,QString> TrainMap = nullptr; if(......) ( TrainMap = PrevDayTrainMap(); TrainMap = NextDayTrainMap(); TrainMap = CurrentDayTrainMap(); }
The PrevDayTrainMap,NextDayTrainMap & CurrentDayTrainMap returns a set of values with Date and the TrainIdName.I need to store all the values from prevday,currentday and nextday in the TrainMap but it stores only the currentday values to the TrainMap as it is assigned at the last.I am not sure what to do so that it doesn't overwrite.If I should merge what is the way to do it?
-
Why does my function work in g++, but not in LeetCode?
I'm trying to submit code for this question, https://leetcode.com/problems/zigzag-conversion/
I'm using g++ to compile on my system. It works and outputs all the example solutions correctly on my end. However, it keeps giving me an error when I put the code into the submission area.
Here's a look at my code...
#include <string> #include <iostream> using namespace std; class Solution { public: string convert(string s, int numRows) { int size = s.size(); int i, j; string *zigZag = new string[numRows]; char* retStr = new char[size]; int count = 0; bool moreString = true; int col = 0; while(moreString) { for(i = 0; i< numRows && count < size; i++) { zigZag[i][col] = s[count]; count++; } col++; for(i = numRows - 2; i > 0 && count < size; i--) { zigZag[i][col] = s[count]; count++; col++; } if(count >= size) moreString = false; } count = 0; for(i = 0; i < numRows; i++) { for(j = 0; j < col; j++) { if(zigZag[i][j] != '\0') { retStr[count] = zigZag[i][j]; count++; } } } return retStr; } };
This is the error it keeps spitting out at me...
================================================================= ==31==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60200000001e at pc 0x0000003441f4 bp 0x7ffdf5b48350 sp 0x7ffdf5b48348 WRITE of size 1 at 0x60200000001e thread T0 #3 0x7f93f12dd0b2 (/lib/x86_64-linux-gnu/libc.so.6+0x270b2) 0x60200000001e is located 0 bytes to the right of 14-byte region [0x602000000010,0x60200000001e) allocated by thread T0 here: #4 0x7f93f12dd0b2 (/lib/x86_64-linux-gnu/libc.so.6+0x270b2) Shadow bytes around the buggy address: 0x0c047fff7fb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0c047fff7fc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0c047fff7fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0c047fff7fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0c047fff7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 =>0x0c047fff8000: fa fa 00[06]fa fa fa fa fa fa fa fa fa fa fa fa 0x0c047fff8010: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c047fff8020: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c047fff8030: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c047fff8040: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c047fff8050: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa Shadow byte legend (one shadow byte represents 8 application bytes): Addressable: 00 Partially addressable: 01 02 03 04 05 06 07 Heap left redzone: fa Freed heap region: fd Stack left redzone: f1 Stack mid redzone: f2 Stack right redzone: f3 Stack after return: f5 Stack use after scope: f8 Global redzone: f9 Global init order: f6 Poisoned by user: f7 Container overflow: fc Array cookie: ac Intra object redzone: bb ASan internal: fe Left alloca redzone: ca Right alloca redzone: cb Shadow gap: cc ==31==ABORTING
Any advice would be appreciated.
-
unordered_map and unordered_set are working differently in MSVC++ and G++ compilers
unordered_map and unordered_set are working differently in MSVC++ and G++ compilers. The insertion order is maintained properly in MSVC++ but not in g++
unordered_set<char> uset; uset.emplace('b'); uset.emplace('a'); uset.emplace('d'); uset.emplace('c'); for (auto it : uset) { cout << it << " "; }
The above code prints b a d c on windows with MSVC++ where as prints c d b a on linux using GCC(g++). Which is correct? I am a windows dev for long time, just surprised looking at results on linux.
-
Linking C++ code to a dylib library in MacOS
I was able to setup BlockSci on MacOS High Sierra 10.13.6. The setup installed header files in
/usr/local/include
and alibblocksci.dylib
in/usr/local/lib
. The C++ code I am trying to compile is:#include "blocksci.hpp" #include <iostream> #include <string> int main(int argc, const char * argv[]) { blocksci::Blockchain chain{"path/config.json"}; return 0; };
The compile command I am using for
hello.cpp
is:g++ -std=c++17 -L/usr/local/lib -I/usr/local/include/blocksci -I/usr/local/include/blocksci/external -o hello hello.cpp
However, the symbols for the BlockSci library are not found:
Undefined symbols for architecture x86_64: "blocksci::Blockchain::Blockchain(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)", referenced from: _main in hello-942a60.o "blocksci::Blockchain::~Blockchain()", referenced from: _main in hello-942a60.o ld: symbol(s) not found for architecture x86_64 clang: error: linker command failed with exit code 1 (use -v to see invocation)
What am I doing wrong when I try to compile this?
-
How to run FreeRTOS + Lwip application on EK-TM4C1294XL launchpad featuring a TM4C1294NCPDTI microcontroller device?
I have a EK-TM4C1294XL launchpad with a TM4C1294NCPDTI microcontroller device.I want to run a FreeRTOS + Lwip application on the board. The examples provided by TI has lwip example but it uses Tiva-OS and I want to use FreeRTOS. Can you provide any resources on how to run a FreeRTOS+Lwip on EK-TM4C1294XL microcontroller.
-
Platformio: teensy platform error, wiring.h
I'm trying to compile my project in platformio. I'm using teensy 4.1 board. Everything is fine besides built-in package wiring.h. I get error:
C:\Users\kubaj\.platformio\packages\framework-arduinoteensy\cores\teensy4/wiring.h:123:12: error: expected identifier before numeric constant #define PI 3.1415926535897932384626433832795 ^
as it's built-in I didn't change anything, but still getting the errors. Please give me a clue where to look for my mistakes.
-
PyFtdi Value Error 'No backend available' every now and then
I'm using pyftdi (https://eblot.github.io/pyftdi/) to handle a FTDI ft4232h. Everything usually works fine but every now and then I come across a ValueError saying 'No backend available'.
Is there any solution regarding that issue? I tried to copy the libusb-1.0.dll to C:\Windows32 as well as to C:\Windows\SysWOW64. I also tried reinstalling the ftdi driver with zadig as recommended.
Nothing worked so far.
NOTE: I'm bound to windows.
-
Probleme to link my stub with newlib with arm-none-eabi-gcc
I'm trying to compile a small proof of work tath run lua code on the rasperry pi zero bare-metal.
All my object file and lua's have been compiled with similar options. I tried with and without the
-nostdlib
and-lc -lgcc
but the output is the same.Commande:
arm-none-eabi-gcc \ -mfpu=vfp -mfloat-abi=hard -march=armv6zk -mtune=arm1176jzf-s \ -g -O0 \ -Wl,-z,max-page-size=0x04,-T,linker.ld \ -nostdlib \ ./lua/lua-5.4.4/src/lapi.o ./lua/lua-5.4.4/src/lauxlib.o ./lua/lua-5.4.4/src/lbaselib.o ./lua/lua-5.4.4/src/lcode.o ./lua/lua-5.4.4/src/lcorolib.o ./lua/lua-5.4.4/src/lctype.o ./lua/lua-5.4.4/src/ldblib.o ./lua/lua-5.4.4/src/ldebug.o ./lua/lua-5.4.4/src/ldo.o ./lua/lua-5.4.4/src/ldump.o ./lua/lua-5.4.4/src/lfunc.o ./lua/lua-5.4.4/src/lgc.o ./lua/lua-5.4.4/src/linit.o ./lua/lua-5.4.4/src/liolib.o ./lua/lua-5.4.4/src/llex.o ./lua/lua-5.4.4/src/lmathlib.o ./lua/lua-5.4.4/src/lmem.o ./lua/lua-5.4.4/src/loadlib.o ./lua/lua-5.4.4/src/lobject.o ./lua/lua-5.4.4/src/lopcodes.o ./lua/lua-5.4.4/src/loslib.o ./lua/lua-5.4.4/src/lparser.o ./lua/lua-5.4.4/src/lstate.o ./lua/lua-5.4.4/src/lstring.o ./lua/lua-5.4.4/src/lstrlib.o ./lua/lua-5.4.4/src/ltable.o ./lua/lua-5.4.4/src/ltablib.o ./lua/lua-5.4.4/src/ltm.o ./lua/lua-5.4.4/src/lundump.o ./lua/lua-5.4.4/src/lutf8lib.o ./lua/lua-5.4.4/src/lvm.o ./lua/lua-5.4.4/src/lzio.o \ ./.build/startup.o ./.build/start.o ./.build/main.o ./.build/bootstrap.lua.o ./.build/0stubs.o \ -lc \ -lgcc \ -lm
Output:
/usr/lib/gcc/arm-none-eabi/9.2.1/../../../arm-none-eabi/bin/ld: /usr/lib/gcc/arm-none-eabi/9.2.1/../../../arm-none-eabi/lib/arm/v5te/hard/libc.a(lib_a-fstatr.o): in function `_fstat_r': /build/newlib-wFsRXh/newlib-3.3.0/build/arm-none-eabi/arm/v5te/hard/newlib/libc/reent/../../../../../../../../newlib/libc/reent/fstatr.c:55: undefined reference to `_fstat' /usr/lib/gcc/arm-none-eabi/9.2.1/../../../arm-none-eabi/bin/ld: /usr/lib/gcc/arm-none-eabi/9.2.1/../../../arm-none-eabi/lib/arm/v5te/hard/libc.a(lib_a-openr.o): in function `_open_r': /build/newlib-wFsRXh/newlib-3.3.0/build/arm-none-eabi/arm/v5te/hard/newlib/libc/reent/../../../../../../../../newlib/libc/reent/openr.c:50: undefined reference to `_open' /usr/lib/gcc/arm-none-eabi/9.2.1/../../../arm-none-eabi/bin/ld: /usr/lib/gcc/arm-none-eabi/9.2.1/../../../arm-none-eabi/lib/arm/v5te/hard/libc.a(lib_a-timesr.o): in function `_times_r': /build/newlib-wFsRXh/newlib-3.3.0/build/arm-none-eabi/arm/v5te/hard/newlib/libc/reent/../../../../../../../../newlib/libc/reent/timesr.c:52: undefined reference to `_times' /usr/lib/gcc/arm-none-eabi/9.2.1/../../../arm-none-eabi/bin/ld: /usr/lib/gcc/arm-none-eabi/9.2.1/../../../arm-none-eabi/lib/arm/v5te/hard/libc.a(lib_a-unlinkr.o): in function `_unlink_r': /build/newlib-wFsRXh/newlib-3.3.0/build/arm-none-eabi/arm/v5te/hard/newlib/libc/reent/../../../../../../../../newlib/libc/reent/unlinkr.c:47: undefined reference to `_unlink' /usr/lib/gcc/arm-none-eabi/9.2.1/../../../arm-none-eabi/bin/ld: /usr/lib/gcc/arm-none-eabi/9.2.1/../../../arm-none-eabi/lib/arm/v5te/hard/libc.a(lib_a-writer.o): in function `_write_r': /build/newlib-wFsRXh/newlib-3.3.0/build/arm-none-eabi/arm/v5te/hard/newlib/libc/reent/../../../../../../../../newlib/libc/reent/writer.c:49: undefined reference to `_write' /usr/lib/gcc/arm-none-eabi/9.2.1/../../../arm-none-eabi/bin/ld: /usr/lib/gcc/arm-none-eabi/9.2.1/../../../arm-none-eabi/lib/arm/v5te/hard/libc.a(lib_a-closer.o): in function `_close_r': /build/newlib-wFsRXh/newlib-3.3.0/build/arm-none-eabi/arm/v5te/hard/newlib/libc/reent/../../../../../../../../newlib/libc/reent/closer.c:47: undefined reference to `_close' /usr/lib/gcc/arm-none-eabi/9.2.1/../../../arm-none-eabi/bin/ld: /usr/lib/gcc/arm-none-eabi/9.2.1/../../../arm-none-eabi/lib/arm/v5te/hard/libc.a(lib_a-gettimeofdayr.o): in function `_gettimeofday_r': /build/newlib-wFsRXh/newlib-3.3.0/build/arm-none-eabi/arm/v5te/hard/newlib/libc/reent/../../../../../../../../newlib/libc/reent/gettimeofdayr.c:62: undefined reference to `_gettimeofday' /usr/lib/gcc/arm-none-eabi/9.2.1/../../../arm-none-eabi/bin/ld: /usr/lib/gcc/arm-none-eabi/9.2.1/../../../arm-none-eabi/lib/arm/v5te/hard/libc.a(lib_a-isattyr.o): in function `_isatty_r': /build/newlib-wFsRXh/newlib-3.3.0/build/arm-none-eabi/arm/v5te/hard/newlib/libc/reent/../../../../../../../../newlib/libc/reent/isattyr.c:52: undefined reference to `_isatty' /usr/lib/gcc/arm-none-eabi/9.2.1/../../../arm-none-eabi/bin/ld: /usr/lib/gcc/arm-none-eabi/9.2.1/../../../arm-none-eabi/lib/arm/v5te/hard/libc.a(lib_a-linkr.o): in function `_link_r': /build/newlib-wFsRXh/newlib-3.3.0/build/arm-none-eabi/arm/v5te/hard/newlib/libc/reent/../../../../../../../../newlib/libc/reent/linkr.c:53: undefined reference to `_link' /usr/lib/gcc/arm-none-eabi/9.2.1/../../../arm-none-eabi/bin/ld: /usr/lib/gcc/arm-none-eabi/9.2.1/../../../arm-none-eabi/lib/arm/v5te/hard/libc.a(lib_a-lseekr.o): in function `_lseek_r': /build/newlib-wFsRXh/newlib-3.3.0/build/arm-none-eabi/arm/v5te/hard/newlib/libc/reent/../../../../../../../../newlib/libc/reent/lseekr.c:49: undefined reference to `_lseek' /usr/lib/gcc/arm-none-eabi/9.2.1/../../../arm-none-eabi/bin/ld: /usr/lib/gcc/arm-none-eabi/9.2.1/../../../arm-none-eabi/lib/arm/v5te/hard/libc.a(lib_a-readr.o): in function `_read_r': /build/newlib-wFsRXh/newlib-3.3.0/build/arm-none-eabi/arm/v5te/hard/newlib/libc/reent/../../../../../../../../newlib/libc/reent/readr.c:49: undefined reference to `_read' /usr/lib/gcc/arm-none-eabi/9.2.1/../../../arm-none-eabi/bin/ld: /usr/lib/gcc/arm-none-eabi/9.2.1/../../../arm-none-eabi/lib/arm/v5te/hard/libc.a(lib_a-signalr.o): in function `_kill_r': /build/newlib-wFsRXh/newlib-3.3.0/build/arm-none-eabi/arm/v5te/hard/newlib/libc/reent/../../../../../../../../newlib/libc/reent/signalr.c:53: undefined reference to `_kill' /usr/lib/gcc/arm-none-eabi/9.2.1/../../../arm-none-eabi/bin/ld: /usr/lib/gcc/arm-none-eabi/9.2.1/../../../arm-none-eabi/lib/arm/v5te/hard/libc.a(lib_a-signalr.o): in function `_getpid_r': /build/newlib-wFsRXh/newlib-3.3.0/build/arm-none-eabi/arm/v5te/hard/newlib/libc/reent/../../../../../../../../newlib/libc/reent/signalr.c:83: undefined reference to `_getpid'
My 0stubs.c file:
#include <sys/stat.h> /* A helper function written in assembler to aid us in allocating memory */ extern caddr_t _get_stack_pointer(void); /* Increase program data space. As malloc and related functions depend on this, it is useful to have a working implementation. The following suffices for a standalone system; it exploits the symbol _end automatically defined by the GNU linker. */ caddr_t _sbrk( int incr ) { extern char _end; static char* heap_end = 0; char* prev_heap_end; if( heap_end == 0 ) heap_end = &_end; prev_heap_end = heap_end; heap_end += incr; return (caddr_t)prev_heap_end; } int close(int file) { return -1; } char *__env[1] = { 0 }; char **environ = __env; #include <errno.h> #undef errno extern int errno; int execve(char *name, char **argv, char **env) { errno = ENOMEM; return -1; } int fork(void) { errno = EAGAIN; return -1; } int kill(int pid, int sig) { errno = EINVAL; return -1; } int link(char *old, char *new) { errno = EMLINK; return -1; } int fstat(int file, struct stat *st) { st->st_mode = S_IFCHR; return 0; } int getpid(void) { return 1; } int isatty(int file) { return 1; } int lseek(int file, int ptr, int dir) { return 0; } int open(const char *name, int flags, int mode) { return -1; } int read(int file, char *ptr, int len) { return 0; } int times(struct tms *buf) { return -1; } int unlink(char *name) { errno = ENOENT; return -1; } int wait(int *status) { errno = ECHILD; return -1; } int write(int file, char *ptr, int len) { int todo; for (todo = 0; todo < len; todo++) { //outbyte (*ptr++); } return len; } void abort(void){ while(1){} } void exit(int status){ while(1){} }
-
customized sprintf: complete unit test to check it
I am using a custom version of sprintf (written for embedded bare metal systems). I would like to test if the string conversions are reliable, especially the float ones.
Is there and where can I find a complete set of tests for "standard" sprintf where I can replace calls to standard sprintf with my sprintf? -
Developing a bare metal lwip rtp application using Visual Studio
I am trying to get started with lwip running in bare metal (NO_SYS==1) mode. In order to learn how lwip works under the covers, I built lwip using the 'contrib/ports/win32' solution and test application that prints out the list of network adapters. The only change I made to this application was to change the configuration file 'lwip/contrib/examples/example_app/lwipopts.h' to run in bare metal mode by setting the NO_SYS preprocessor directive to 1.
#define NO_SYS 1
After installing npcap, configuring it to run in pcap compatibility mode, and also installing the npcap sdk 1.2 (and adding an environment variable
PCAP_DIR
that points to this sdk location), I can single step themain_loop()
forever loop in bare metal(NO_SYS==1)
mode. This is a great way to learn the inner workings of lwip while using Visual Studio.The 'lwip/contrib/examples/example_app/test.c' file example works well and prints out the following:
Starting lwIP, local interface IP is dhcp-enabled 0: NPF_{15A80AE8-8763-41F6-9FD5-48679C001987} Desc: "WAN Miniport (Network Monitor)" 1: NPF_{0118A172-5B42-4CAF-9E49-8BD25939888C} Desc: "WAN Miniport (IPv6)" 2: NPF_{78A6D491-D3BE-4A30-8148-140363AC5DAB} Desc: "WAN Miniport (IP)" 3: NPF_{9F0260A3-1AB8-467E-813F-318AB73F2AB5} Desc: "Intel(R) Ethernet Connection I217-LM" 4: NPF_Loopback Desc: "Adapter for loopback traffic capture" 5: NPF_{3CA2B6C7-E440-4901-87B8-CF3A8042ABC1} Desc: "TAP-Win32 Adapter V9 #2" 6: NPF_{CDAE33E7-4AFF-4458-8702-6E9473BB17B0} Desc: "TAP-Win32 Adapter V9" 7: NPF_{E2E817B7-54F1-4A41-BAD9-4BF568DE5B52} Desc: "Intel(R) Gigabit CT Desktop Adapter" Using adapter_num: 1 Using adapter: "WAN Miniport (IPv6)" status_callback==UP, local interface IP is 0.0.0.0
I have no idea how to convert the rtp application to run in bare metal
(NO_SYS==1)
mode. Also in windows, I am unsure how to setup the IP, GW and NETMASK values - I use DHCP from my ISP so I probably need to set those options also. From the source code, the rtp example in the repository 'lwip/contrib/apps/rtp/rtp.c' uses the socket api API which is not compatible with running in bare metal mode.How can
-
Implementing PRI macros 'portably'
The C99 specified inttypes.h header includes macros for providing format specifiers for the fixed-width integer types provided by stdint.h (beginning with PRI). While stdint.h is on the 'freestanding' list of headers and thus is always provided by the implementation, inttypes.h is not.
This means that when compiling for an unhosted environment (say bare-metal), you must provide inttypes.h yourself if you want to provide a standards-compliant printf that can handle fixed-width types.
However, I cannot figure out how to correctly determine at compile-time what each macro should be without manually inspecting the implementation's stdint.h, a task that would need to be repeated not just for each target platform, but for every supported compiler.
I tried an implementation via C11's _Generic but discovered one of the limitations of that feature.
Is there a standard way to do this?
-
How to link without libc on old (<9) gcc versions?
GCC 9 introduced the 'nolibc' linker option for linking without libc? How was it done on older version? Does one actually need a linker script for it or is it possible to achieve this with some other combination of linker options?