floating point library on cortex-m0plus - c

I am working on a project that uses dynamic relocations, it works fine for the Cortex-M4, but I am having some problems with the Cortex-M0+.
The problems are occuring with the symbols of the functions of floating point. This cores do not have floating point unit.
So I was trying to understand the difference between the codes generated of the two cores (M4 and M0+).
The code is this:
#include <stdint.h>
#include <math.h> // <fastmath.h>
float a, b, c; //, d, e;
void ldMain(void)
{
a = 1.100000f + a;
b = 1.100000f - b;
c = 1.100000f * c;
//d = 1.100000f / d;
}
The commands to compile and linking are these:
arm-none-eabi-gcc.exe -c TESTE.c -o TESTE.o0 -mthumb -mcpu=cortex-m0plus -O0 -mlong-calls -mword-relocations -mabi=atpcs -mfloat-abi=soft -mcaller-super-interworking
arm-none-eabi-ld.exe -o TESTE.o TESTE.o0 --relocatable --strip-all --discard-all --embedded-relocs
The symbols that are generated are (get with arm-none-eabi-readelf):
Relocation section '.rel.text' at offset 0x2e4 contains 6 entries:
Offset Info Type Sym.Value Sym. Name
00000028 00000b02 R_ARM_ABS32 00000004 a
0000002c 00000c02 R_ARM_ABS32 00000000 __addsf3
00000034 00000602 R_ARM_ABS32 00000004 b
00000038 00000802 R_ARM_ABS32 00000000 __subsf3
0000003c 00000902 R_ARM_ABS32 00000004 c
00000040 00000a02 R_ARM_ABS32 00000000 __mulsf3
Independent of the flag -mcpu=cortex-m0plus or -mcpu=cortex-m4 used on the gcc command, the symbols generated are the same.
The problem is that these symbols appear does not exist on cortex-m0plus.
The libgcc of cortex-m0plus (armv6-m) located at C:\Program Files (x86)\GNU Tools ARM Embedded\4.9 2015q2\lib\gcc\arm-none-eabi\4.9.3\armv6-m not have these symbols. It was verified with the command arm-none-eabi-nm.
Does anyone know why these symbols are used if they do not exist for the cortex-m0plus?
I am using the version 4.9 2015q2 of the GCC ARM Embedded.

These functions are defined in GCC glibc (either newlib or nanolib). This post is almost 4 years old, and I do not have experience with the 2015 GCC. However, the recent (e.g. 2018 etc.) GCC definitely has these FP software routines in the libraries.

Related

How does GCC implement __attribute__((constructor)) on MinGW?

I know that on ELF platforms, __attribute__((constructor)) uses the .ctors ELF section. Now I realized that the function attribute works with GCC on MinGW as well and I'm wondering how it is implemented.
For MinGW targets (and other COFF targets, like Cygwin) compiler just emits each constructor function address in .ctors COFF section:
$ cat c1.c
void c1() {
}
$ x86_64-w64-mingw32-gcc -c c1.c
$ objdump -x c1.o | grep ctors
# nothing
$ cat c1.c
__attribute__((constructor)) void c1() {
}
$ x86_64-w64-mingw32-gcc -c c1.c
$ objdump -x c1.o | grep ctors
5 .ctors 00000008 0000000000000000 0000000000000000 00000150 2**3
GNU ld linker (for MinGW targets) is then configured (via its default linker script) to combine these sections into regular .text section with __CTOR_LIST__ symbol pointing to the first item, and having the last item terminated with zero. (Probably .rdata section would be clearer since these are just addresses of functions, not CPU instructions, but for some reason .text is used. In fact LLVM LLD linker targeting MinGW places them in .rdata.)
LD linker:
$ x86_64-w64-mingw32-ld --verbose
...
.text ... {
...
__CTOR_LIST__ = .;
LONG (-1); LONG (-1);
KEEP (*(.ctors));
KEEP (*(.ctor));
KEEP (*(SORT_BY_NAME(.ctors.*)));
LONG (0); LONG (0);
...
...
}
Then it is up to C runtime library to run these constructors during initialization, by using this __CTOR_LIST__ symbol.
From mingw-w64 C runtime:
extern func_ptr __CTOR_LIST__[];
void __do_global_ctors (void)
{
// finds the last (zero terminated) item
...
// then runs from last to first:
for (i = nptrs; i >= 1; i--)
{
__CTOR_LIST__[i] ();
}
...
}
(also, it is very similar in Cygwin runtime)
This can be also seen in the debugger:
$ echo $MSYSTEM
MINGW64
$ cat c11.c
#include <stdio.h>
__attribute__((constructor))
void i1() {
puts("i 1");
}
int main() {
puts("main");
return 0;
}
$ gcc c11.c -o c11
$ gdb ./c11.exe
(gdb) b i1
(gdb) r
(gdb) bt
#0 0x00007ff603591548 in i1 ()
#1 0x00007ff6035915f2 in __do_global_ctors () at C:/_/M/mingw-w64-crt-git/src/mingw-w64/mingw-w64-crt/crt/gccmain.c:44
#2 0x00007ff60359164f in __main () at C:/_/M/mingw-w64-crt-git/src/mingw-w64/mingw-w64-crt/crt/gccmain.c:58
#3 0x00007ff60359139b in __tmainCRTStartup () at C:/_/M/mingw-w64-crt-git/src/mingw-w64/mingw-w64-crt/crt/crtexe.c:313
#4 0x00007ff6035914f6 in mainCRTStartup () at C:/_/M/mingw-w64-crt-git/src/mingw-w64/mingw-w64-crt/crt/crtexe.c:202
(gdb)
Note that in some environments (not MinGW and not Linux) it is instead the responsibility of GCC (its compiler runtime libgcc, more specifically its static part called crtbegin.o and crtend.o) and not C runtime to run these constructors.
Also, for comparison, on ELF targets (like Linux) GCC compiler used similar mechanism like the one described above for MinGW (it used ELF .ctors sections, although the rest was a bit different), but since GCC 4.7 (released in 2012) it uses slightly different mechanism (ELF .init_array section).

gcc weak attribute inconsistent behaviour

I am using gcc compiler in windows10's powershell. gcc came with the Atollic TrueSTUDIO ide. The reason I am doing this is to be able to create an .exe file from the C code so unit testing becomes easier.
I encounter a linker error (undefined reference to 'function_name') when there is a function that is defined as weak and that function is used in another .c file.
Meanwhile I do not get this linker error if I use arm-atollic-eabi-gcc or gcc running on ubuntu.
Here is a simple code to demonstrate this:
hello.c:
#include "weak.h"
void whatever(void)
{
iamweak();
}
weak.c:
#include <stdio.h>
#include "weak.h"
void __attribute__((weak)) iamweak(void)
{
printf("i am weak...\n");
}
weak.h
void iamweak(void);
main.c
int main(void)
{
return 0;
}
Creating the object files and linking:
> gcc -c main.c weak.c hello.c
> gcc -o main.exe main.o weak.o hello.o
> hello.o:hello.c:(.text+0x7): undefined reference to `iamweak'
collect2.exe: error: ld returned 1 exit status
Now I checked with gcc-nm the symbol table of hello.o:
> gcc-nm hello.o
00000000 b .bss
00000000 d .data
00000000 r .eh_frame
00000000 r .rdata$zzz
00000000 t .text
U _iamweak
00000000 T _whatever
Symbol table for weak.o:
>gcc-nm weak.o
00000000 b .bss
00000000 d .data
00000000 r .eh_frame
00000000 r .rdata
00000000 r .rdata$zzz
00000000 t .text
00000000 T .weak._iamweak.
w _iamweak
U _puts
Now when I use gcc on Ubuntu as I said everything works. Also the symbol tables are a little different.
Symbol table for hello.o:
nm hello.o
U _GLOBAL_OFFSET_TABLE_
U iamweak
0000000000000000 T whatever
Symbol table for weak.o:
nm weak.o
U _GLOBAL_OFFSET_TABLE_
0000000000000000 W iamweak
U puts
From https://linux.die.net/man/1/nm it says that "If lowercase, the symbol is local; if uppercase, the symbol is global (external)."
So iamweak is local in windows10 and global in Ubuntu. Is that why the linker cannot see it? What can I do about this? The weak function definitions are also in some HAL libraries and I don't want to modify those. Is there a workaround?
it is atollic gcc fork error. It does even worse:
main:
00401440: push %ebp
00401441: mov %esp,%ebp
00401443: and $0xfffffff0,%esp
00401446: call 0x401970 <__main>
36 iamweak();
0040144b: call 0x0
37 return 0;
00401450: mov $0x0,%eax
38 }
the complete atollic studio project here

What is *ABS* section and when to use?

// foo.c
int main() { return 0; }
When I compiled the code above I noticed some symbols located in *ABS*:
$ gcc foo.c
$ objdump -t a.out | grep ABS
0000000000000000 l df *ABS* 0000000000000000 crtstuff.c
0000000000000000 l df *ABS* 0000000000000000 foo.c
0000000000000000 l df *ABS* 0000000000000000 crtstuff.c
0000000000000000 l df *ABS* 0000000000000000
Looks like they're some debug symbols but isn't debug info are stored in somewhere like .debug_info section?
According to man objdump:
*ABS* if the section is absolute (ie not connected with any section)
I don't understand it since no example is given here.
Question here shows an interesting way to pass some extra symbols in *ABS* by --defsym. But I think it could be easier by passing macros.
So what is this *ABS* section and when would someone use it?
EDIT:
Absolute symbols don't get relocated, their virtual addresses (0000000000000000 in the example you gave) are fixed.
I wrote a demo but it seems that the addresses of absolute symbols can be modified.
// foo.c
#include <stdio.h>
extern char foo;
int main()
{
printf("%p\n", &foo);
return 0;
}
$ gcc foo.c -Wl,--defsym,foo=0xbeef -g
$ objdump -t a.out | grep ABS
0000000000000000 l df *ABS* 0000000000000000 crtstuff.c
0000000000000000 l df *ABS* 0000000000000000 foo.c
0000000000000000 l df *ABS* 0000000000000000 crtstuff.c
0000000000000000 l df *ABS* 0000000000000000
000000000000beef g *ABS* 0000000000000000 foo
# the addresses are not fixed
$ ./a.out
0x556e06629eef
$ ./a.out
0x564f0d7aeeef
$ ./a.out
0x55c2608dceef
# gdb shows that before entering main(), &foo == 0xbeef
$ gdb a.out
(gdb) p &foo
$1 = 0xbeef <error: Cannot access memory at address 0xbeef>
(gdb) br main
Breakpoint 1 at 0x6b4: file foo.c, line 7.
(gdb) r
Starting program: /home/user/a.out
Breakpoint 1, main () at foo.c:7
7 printf("%p", &foo);
(gdb) p &foo
$2 = 0x55555555feef <error: Cannot access memory at address 0x55555555feef>
If you look at other symbols you might find an index (or section name if the reader does the mapping for you) in place of *ABS*. This is a section index in the section headers table. It points to the section header of a section the symbol is defined in (or SHN_UNDEF (zero) if it is undefined in the object you are looking at). So the value (virtual address) of a symbol will be adjusted by the same value its containing section is adjusted during loading. (This process is called relocation.) Not so for absolute symbols (having special value SHN_ABS as their st_shndx). Absolute symbols don't get relocated, their virtual addresses (0000000000000000 in the example you gave) are fixed.
Such absolute symbols are sometimes used to store some meta information. In particular, the compiler can create symbols with symbol names equivalent to the names of translation units it compiles. Such symbols aren't needed for linking or running the program, they are just for humans and binary processing tools.
As for your question w.r.t the reason this isn't stored in .debug_info section (and why this info is emitted even though no debug switches were specified), the answer is that it is a separate thing; it is just the symbol table (.symtab). It is also needed for debugging, sure, but it's primary purpose is linking of object (.o) files. By default it is preserved in linked executables/libraries. You can get rid of it with strip.
Much of what I wrote here is in man 5 elf.
I don't think doing what you are doing (with --defsym) is supported/supposed to work with dynamic linking. Looking at the compiler output (gcc -S -masm=intel), I see this
lea rsi, foo[rip]
Or, if we look at objdump -M intel -rD a.out (linking with -q to preserve relocations), we see the same thing: rip-relative addressing is used to get the address of foo.
113d: 48 8d 35 ab ad 00 00 lea rsi,[rip+0xadab] # beef <foo>
1140: R_X86_64_PC32 foo-0x4
The compiler doesn't know that it's going to be an absolute symbol, so it produces the code it does (as for a normal symbol). rip is the instruction pointer, so it depends on the base address of the segment containing .text after the program is mapped into memory by ld.so.
I found this answer shedding light on the proper use-case for absolute symbols.

linking dilemma (undefined reference) between MinGW and MSVC. MinGW fails MSVC works

I'm trying to port an old C .dll library originally done with MSVC that uses BEA Tuxedo library to use MinGW.
I have encountered a situation where MSVC compiles and links one file but MinGW fails. The actual problem is in linking stage. There comes 'undefined reference' error.
Here's the minimal example to create a dll: (tpsetunsol_test.c)
#include <atmi.h>
void __stdcall msghandler(char *pszMessage, long lMessageLen, long lFlags)
{
}
int Inittpsetunsol()
{
int ret = 0;
tpsetunsol(msghandler);
return ret;
}
This compiles without errors:
gcc -Wall -fexceptions -g -O2 -DWIN32 -DNDEBUG -D_WINDOWS -ID:/dev/tuxedo/include -o tpsetunsol_test.o -c tpsetunsol_test.c
Here comes the error:
dllwrap --export-all-symbols -LD:/dev/tuxedo/lib -k --output-lib test.lib --output-def test.def --enable-stdcall-fixup --add-stdcall-alias -o IAWS.dll tpsetunsol_test.o -lkernel32 -luser32 -lgdi32 -lwinspool -lcomdlg32 -ladvapi32 -lshell32 -lwtuxws32
C:\MinGW\bin\dllwrap.exe: no export definition file provided.
Creating one, but that may not be what you want
tpsetunsol_test.o: In function `Inittpsetunsol':
d:\dev\tpsetunsol_test.c:13: undefined reference to `tpsetunsol'
collect2.exe: error: ld returned 1 exit status
C:\MinGW\bin\dllwrap.exe: C:\MinGW\bin\gcc exited with status 1
function declaration in atmi.h:
extern void (_TMDLLENTRY * _TMDLLENTRY tpsetunsol _((void (_TMDLLENTRY *)(char _TM_FAR *, long, long)))) _((char _TM_FAR *, long, long));
#define _TMDLLENTRY __stdcall
#define _TM_FAR
Version:
$ gcc -v
Using built-in specs.
COLLECT_GCC=C:\MinGW\bin\gcc.exe
COLLECT_LTO_WRAPPER=c:/mingw/bin/../libexec/gcc/mingw32/4.7.2/lto-wrapper.exe
Target: mingw32
Configured with: ../gcc-4.7.2/configure --enable- languages=c,c++,ada,fortran,objc,obj-c++ --disable-sjlj-exceptions --with-dwarf2 --enable-shared --enable-libgomp --disable-win32-registry --enable-libstdcxx-debug --disable-build-poststage1-with-cxx --enable-version-specific-runtime-libs --build=ming
w32 --prefix=/mingw
Thread model: win32
gcc version 4.7.2 (GCC)
Edit: I found out using nm on object files created by MSVC and GCC that symbol tpsetunsol is different
Looking at _tpsetunsol symbol it is quite evident that MSVC and GCC produce different symbols.
GCC produces: U _tpsetunsol and MSVC: U _tpsetunsol#4
Edit: nm output after build with Haroogan's suggestion:
$ dllwrap --export-all-symbols -LD:/dev/tuxedo.64/lib --output-lib test.lib --output-def test.def -o IAWS.dll tpsetunsol_test.o -lwtuxws32_new
C:\MinGW\bin\dllwrap.exe: no export definition file provided.
Creating one, but that may not be what you want
tpsetunsol_test.o: In function `Inittpsetunsol':
d:\dev\IA/tpsetunsol_test.c:13: undefined reference to `tpsetunsol'
collect2.exe: error: ld returned 1 exit status
C:\MinGW\bin\dllwrap.exe: C:\MinGW\bin\gcc exited with status 1
$ nm tpsetunsol_test.o
00000000 b .bss
00000000 d .data
00000000 N .debug_abbrev
00000000 N .debug_aranges
00000000 N .debug_info
00000000 N .debug_line
00000000 N .debug_loc
00000000 r .eh_frame
00000000 t .text
00000004 T _Inittpsetunsol
00000000 T _msghandler#12
U _tpsetunsol
$ nm ../tuxedo.64/lib/libwtuxws32.a | grep -i tpsetuns
00000000 I __imp__tpsetunsol#4
00000000 T _tpsetunsol#4
output from gcc preprocessor (-E) (only the line tpsetunsol is declared)
extern void (__attribute__((__stdcall__)) * __attribute__((__stdcall__)) tpsetunsol (void (__attribute__((__stdcall__)) *)(char *, long, long))) (char *, long, long);
As you have already discovered yourself - name mangling may be different across compilers. To solve your problem follow the instructions:
Download and install (can build from source) gendef utility:
If you have usual MinGW (targeting 32-bit), then obtain it here;
If you have MinGW-w64 (targeting 64-bit), then obtain it here.
Run gendef wtuxws32.dll (will generate wtuxws32.def);
Run dlltool -D wtuxws32.dll -d wtuxws32.def -l libwtuxws32.a (will generate libwtuxws32.a);
Put libwtuxws32.a to D:/dev/tuxedo/lib;
Now link against it.
Change the declaration of tpsetunsol() in the atmi.h header from:
extern void (_TMDLLENTRY * _TMDLLENTRY tpsetunsol _((void (_TMDLLENTRY *)(char _TM_FAR *, long, long)))) _((char _TM_FAR *, long, long));
to:
extern void (_TMDLLENTRY * (_TMDLLENTRY tpsetunsol) _((void (_TMDLLENTRY *)(char _TM_FAR *, long, long)))) _((char _TM_FAR *, long, long));
// ^ ^
so the function will be properly declared to be a stdcall function as it is in the library (as indicated by the #4 suffix on the name in the library).

Undefined reference to main - collect2: ld returned 1 exit status

I'm trying to compile a program (called es3), but, when I write from terminal:
gcc es3.c -o es3
it appears this message:
/usr/lib/gcc/i686-linux-gnu/4.4.5/../../../../lib/crt1.o: In function `_start':
(.text+0x18): undefined reference to `main'
collect2: ld returned 1 exit status
What could I do?
It means that es3.c does not define a main function, and you are attempting to create an executable out of it. An executable needs to have an entry point, thereby the linker complains.
To compile only to an object file, use the -c option:
gcc es3.c -c
gcc es3.o main.c -o es3
The above compiles es3.c to an object file, then compiles a file main.c that would contain the main function, and the linker merges es3.o and main.o into an executable called es3.
Perhaps your main function has been commented out because of e.g. preprocessing.
To learn what preprocessing is doing, try gcc -C -E es3.c > es3.i then look with an editor into the generated file es3.i (and search main inside it).
First, you should always (since you are a newbie) compile with
gcc -Wall -g -c es3.c
gcc -Wall -g es3.o -o es3
The -Wall flag is extremely important, and you should always use it. It tells the compiler to give you (almost) all warnings. And you should always listen to the warnings, i.e. correct your source code file es3.C till you got no more warnings.
The -g flag is important also, because it asks gcc to put debugging information in the object file and the executable. Then you are able to use a debugger (like gdb) to debug your program.
To get the list of symbols in an object file or an executable, you can use nm.
Of course, I'm assuming you use a GNU/Linux system (and I invite you to use GNU/Linux if you don't use it already).
In my case it was just because I had not Saved the source file and was trying to compile a empty file .
Executable file needs a main function. See below hello world demo.
#include <stdio.h>
int main(void)
{
printf("Hello world!\n");
return 0;
}
As you can see there is a main function. if you don't have this main function, ld will report "undefined reference to main' "
check my result:
$ cat es3.c
#include <stdio.h>
int main(void)
{
printf("Hello world!\n");
return 0;
}
$ gcc -Wall -g -c es3.c
$ gcc -Wall -g es3.o -o es3
~$ ./es3
Hello world!
please use $ objdump -t es3.o to check if there is a main symbol. Below is my result.
$ objdump -t es3.o
es3.o: file format elf32-i386
SYMBOL TABLE:
00000000 l df *ABS* 00000000 es3.c
00000000 l d .text 00000000 .text
00000000 l d .data 00000000 .data
00000000 l d .bss 00000000 .bss
00000000 l d .debug_abbrev 00000000 .debug_abbrev
00000000 l d .debug_info 00000000 .debug_info
00000000 l d .debug_line 00000000 .debug_line
00000000 l d .rodata 00000000 .rodata
00000000 l d .debug_frame 00000000 .debug_frame
00000000 l d .debug_loc 00000000 .debug_loc
00000000 l d .debug_pubnames 00000000 .debug_pubnames
00000000 l d .debug_aranges 00000000 .debug_aranges
00000000 l d .debug_str 00000000 .debug_str
00000000 l d .note.GNU-stack 00000000 .note.GNU-stack
00000000 l d .comment 00000000 .comment
00000000 g F .text 0000002b main
00000000 *UND* 00000000 puts
One possibility which has not been mentioned so far is that you might not be editing the file you think you are. i.e. your editor might have a different cwd than you had in mind.
Run 'more' on the file you're compiling to double check that it does indeed have the contents you hope it does. Hope that helps!
You can just add a main function to resolve this problem.
Just like:
int main()
{
return 0;
}
I my case I found out the void for the main function declaration was missing.
I was previously using Visual Studio in Windows and this was never a problem, so I thought I might leave it out now too.

Resources