Error in linking files into a kernel - c++

I have problem. I have compiled file boot.o:
[BITS 16]
[ORG 0x7C00]
[global start]
[extern _main]
start:
call _main
cli
hlt
and compiled C++ file main.o:
int main(){
//processes
}
Im using this LD file linker.ld for linking:
OUTPUT_FORMAT("binary")
ENTRY(start)
SECTIONS
{
. = 0x100000;
.text ALIGN(4096) :
{
*(.text*)
*(.gnu.linkonce.t*)
}
.rodata ALIGN(4096) :
{
start_ctors = .;
*(.ctor*)
end_ctors = .;
start_dtors = .;
*(.dtor*)
end_dtors = .;
*(.rodata*)
*(.gnu.linkonce.r*)
}
.data ALIGN(4096) :
{
*(.data*)
*(.gnu.linkonce.d*)
}
.bss ALIGN(4096) :
{
*(.COMMON*)
*(.bss*)
*(.gnu.linkonce.b*)
}
}
So I want to start linking and I'm using g++ for windows, and I'm using this commands in cmd: ld -T linker.ld -o kernle.bin main.o boot.o. And is rejecting me error: ld: cannot preform PE operations on non PE output file kernel.bin. Does anybody know how can I repair it? Please help me.

Maybe -oformat bin?
And I doubt you will be able to boot it, anyway... Go read some bootloader tutorials (on osdev.org and brokenthorn.com) and you will get an answer why.

You are using a compiler and toolchain built to make windows executables, not flat binaries. You need a cross compiler for kernel development. Also, you will need a bootloader, a kernel, even minimal, can't fit into the 512 byte bootsector.
Correct me if I'm wrong, but you don't seem to understand the bot process of a pc at all. I suggest reading http://wiki.osdev.org/ as a start.

Related

exceptions not working cross compiling with clang and cmake for arm cortex m4, and "got" section is generated

I have been trying lately to compile firmware with Clang and CMake, using Toolchain files, for C++. I can get it normally working without exceptions. A problem arises when I use exceptions.
LLVM version: 13.0.0
CMake version: 3.21.3
CPU: STM32L432KC, ARM Cortex M4
To successfully compile the firmware I use precompiled libc, libm, libgcc and libstdc++ bundled with ARM GNU GCC Toolchain, version 10.3.2021-10.
I won't put the entire toolchain file here. Trust me that the paths to the CMAKE_C_COMPILER, CMAKE_CXX_COMPILER, CMAKE_ASM_COMPILER and CMAKE_LINKER are good.
CMAKE_CXX_FLAGS_INIT, which define initial compile flags for C language, are defined like so:
-mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16
-nodefaultlibs
--sysroot=${ARM_GNU_TOOLCHAIN_PATH}/arm-none-eabi
-flto
-fdata-sections -ffunction-sections
# For <iostream>, <string>, ...
-isystem "${ARM_GNU_TOOLCHAIN_PATH}/arm-none-eabi/include/c++/${ARM_GNU_TOOLCHAIN_GCC_VERSION}/"
# For <bits/*>, ...
-isystem "${ARM_GNU_TOOLCHAIN_PATH}/arm-none-eabi/include/c++/${ARM_GNU_TOOLCHAIN_GCC_VERSION}/arm-none-eabi/thumb/v7e-m+fp/hard/"
-fexceptions
ARM_GNU_TOOLCHAIN_PATH is the root path to the mentioned ARM GNU GCC Toolchain. ARM_GNU_TOOLCHAIN_GCC_VERSION is equal to 10.3.1.
The linker flags, defined with CMAKE_EXE_LINKER_FLAGS_INIT:
-mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16
-nodefaultlibs
--sysroot=${ARM_GNU_TOOLCHAIN_PATH}/arm-none-eabi
-flto
-fdata-sections -ffunction-sections
-Wl,--gc-sections
-flto
-fexceptions
# Path to standard libraries: libc, libm, ...
-L"${ARM_GNU_TOOLCHAIN_PATH}/arm-none-eabi/lib/thumb/v7e-m+fp/hard/"
# Path to libgcc
-L"${ARM_GNU_TOOLCHAIN_PATH}/lib/gcc/arm-none-eabi/${ARM_GNU_TOOLCHAIN_GCC_VERSION}/thumb/v7e-m+fp/hard/"
-lc -lm -lnosys -lstdc++ -lgcc")
If in the binary there is no, try ... catch block. Everything compiles just fine, but if there is at least one block:
try
{
throw std::runtime_error{"Some error!"};
} catch (const std::exception&e)
{
printf("Error: %s\r\n", e.what());
}
The linker inputs the .got section, before .data section without being instructed within the linker script. The RAM start address is 0x20000000. objdump output:
...
Contents of section .got:
20000000 848f0108 ....
Contents of section .data:
20000004 00000000 00000000 08000020 08000020 ........... ...
20000014 10000020 10000020 18000020 18000020 ... ... ... ...
20000024 20000020 20000020 28000020 28000020 .. .. (.. (..
20000034 30000020 30000020 38000020 38000020 0.. 0.. 8.. 8..
...
My linker script, generated by CubeMX, has LMA .data section, which shall be the first in RAM.:
.fini_array :
{
. = ALIGN(8);
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array*))
PROVIDE_HIDDEN (__fini_array_end = .);
. = ALIGN(8);
} >FLASH
/* used by the startup to initialize data */
_sidata = LOADADDR(.data);
/* Initialized data sections goes into RAM, load LMA copy after code */
.data :
{
. = ALIGN(8);
_sdata = .; /* create a global symbol at data start */
*(.data) /* .data sections */
*(.data*) /* .data* sections */
. = ALIGN(8);
_edata = .; /* define a global symbol at data end */
} >RAM AT> FLASH
As you can see in the comment, _sdata will be used by the startup code to initialize data in RAM. The problem is that _sdata will be set to 0x20000000, not 0x20000008, where the first global variable lies. This means that all the global variables will have wrong values.
As a workaround, I have added a .got section which uses all the got* input sections:
...
.fini_array :
{
. = ALIGN(8);
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array*))
PROVIDE_HIDDEN (__fini_array_end = .);
. = ALIGN(8);
} >FLASH
.got :
{
. = ALIGN(8);
*(.got)
*(.got*)
. = ALIGN(8);
} >RAM AT> FLASH
/* used by the startup to initialize data */
_sidata = LOADADDR(.data);
/* Initialized data sections goes into RAM, load LMA copy after code */
.data :
{
...
Since .got section is related to dynamic symbol resolution, I am not really fluent with it. I use only static libraries to compile the firmware, since I write bare-metal programs targeted one binary per project.
The main issue is that the exceptions don't work correctly. No exceptions are caught within the above try ... catch ... block. The firmware ends within Default_Handler.
I guess it's related to the .got section generated by clang. Clang is not able to properly link the compiler builtins from libgcc to handle the exceptions.
Could you help me in debugging and fixing that?
Use -Wl,--target2=rel flag when compiling.
I have created a post on the llvm-dev mailing list, which can be found here. Peter Smith has helped to resolve the problem and pointed to the solution.

How can I compile a hybrid (asm, C++) source code into a 32-bit program?

I am using Cygwin 32-bit under Win7 in a 64-bit machine.
The following program
makefile:
runme: main.cpp asm.o
g++ main.cpp asm.o -o executable
asm.o: asm.asm
nasm -f elf asm.asm -o asm.o
asm.asm:
section .data
section .bss
section .text
global GetValueFromASM
GetValueFromASM:
mov eax, 9
ret
main.cpp:
#include <iostream>
using namespace std;
extern "C" int GetValueFromASM();
int main()
{
cout<<"GetValueFromASM() returned = "<<GetValueFromASM()<<endl;
return 0;
}
is giving me the following error:
$ make
nasm -f elf asm.asm -o asm.o
g++ main.cpp asm.o -o executable
/tmp/cc3F1pPh.o:main.cpp:(.text+0x26): undefined reference to `GetValueFromASM'
collect2: error: ld returned 1 exit status
make: *** [makefile:2: runme] Error 1
I am not understanding why this error is being generated.
How can I get rid of this issue?
You have to prefix your symbols with _, as is customary in Windows/Cygwin:
section .data
section .bss
section .text
global _GetValueFromASM
_GetValueFromASM:
mov eax, 9
ret
The rest of your code should work fine.
An alternative would be to compile with -fno-leading-underscore. However, this may break linking with other (Cygwin system) libraries. I suggest using the first option if portability to other platforms does not matter to you.
Quoting from the GNU Online Docs:
-fleading-underscore
This option and its counterpart, -fno-leading-underscore, forcibly change the way C symbols are represented in the object file. One use is to help link with legacy assembly code.
Warning: the -fleading-underscore switch causes GCC to generate code that is not binary compatible with code generated without that switch. Use it to conform to a non-default application binary interface. Not all targets provide complete support for this switch.

How to run HelloWorld on ARM

I need to run HelloWorld on arm.
I launch:
$ arm-none-eabi-g++ -mthumb -mcpu=cortex-m3 -c test.cpp -o test
$ file test
test: ELF 32-bit LSB relocatable, ARM, EABI5 version 1 (SYSV), not stripped
$ qemu-arm test <br>
Error while loading test: Permission denied
qemu-system-arm -machine help
...
lm3s811evb Stellaris LM3S811EVB
...
From either the lm3s811 datasheet or looking at the source for the stellaris backend on qemu arm hardware. Uart0 base address is 0x4000C000, the data (rx and tx) register is offset 0x000. From experience the qemu backends tend not to bother with the tx buffer being busy...
flash.s
.cpu cortex-m0
.thumb
.thumb_func
.global _start
_start:
.word 0x20001000
.word reset
.word hang
.word hang
.word hang
.word hang
.word hang
.thumb_func
reset:
bl notmain
b hang
.thumb_func
hang: b .
.thumb_func
.globl PUT32
PUT32:
str r1,[r0]
bx lr
uart01.c
void PUT32 ( unsigned int, unsigned int );
#define UART0BASE 0x4000C000
int notmain ( void )
{
unsigned int rx;
for(rx=0;rx<7;rx++)
{
PUT32(UART0BASE+0x00,0x30+rx);
}
return(0);
}
flash.ld
MEMORY
{
rom : ORIGIN = 0x00000000, LENGTH = 0x1000
ram : ORIGIN = 0x20000000, LENGTH = 0x1000
}
SECTIONS
{
.text : { *(.text*) } > rom
.rodata : { *(.rodata*) } > rom
.bss : { *(.bss*) } > ram
}
Yep, the stellaris was the first cortex-m3 in silicon that you could buy and I specified cortex-m0. Basically preventing the thumb2 extensions, or most of them. More portable, can easily change that if you want.
arm-none-eabi-as --warn -mcpu=cortex-m0 flash.s -o flash.o
arm-none-eabi-gcc -Wall -O2 -nostdlib -nostartfiles -ffreestanding -mcpu=cortex-m0 -mthumb -c uart01.c -o uart01.o
arm-none-eabi-ld -o uart01.elf -T flash.ld flash.o uart01.o
arm-none-eabi-objdump -D uart01.elf > uart01.list
arm-none-eabi-objcopy uart01.elf uart01.bin -O binary
then
qemu-system-arm -M lm3s811evb -m 16K -nographic -kernel uart01.bin
and the output is
0123456
ctrl-a then press x to exit qemu. or
qemu-system-arm -M lm3s811evb -m 16K -kernel uart01.bin
then ctrl-alt-3 (3 not F3) and the serial console pops up with the serial output. when you close that serial console qemu closes.
I want to remember someone telling me that the qemu cortex-m3 support is not that good.
the normal arm cores should be well tested as they are used to cross compile for all kinds of arm target boards. not sure exactly which cores are well tested, but you could do thumb stuff if you booted like an arm but did the rest in thumb, boot with
.globl _start
_start:
b reset
b hang
b hang
b hang
reset:
mov sp,#0x20000
bl notmain
hang:
b hang
the machine
versatilepb ARM Versatile/PB (ARM926EJ-S)
has its uart at 0x101f1000, so
for(ra=0;;ra++)
{
ra&=7;
PUT32(0x101f1000,0x30+ra);
}
can build your app with
arm-none-eabi-gcc -Wall -O2 -nostdlib -nostartfiles -ffreestanding -mcpu=arm7tdmi -mthumb -c uart01.c -o uart01.o
change your linker script to be all ram based.
MEMORY
{
ram : ORIGIN = 0x00000000, LENGTH = 32K
}
SECTIONS
{
.text : { *(.text*) } > ram
.bss : { *(.text*) } > ram
}
and then
qemu-system-arm -M versatilepb -m 128M -nographic -kernel hello.bin
(hmmm, does this load at 0x0000, or 0x8000?, shouldnt be too hard to figure out)
you can get mostly the thumb feel of a cortex-m (an m0 basically not an m3, you can find an armv7-a machine you can probably run thumb2 built code (still boots like an arm not a cortex-m)). for example
realview-pb-a8 ARM RealView Platform Baseboard for Cortex-A8
Can probably use newlib almost as is, need to change the crt0.s or whatever it is called these days to boot like an arm not a cortex-m. The rest can build using armv7m and in theory will work.
And or start with the stellaris and just make your own hw support for whatever your real target is and fix the cortex-m3 core if/when you find problems.

Global constructor call not in .init_array section

I'm trying to add global constructor support on an embedded target (ARM Cortex-M3).
Lets say I've the following code:
class foobar
{
int i;
public:
foobar()
{
i = 100;
}
void inc()
{
i++;
}
};
foobar foo;
int main()
{
foo.inc();
for (;;);
}
I compile it like this:
arm-none-eabi-g++ -O0 -gdwarf-2 -mcpu=cortex-m3 -mthumb -c foo.cpp -o foo.o
When I look at the .init_array section with objdump it shows the .init_section has a zero size.
I do get an symbol named _Z41__static_initialization_and_destruction_0ii.
When I disassemble the object file I see that the global construction is done in the static_initialization_and_destruction symbol.
Why isn't a pointer added to this symbol in the .init_section?
I know it has been almost two years since this question was asked, but I just had to figure out the mechanics of bare-metal C++ initialization with GCC myself, so I thought I'd share the details here. There turns out to be a lot of out-of-date or confusing information on the web. For example, the oft-mentioned collect2 wrapper does not appear to be used for ARM ELF targets, since its arbitrary section support enables the approach described below.
First, when I compile the code above with the given command line using Sourcery CodeBench Lite 2012.09-63, I do see the correct .init_array section size of 4:
$ arm-none-eabi-objdump -h foo.o
foo.o: file format elf32-littlearm
Sections:
Idx Name Size VMA LMA File off Algn
...
13 .init_array 00000004 00000000 00000000 0000010c 2**2
CONTENTS, ALLOC, LOAD, RELOC, DATA
...
When I look at the section contents, it just contains 0:
$ arm-none-eabi-objdump -j .init_array -s foo.o
Contents of section .init_array:
0000 00000000 ....
However, there is also a relocation section that sets it correctly to _GLOBAL__sub_I_foo:
$ arm-none-eabi-objdump -x foo.o
...
RELOCATION RECORDS FOR [.init_array]:
OFFSET TYPE VALUE
00000000 R_ARM_TARGET1 _GLOBAL__sub_I_foo
In general, .init_array points to all of your _GLOBAL__sub_I_XXX initializer stubs, each of which calls its own copy of _Z41__static_initialization_and_destruction_0ii (yes, it is multiply-defined), which calls the constructor with the appropriate arguments.
Because I'm using -nostdlib in my build, I can't use CodeSourcery's __libc_init_array to execute the .init_array for me, so I need to call the static initializers myself:
extern "C"
{
extern void (**__init_array_start)();
extern void (**__init_array_end)();
inline void static_init()
{
for (void (**p)() = __init_array_start; p < __init_array_end; ++p)
(*p)();
}
}
__init_array_start and __init_array_end are defined by the linker script:
. = ALIGN(4);
.init_array :
{
__init_array_start = .;
KEEP (*(.init_array*))
__init_array_end = .;
}
This approach seems to work with both the CodeSourcery cross-compiler and native ARM GCC, e.g. in Ubuntu 12.10 for ARM. Supporting both compilers is one reason for using -nostdlib and not relying on the CodeSourcery CS3 bare-metal support.
Timmmm,
I just had the same issue on the nRF51822 and solved it by adding KEEP() around a couple lines in the stock Nordic .ld file:
KEEP(*(SORT(.init_array.*)))
KEEP(*(.init_array))
While at it, I did the same to the fini_array area too. Solved my problem and the linker can still remove other unused sections...
You have only produced an object file, due to the -c argument to gcc. To create the .init section, I believe that you need to link that .o into an actual executable or shared library. Try removing the -c argument and renaming the output file to "foo", and then check the resulting executable with the disassembler.
If you look carefully _Z41__static_initialization_and_destruction_0ii would be called inside global constructor. Which inturn would be linked in .init_array section (in arm-none-eabi- from CodeSourcery.) or some other function (__main() if you are using Linux g++). () This should be called at startup or at main().
See also this link.
I had a similar issue where my constructors were not being called (nRF51822 Cortex-M0 with GCC). The problem turned out to be due to this linker flag:
-Wl,--gc-sections
Don't ask me why! I thought it only removed dead code.

no debugging symbols found when using gdb

GNU gdb Fedora (6.8-37.el5)
Kernal 2.6.18-164.el5
I am trying to debug my application. However, everytime I pass the binary to the gdb it says:
(no debugging symbols found)
Here is the file output of the binary, and as you can see it is not stripped:
vid: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), for GNU/Linux 2.6.9, dynamically linked (uses shared libs), for GNU/Linux 2.6.9, not stripped
I am compiling with the following CFLAGS:
CFLAGS = -Wall -Wextra -ggdb -O0 -Wunreachable-code
Can anyone tell me if I am missing some simple here?
The most frequent cause of "no debugging symbols found" when -g is present is that there is some "stray" -s or -S argument somewhere on the link line.
From man ld:
-s
--strip-all
Omit all symbol information from the output file.
-S
--strip-debug
Omit debugger symbol information (but not all symbols) from the output file.
The application has to be both compiled and linked with -g option. I.e. you need to put -g in both CPPFLAGS and LDFLAGS.
Some Linux distributions don't use the gdb style debugging symbols. (IIRC they prefer dwarf2.)
In general, gcc and gdb will be in sync as to what kind of debugging symbols they use, and forcing a particular style will just cause problems; unless you know that you need something else, use just -g.
You should also try -ggdb instead of -g if you're compiling for Android!
Replace -ggdb with -g and make sure you aren't stripping the binary with the strip command.
I know this was answered a long time ago, but I've recently spent hours trying to solve a similar problem. The setup is local PC running Debian 8 using Eclipse CDT Neon.2, remote ARM7 board (Olimex) running Debian 7. Tool chain is Linaro 4.9 using gdbserver on the remote board and the Linaro GDB on the local PC. My issue was that the debug session would start and the program would execute, but breakpoints did not work and when manually paused "no source could be found" would result. My compile line options (Linaro gcc) included -ggdb -O0 as many have suggested but still the same problem. Ultimately I tried gdb proper on the remote board and it complained of no symbols. The curious thing was that 'file' reported debug not stripped on the target executable.
I ultimately solved the problem by adding -g to the linker options. I won't claim to fully understand why this helped, but I wanted to pass this on for others just in case it helps. In this case Linux did indeed need -g on the linker options.
Hope the sytem you compiled on and the system you are debugging on have the same architecture. I ran into an issue where debugging symbols of 32 bit binary refused to load up on my 64 bit machine. Switching to a 32 bit system worked for me.
Bazel can strip binaries by default without warning, if that's your build manager. I had to add --strip=never to my bazel build command to get gdb to work, --compilation_mode=dbg may also work.
$ bazel build -s :mithral_wrapped
...
#even with -s option, no '-s' was printed in gcc command
...
$ file bazel-bin/mithral_wrapped.so
../cpp/bazel-bin/mithral_wrapped.so: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, BuildID[sha1]=4528622fb089b579627507876ff14991179a1138, not stripped
$ objdump -h bazel-bin/mithral_wrapped.so | grep debug
$ bazel build -s :mithral_wrapped --strip=never
...
$ file bazel-bin/mithral_wrapped.so
bazel-bin/mithral_wrapped.so: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, BuildID[sha1]=28bd192b145477c2a7d9b058f1e722a29e92a545, not stripped
$ objdump -h bazel-bin/mithral_wrapped.so | grep debug
30 .debug_info 002c8e0e 0000000000000000 0000000000000000 0006b11e 2**0
31 .debug_abbrev 000030f6 0000000000000000 0000000000000000 00333f2c 2**0
32 .debug_loc 0013cfc3 0000000000000000 0000000000000000 00337022 2**0
33 .debug_aranges 00002950 0000000000000000 0000000000000000 00473fe5 2**0
34 .debug_ranges 00011c80 0000000000000000 0000000000000000 00476935 2**0
35 .debug_line 0001e523 0000000000000000 0000000000000000 004885b5 2**0
36 .debug_str 0033dd10 0000000000000000 0000000000000000 004a6ad8 2**0
For those that came here with this question and who are using Qt: in the release config there is a step where the binary is stripped as part of doing the make install. You can pass the configuration option CONFIG+=nostrip to tell it not to:
Instead of:
qmake <your options here, e.g. CONFIG=whatever>
you add CONFIG+=nostrip, so:
qmake <your options here, e.g. CONFIG=whatever> CONFIG+=nostrip
The solutions I've seen so far are good:
must compile with the -g debugging flag to tell the compiler to generate debugging symbols
make sure there is no stray -s in the compiler flags, which strips the output of all symbols.
Just adding on here, since the solution that worked for me wasn't listed anywhere. The order of the compiler flags matters. I was including multiple header files from many locations (-I/usr/local/include -Iutil -I. And I was compiling with all warnings on (-Wall).
The correct recipe for me was:
gcc -I/usr/local/include -Iutil -I -Wall -g -c main.c -o main.o
Notice:
include flags are at the beginning
-Wall is after include flags and before -g
-g is at the end
Any other ordering of the flags would cause no debug symbols to be generated.
I'm using gcc version 11.3.0 on Ubuntu 22.04 on WSL2.