I am currently trying to learn the ways of C and am using GCC to translate C to ARM instructions. To do so, I am attempting to draw a simple shape to the window, but am having a hard time working out how to do it without using a graphics package like . Here is what I have managed to work out so far:
My make file is pretty self-explanatory I would say.
CC=/cygdrive/c/Users/Ribbyon/Desktop/gcc-arm-none-eabi-5_3-2016q1-20160330-win32/bin/arm-none-eabi-gcc
LD=/cygdrive/c/Users/Ribbyon/Desktop/gcc-arm-none-eabi-5_3-2016q1-20160330-win32/bin/arm-none-eabi-ld.exe
AS=$(CC)
OBJCOPY=/cygdrive/c/Users/Ribbyon/Desktop/gcc-arm-none-eabi-5_3-2016q1-20160330-win32/bin/arm-none-eabi-objcopy.exe
QEMU=/cygdrive/c/Users/Ribbyon/Desktop/qemu/qemu-system-arm.exe
#these should be cross-platform...
CC+= -Wall -c -mcpu=arm926ej-s -marm -Werror
LD+=-Map kernelmap.txt -T linkerscript.txt
AS+= -c -x assembler-with-cpp -mcpu=arm926ej-s
QEMUARGS=-machine integratorcp -kernel kernel.bin -serial stdio
DISPLAY?=:0
export DISPLAY
SDL_STDIO_REDIRECT=no
export SDL_STDIO_REDIRECT
all:
$(AS) kernelasm.s
$(CC) kernelc.c
$(CC) console.c
$(LD) -o kernel.tmp kernelasm.o kernelc.o console.o
$(OBJCOPY) -Obinary kernel.tmp kernel.bin
$(QEMU) $(QEMUARGS) kernel.bin
clean:
-/bin/rm *.o *.exe *.bin *.img *.tmp
Linkerscript to put it together:
ENTRY (_start)
SECTIONS {
/* The kernel will be loaded at this address in RAM.
The dot (.) means "the current location" */
. = 0x10000 ;
.text : {
/* stext = start of text (read-only) section */
stext = .;
/* .text = program code. rodata and rdata = read-only data */
*(.text)
*(.rodata)
*(.rdata)
*(.rdata$zzz)
/* etext = end of text section */
etext = .;
/* pad to a 4K boundary */
. = ALIGN( ABSOLUTE(.) , 0x1000 );
/* start of data (writable) section */
_sdata = .;
sdata = .;
*(.data)
_edata = .;
edata = .;
/* end of data section */
/* bss: Block Started by Symbol: Uninitialized data */
_sbss = . ;
sbss = . ;
*(COMMON)
*(.bss)
_ebss = . ;
ebss = . ;
}
/DISCARD/ : {
*(.eh_frame)
*(.comment)
}
}
Kernel Map (for completeness):
Discarded input sections
.comment 0x0000000000000000 0x33 kernelc.o
.comment 0x0000000000000000 0x33 console.o
Memory Configuration
Name Origin Length Attributes
*default* 0x0000000000000000 0xffffffffffffffff
Linker script and memory map
0x0000000000010000 . = 0x10000
.text 0x0000000000010000 0x2000
0x0000000000010000 stext = .
*(.text)
.text 0x0000000000010000 0x10 kernelasm.o
.text 0x0000000000010010 0x14 kernelc.o
0x0000000000010010 kmain
.text 0x0000000000010024 0x0 console.o
*(.rodata)
*(.rdata)
*(.rdata$zzz)
0x0000000000010024 etext = .
0x0000000000011000 . = ALIGN (ABSOLUTE (.), 0x1000)
*fill* 0x0000000000010024 0xfdc
0x0000000000011000 _sdata = .
0x0000000000011000 sdata = .
*(.data)
.data 0x0000000000011000 0x1000 kernelasm.o
0x0000000000012000 stack
.data 0x0000000000012000 0x0 kernelc.o
.data 0x0000000000012000 0x0 console.o
0x0000000000012000 _edata = .
0x0000000000012000 edata = .
0x0000000000012000 _sbss = .
0x0000000000012000 sbss = .
*(COMMON)
*(.bss)
.bss 0x0000000000012000 0x0 kernelasm.o
.bss 0x0000000000012000 0x0 kernelc.o
.bss 0x0000000000012000 0x0 console.o
0x0000000000012000 _ebss = .
0x0000000000012000 ebss = .
.glue_7 0x0000000000012000 0x0
.glue_7 0x0000000000012000 0x0 linker stubs
.glue_7t 0x0000000000012000 0x0
.glue_7t 0x0000000000012000 0x0 linker stubs
.vfp11_veneer 0x0000000000012000 0x0
.vfp11_veneer 0x0000000000012000 0x0 linker stubs
.v4_bx 0x0000000000012000 0x0
.v4_bx 0x0000000000012000 0x0 linker stubs
.iplt 0x0000000000012000 0x0
.iplt 0x0000000000012000 0x0 kernelasm.o
.igot.plt 0x0000000000012000 0x0
.igot.plt 0x0000000000012000 0x0 kernelasm.o
.rel.dyn 0x0000000000012000 0x0
.rel.iplt 0x0000000000012000 0x0 kernelasm.o
/DISCARD/
*(.eh_frame)
*(.comment)
LOAD kernelasm.o
LOAD kernelc.o
LOAD console.o
OUTPUT(kernel.tmp elf32-littlearm)
.ARM.attributes
0x0000000000000000 0x32
.ARM.attributes
0x0000000000000000 0x24 kernelasm.o
.ARM.attributes
0x0000000000000024 0x36 kernelc.o
.ARM.attributes
0x000000000000005a 0x36 console.o
.note.GNU-stack
0x0000000000000000 0x0
.note.GNU-stack
0x0000000000000000 0x0 kernelc.o
.note.GNU-stack
0x0000000000000000 0x0 console.o
Kernelasm:
ldr sp,=stack
b kmain
forever:
b forever
.section .data
.global stack
.rept 1024
.word 0
.end
stack:
Now, I know in C, I could do something like:
#include<graphics.h>
#include<conio.h>
main()
{
int gd = DETECT, gm;
initgraph(&gd, &gm, "C:\\TC\\BGI");
setcolor(BLUE);
rectangle(50,50,100,100);
getch();
closegraph();
return 0;
}
But since I am working with ARM, it complicates matters. As such, I am thinking I need a kernel.
The actual file that does the work:
#define blue COLOR16(0,0,255)
void console_init(){
}
void setpixel(x, y, blue){
}
The kernel I am using it in:
#include "console.h"
void kmain(){
console_init();
//draw using setpixel
while(1){
}
}
I wrote up the skeleton of it, but I am not sure where to go from here. I believe I need to isolate blue from the RBG band and display it, but I am having a hard time figuring out how to go about utilizing the logic I used in the C example for the ARM.
I think I might need to define width and height of the screen for the placement of the rectangle:
#define WIDTH 800
#define HEIGHT 600
As well as a framebuffer to do the actual communication of where to put the rectangle on the screen:
#define framebuffer ((volatile unsigned short*) (((0x07ffffff - WIDTH*HEIGHT*2))&~0xf))
And a way to assign the blue to the screen:
framebuffer[ HEIGHT/2 * WIDTH + WIDTH/2 ] = #0000FF
Could I use something like a script to grab the colors?
((b >> 3) | (r << 8) | (g << 3))
Any insight would be very helpful in getting the hang of this.
Related
I am developing a freestanding application for an ARM Cortex-M microcontroller and while researching the structure of an S-Record file I found that I have some kind of misunderstanding in how the addresses are represented in the S-Record format.
I have a variable defined in my source code like so:
uint32_t g_ip_address = IP_ADDRESS(10, 1, 0, 56); // in LE: 0x3800010A
When I run objdump I see that the variable ends up in the .data section at address 0x1ffe01c4:
$ arm-none-eabi-objdump -t application.elf | grep g_ip_address
1ffe01c4 g O .data 00000004 g_ip_address
This makes sense, given that the memory section of my linker script looks like this and .data is going to RAM:
MEMORY
{
FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x0200000 /* 2M */
RAM (rwx) : ORIGIN = 0x1FFE0000, LENGTH = 0x00A0000 /* 640K */
}
However, when I check through the srec file, I'm finding that the address for the record is not 0x1FFE0000. It's 0x0005F570, which seems to put it in the FLASH section (spaces added for clarity).
S315 0005F570 00000000 3800010A 000010180000000014
Is there an implicit offset encoded in a different record entry? How does objcopy get this new address? If this value is being encoded into a function in some way (some pre-main initialization of variables perhaps)?
Ultimately, my goal is to be able to parse the srec file and patch the IP address value to create a new srec file. Is the idiomatic way of doing something like this simply to create a struct that hardcodes some leading magic number sequence that can be detected in the file?
flash.s
.cpu cortex-m0
.thumb
.word 0x00002000
.word reset
.thumb_func
reset:
b reset
.data
.word 0x11223344
.bss
.word 0x00000000
.word 0x00000000
flash.ld
MEMORY
{
rom : ORIGIN = 0x08000000, LENGTH = 0x1000
ram : ORIGIN = 0x20000000, LENGTH = 0x1000
}
SECTIONS
{
.text : { *(.text*) } > rom
.bss : { *(.bss*) } > ram AT > rom
.data : { *(.data*) } > ram AT > rom
}
build it
arm-none-eabi-as --warn --fatal-warnings -mcpu=cortex-m0 flash.s -o flash.o
arm-none-eabi-ld -nostdlib -nostartfiles -T flash.ld flash.o -o so.elf
arm-none-eabi-objdump -D so.elf > so.list
arm-none-eabi-objcopy --srec-forceS3 so.elf -O srec so.srec
arm-none-eabi-objcopy -O binary so.elf so.bin
cat so.list
08000000 <reset-0x8>:
8000000: 00002000 andeq r2, r0, r0
8000004: 08000009 stmdaeq r0, {r0, r3}
08000008 <reset>:
8000008: e7fe b.n 8000008 <reset>
Disassembly of section .bss:
20000000 <.bss>:
...
Disassembly of section .data:
20000008 <.data>:
20000008: 11223344 ; <UNDEFINED> instruction: 0x11223344
cat so.srec
S00A0000736F2E7372656338
S30F080000000020000009000008FEE7D2
S3090800000A443322113A
S70508000000F2
arm-none-eabi-readelf -l so.elf
Elf file type is EXEC (Executable file)
Entry point 0x8000000
There are 3 program headers, starting at offset 52
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x000094 0x08000000 0x08000000 0x0000a 0x0000a R E 0x2
LOAD 0x000000 0x20000000 0x0800000a 0x00000 0x00008 RW 0x1
LOAD 0x00009e 0x20000008 0x0800000a 0x00004 0x00004 RW 0x1
Section to Segment mapping:
Segment Sections...
00 .text
01 .bss
02 .data
hexdump -C so.bin
00000000 00 20 00 00 09 00 00 08 fe e7 44 33 22 11 |. ........D3".|
0000000e
bss is not normally exposed as is, you complicate your linker script to add beginning and end points so you can then zero that range in your bootstrap. For .data you can clearly see what is going on with the standard binutils tools.
You have not provided enough of your code (and linker script), nor a minimal example that demonstrates the problem, so this is about as far as this can go.
I'm trying to make .rodata section location stay with its associated function memory location. I'm using the GNU compiler/linker, bare metal, plain-jane c, with an STM32L4A6 micro-controller.
I have a custom board using an STM32L4A6 controller with 1Meg of Flash divided into 512 - 2K pages. Each page can be individually erased and programmed from a function running in RAM. I'd like to take advantage of this fine-grained flash organization to create an embedded firmware application that can be updated on-the-fly by modifying or adding individual functions in the code. My scheme is to dedicate a separate page of flash for each function that might ever need to be changed or created. It's extremely wasteful of flash but I'll never use more than ~10% of it so I can afford to to be wasteful. I've made some progress on this and can now make significant changes to the operation of my application by uploading very small bits of binary code. These "Patches" often do not even require a system reboot.
The problem I'm having is that when a function contains any sort of constant data, such as a literal string, it winds up in the .rodata section. I need the rodata for a given function to stay in the same area as the function that created it. Does anyone know how I might be able to force the .rodata that is created in a function to stay attached to that same function in flash? Like maybe the .rodata from that function could be positioned immediately following the function itself? Maybe I need to use -ffunction-sections or something like that? I've been through the various linker manuals but still can't figure how to do this. Below is the start of my linker script. I don't know how to include function .rodata in the individual page sections.
Example function:
#define P018 __attribute__((long_call, section(".txt018")))
P018 int Function18(int A, int B){int C = A*B; return C;}
A better example that shows my problem would be the following:
#define P152 __attribute__((long_call, section(".txt152")))
P152 void TestFunc(int A){printf("%d Squared Is: %d\r\n",A,A*A);}
In this case, the binary equivalent of "%d Squared Is: %d\r\n" can be found in .rodata with all of the other literal strings in my program. I would prefer it to be located in section .txt152 .
Linker Script snippet (Mostly generated from a simple console program.)
MEMORY
{
p000 (rx) : ORIGIN = 0x08000000, LENGTH = 0x8000
p016 (rx) : ORIGIN = 0x08008000, LENGTH = 0x800
p017 (rx) : ORIGIN = 0x08008800, LENGTH = 0x800
p018 (rx) : ORIGIN = 0x08009000, LENGTH = 0x800
.
.
.
p509 (rx) : ORIGIN = 0x080fe800, LENGTH = 0x800
p510 (rx) : ORIGIN = 0x080ff000, LENGTH = 0x800
p511 (rx) : ORIGIN = 0x080ff800, LENGTH = 0x800
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 256K
ram2 (rw) : ORIGIN = 0x10000000, LENGTH = 64K
}
SECTIONS
{
.vectors :
{
KEEP(*(.isr_vector .isr_vector.*))
} > p000
.txt016 : { *(.txt016) } > p016 /* first usable 2k page following 32k p000 */
.txt017 : { *(.txt017) } > p017
.txt018 : { *(.txt018) } > p018
.
.
.
.txt509 : { *(.txt509) } > p509
.txt510 : { *(.txt510) } > p510
.txt511 : { *(.txt511) } > p511
.text :
{
*(.text .text.* .gnu.linkonce.t.*)
*(.glue_7t) *(.glue_7)
*(.rodata .rodata* .gnu.linkonce.r.*)
} > p000
.
.
.
In case anyone's interested, here's my RAM code for doing the erase/program operation
__attribute__((long_call, section(".data")))
void CopyPatch
(
unsigned short Page,
unsigned int NumberOfBytesToFlash,
unsigned char *PatchBuf
)
{
unsigned int i;
unsigned long long int *Flash;
__ASM volatile ("cpsid i" : : : "memory"); //disable interrupts
Flash = (unsigned long long int *)(FLASH_BASE + Page*2048); //set flash memory pointer to Page address
GPIOE->BSRR = GPIO_BSRR_BS_1; //make PE1(LED) high
FLASH->KEYR = 0x45670123; //unlock the flash
FLASH->KEYR = 0xCDEF89AB; //unlock the flash
while(FLASH->SR & FLASH_SR_BSY){} //wait while flash memory operation is in progress
FLASH->CR = FLASH_CR_PER | (Page << 3); //set Page erase bit and the Page to erase
FLASH->CR |= FLASH_CR_STRT; //start erase of Page
while(FLASH->SR & FLASH_SR_BSY){} //wait while Flash memory operation is in progress
FLASH->CR = FLASH_CR_PG; //set flash programming bit
for(i=0;i<(NumberOfBytesToFlash/8+1);i++)
{
Flash[i] = ((unsigned long long int *)PatchBuf)[i]; //copy RAM to FLASH, 8 bytes at a time
while(FLASH->SR & FLASH_SR_BSY){} //wait while flash memory operation is in progress
}
FLASH->CR = FLASH_CR_LOCK; //lock the flash
GPIOE->BSRR = GPIO_BSRR_BR_1; //make PE1(LED) low
__ASM volatile ("cpsie i" : : : "memory"); //enable interrupts
}
Okay ... Sorry for the delay, but I had to think about this a bit ...
I'm not sure you can do this [completely] with a linker script alone. It might be possible, but I think there's an easier/surer way [with a bit of extra prep]
A method I've used before is to compile with -S to get a .s file. Change/mangle that. And, then, compile the modified .s
Note that you may have some trouble with a global like:
int B;
This will go to a .comm section in the asm source. This may not be ideal.
For initialized data:
int B = 23;
You may want to add a section attribute to force it to a special section. Otherwise, it will end up in a .data section
So, I might avoid .comm and/or .bss sections in favor of always using initialized data. That's because .comm has the same issue as .rodata (i.e. it ends up as one big blob).
Anyway, below is a step by step process.
I put the section name macros in a common file (e.g.) sctname.h:
#define _SCTJOIN(_pre,_sct) _pre #_sct
#define _TXTSCT(_sct) __attribute__((section(_SCTJOIN(".txt",_sct))))
#define _DATSCT(_sct) __attribute__((section(_SCTJOIN(".dat",_sct))))
#ifdef SCTNO
#define TXTSCT _TXTSCT(SCTNO)
#define DATSCT _DATSCT(SCTNO)
#endif
Here's a slightly modified version of your .c file (e.g. module.c):
#include <stdio.h>
#ifndef SCTNO
#define SCTNO 152
#endif
#include "sctname.h"
int B DATSCT = 23;
TXTSCT void
TestFunc(int A)
{
printf("%d Squared Is: %d\r\n", A, A * A * B);
}
To create the .s file, we do:
cc -S -Wall -Werror -O2 module.c
The actual section name/number can be specified on the command line:
cc -S -Wall -Werror -O2 -DSCTNO=152 module.c
This gives us a module.s:
.file "module.c"
.text
.section .rodata.str1.1,"aMS",#progbits,1
.LC0:
.string "%d Squared Is: %d\r\n"
.section .txt152,"ax",#progbits
.p2align 4,,15
.globl TestFunc
.type TestFunc, #function
TestFunc:
.LFB11:
.cfi_startproc
movl %edi, %edx
movl %edi, %esi
xorl %eax, %eax
imull %edi, %edx
movl $.LC0, %edi
imull B(%rip), %edx
jmp printf
.cfi_endproc
.LFE11:
.size TestFunc, .-TestFunc
.globl B
.section .dat152,"aw"
.align 4
.type B, #object
.size B, 4
B:
.long 23
.ident "GCC: (GNU) 8.3.1 20190223 (Red Hat 8.3.1-2)"
.section .note.GNU-stack,"",#progbits
Now, we have to read in the .s and modify it. I've created a perl script that does this (e.g. rofix):
#!/usr/bin/perl
master(#ARGV);
exit(0);
sub master
{
my(#argv) = #_;
$root = shift(#argv);
$root =~ s/[.][^.]+$//;
$sfile = "$root.s";
$ofile = "$root.TMP";
open($xfsrc,"<$sfile") or
die("rofix: unable to open '$sfile' -- $!\n");
open($xfdst,">$ofile") or
die("rofix: unable to open '$sfile' -- $!\n");
$txtpre = "^[.]txt";
$datpre = "^[.]dat";
# find the text and data sections
seek($xfsrc,0,0);
while ($bf = <$xfsrc>) {
chomp($bf);
if ($bf =~ /^\s*[.]section\s(\S+)/) {
$sctcur = $1;
sctget($txtpre);
sctget($datpre);
}
}
# modify the data sections
seek($xfsrc,0,0);
while ($bf = <$xfsrc>) {
chomp($bf);
if ($bf =~ /^\s*[.]section\s(\S+)/) {
$sctcur = $1;
sctfix();
print($xfdst $bf,"\n");
next;
}
print($xfdst $bf,"\n");
}
close($xfsrc);
close($xfdst);
system("diff -u $sfile $ofile");
rename($ofile,$sfile) or
die("rofix: unable to rename '$ofile' to '$sfile' -- $!\n");
}
sub sctget
{
my($pre) = #_;
my($sctname,#sct);
{
last unless (defined($pre));
#sct = split(",",$sctcur);
$sctname = shift(#sct);
last unless ($sctname =~ /$pre/);
printf("sctget: FOUND %s\n",$sctname);
$sct_lookup{$pre} = $sctname;
}
}
sub sctfix
{
my($sctname,#sct);
my($sctnew);
{
last unless ($sctcur =~ /^[.]rodata/);
$sctnew = $sct_lookup{$txtpre};
last unless (defined($sctnew));
#sct = split(",",$sctcur);
$sctname = shift(#sct);
$sctname .= $sctnew;
unshift(#sct,$sctname);
$sctname = join(",",#sct);
$bf = sprintf("\t.section\t%s",$sctname);
}
}
The difference between the old and new module.s is:
sctget: FOUND .txt152
sctget: FOUND .dat152
--- module.s 2020-04-20 19:02:23.777302484 -0400
+++ module.TMP 2020-04-20 19:06:33.631926065 -0400
## -1,6 +1,6 ##
.file "module.c"
.text
- .section .rodata.str1.1,"aMS",#progbits,1
+ .section .rodata.txt152,"aMS",#progbits,1
.LC0:
.string "%d Squared Is: %d\r\n"
.section .txt152,"ax",#progbits
So, now, create the .o with:
cc -c module.s
For a makefile, it might be something like [with some wildcards]:
module.o: module.c
cc -S -Wall -Werror -O2 module.c
./rofix module.s
cc -c module.s
Now, you can add appropriate placements in your linker script for [your original section] .txt152 and the new .rodata.txt152.
And, the initialized data section .dat152
Note that the actual naming conventions are arbitrary. If you want to change them, just modify rofix [and the linker script] appropriately
Here's the readelf -a output for module.o:
Note that there's also a .rela.txt152 section!?!?
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: REL (Relocatable file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x0
Start of program headers: 0 (bytes into file)
Start of section headers: 808 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 0 (bytes)
Number of program headers: 0
Size of section headers: 64 (bytes)
Number of section headers: 15
Section header string table index: 14
Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[ 0] NULL 0000000000000000 00000000
0000000000000000 0000000000000000 0 0 0
[ 1] .text PROGBITS 0000000000000000 00000040
0000000000000000 0000000000000000 AX 0 0 1
[ 2] .data PROGBITS 0000000000000000 00000040
0000000000000000 0000000000000000 WA 0 0 1
[ 3] .bss NOBITS 0000000000000000 00000040
0000000000000000 0000000000000000 WA 0 0 1
[ 4] .rodata.txt152 PROGBITS 0000000000000000 00000040
0000000000000014 0000000000000001 AMS 0 0 1
[ 5] .txt152 PROGBITS 0000000000000000 00000060
000000000000001a 0000000000000000 AX 0 0 16
[ 6] .rela.txt152 RELA 0000000000000000 00000250
0000000000000048 0000000000000018 I 12 5 8
[ 7] .dat152 PROGBITS 0000000000000000 0000007c
0000000000000004 0000000000000000 WA 0 0 4
[ 8] .comment PROGBITS 0000000000000000 00000080
000000000000002d 0000000000000001 MS 0 0 1
[ 9] .note.GNU-stack PROGBITS 0000000000000000 000000ad
0000000000000000 0000000000000000 0 0 1
[10] .eh_frame PROGBITS 0000000000000000 000000b0
0000000000000030 0000000000000000 A 0 0 8
[11] .rela.eh_frame RELA 0000000000000000 00000298
0000000000000018 0000000000000018 I 12 10 8
[12] .symtab SYMTAB 0000000000000000 000000e0
0000000000000150 0000000000000018 13 11 8
[13] .strtab STRTAB 0000000000000000 00000230
000000000000001c 0000000000000000 0 0 1
[14] .shstrtab STRTAB 0000000000000000 000002b0
0000000000000078 0000000000000000 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
L (link order), O (extra OS processing required), G (group), T (TLS),
C (compressed), x (unknown), o (OS specific), E (exclude),
l (large), p (processor specific)
There are no section groups in this file.
There are no program headers in this file.
There is no dynamic section in this file.
Relocation section '.rela.txt152' at offset 0x250 contains 3 entries:
Offset Info Type Sym. Value Sym. Name + Addend
00000000000a 00050000000a R_X86_64_32 0000000000000000 .rodata.txt152 + 0
000000000011 000c00000002 R_X86_64_PC32 0000000000000000 B - 4
000000000016 000d00000004 R_X86_64_PLT32 0000000000000000 printf - 4
Relocation section '.rela.eh_frame' at offset 0x298 contains 1 entry:
Offset Info Type Sym. Value Sym. Name + Addend
000000000020 000600000002 R_X86_64_PC32 0000000000000000 .txt152 + 0
The decoding of unwind sections for machine type Advanced Micro Devices X86-64 is not currently supported.
Symbol table '.symtab' contains 14 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FILE LOCAL DEFAULT ABS module.c
2: 0000000000000000 0 SECTION LOCAL DEFAULT 1
3: 0000000000000000 0 SECTION LOCAL DEFAULT 2
4: 0000000000000000 0 SECTION LOCAL DEFAULT 3
5: 0000000000000000 0 SECTION LOCAL DEFAULT 4
6: 0000000000000000 0 SECTION LOCAL DEFAULT 5
7: 0000000000000000 0 SECTION LOCAL DEFAULT 7
8: 0000000000000000 0 SECTION LOCAL DEFAULT 9
9: 0000000000000000 0 SECTION LOCAL DEFAULT 10
10: 0000000000000000 0 SECTION LOCAL DEFAULT 8
11: 0000000000000000 26 FUNC GLOBAL DEFAULT 5 TestFunc
12: 0000000000000000 4 OBJECT GLOBAL DEFAULT 7 B
13: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND printf
No version information found in this file.
I wrote a mini-boot loader and a simple kernel that print a string. I followed step-by-step this playlist(First 3 videos to be precise!). Anyway, when I boot my virtual machine(with my ISO) I get those messages:
"error: no multiboot header found."
"error: you need to load the kernel first."
I tried to modify some section of the assembly code in the boot file but without success.
Here is the code:
boot.s
.set MAGIC, 0x1badb002
.set FLAGS, (1<<0 | 1<<1)
.set CHECKSUM, -(MAGIC + FLAGS)
.section .multiboot
.long MAGIC
.long FLAGS
.long CHECKSUM
.section .text
.extern kernel_main
.extern call_constructors
.global loader
loader:
mov $kernel_stack, %esp
call call_constructors
push %eax
push %ebx
call kernel_main
_stop:
cli
hlt
jmp _stop
.section .bss
.space 2*1024*1024 ;#2 MiB
kernel_stack:
kernel.c
#include <sys/types.h>
void printf(char * str)
{
uint16_t * VideoMemory = (uint16_t *)0xb8000;
for(int32_t i = 0; str[i] != '\0'; i++)
VideoMemory[i] = (VideoMemory[i] & 0xFF00) | str[i];
}
typedef void (*constructor)();
extern "C" constructor start_ctors;
extern "C" constructor end_ctors;
extern "C" void call_constructors()
{
for(constructor* i = &start_ctors; i != &end_ctors; i++)
(*i)();
}
extern "C" void kernel_main(const void * multiboot_structure, uint32_t magic_number)
{
printf("Denos - Version: 0.0.1a");
for(;;);
}
NOTE: sys/types.h comes from my lib. which is included as argument in gcc.
linker.ld
ENTRY(loader)
OUTPUT_FORMAT(elf32-i386)
OUTPUT_ARCH(i386:i386)
SECTIONS
{
. = 0x0100000;
.text :
{
*(.multiboot)
*(.text*)
*(.rodata)
}
.data :
{
start_ctors = .;
KEEP(*( .init_array ));
KEEP(*(SORT_BY_INIT_PRIORITY( .init_array.* )));
end_ctors = .;
*(.data)
}
.bss :
{
*(.bss)
}
/DISCARD/ :
{
*(.fini_array*)
*(.comment)
}
}
Makefile
GPPPARAMS = -m32 -fno-use-cxa-atexit -nostdlib -fno-builtin -fno-rtti -fno-exceptions -fno-leading-underscore -I ../include/
ASPARAMS = --32
objects = boot.o kernel.o
run: denos.iso
(killall VirtualBox && sleep 1) || true
VirtualBox --startvm 'denos' &
%.o: %.c
gcc $(GPPPARAMS) -o $# -c $<
%.o: %.s
as $(ASPARAMS) -o $# $<
kernel.bin : linker.ld $(objects)
ld $(LDPARAMS) -T $< -o $# $(objects)
install: kernel.bin
sudo cp $< ./boot/kernel.bin
denos.iso: kernel.bin
mkdir iso
mkdir iso/boot
mkdir iso/boot/grub
cp kernel.bin iso/boot/kernel.bin
echo 'set timeout=0' > iso/boot/grub/grub.cfg
echo 'set default=0' >> iso/boot/grub/grub.cfg
echo '' >> iso/boot/grub/grub.cfg
echo 'menuentry "Denos" {' >> iso/boot/grub/grub.cfg
echo ' multiboot /boot/kernel.bin' >> iso/boot/grub/grub.cfg
echo ' boot' >> iso/boot/grub/grub.cfg
echo '}' >> iso/boot/grub/grub.cfg
grub-mkrescue --output=denos.iso iso
rm -rf iso
mv -f denos.iso /home/data/libvirt_iso/
objdump -x kernel.bin(Requested)
kernel.bin: file format elf32-i386
kernel.bin
architecture: i386, flags 0x00000112:
EXEC_P, HAS_SYMS, D_PAGED
start address 0x0010000c
Program Header:
LOAD off 0x00000000 vaddr 0x00000000 paddr 0x00000000 align 2**21
filesz 0x001001ac memsz 0x003001ac flags rwx
STACK off 0x00000000 vaddr 0x00000000 paddr 0x00000000 align 2**4
filesz 0x00000000 memsz 0x00000000 flags rwx
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 00000100 00100000 00100000 00100000 2**0
CONTENTS, ALLOC, LOAD, READONLY, CODE
1 .eh_frame 000000a0 00100100 00100100 00100100 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
2 .got.plt 0000000c 001001a0 001001a0 001001a0 2**2
CONTENTS, ALLOC, LOAD, DATA
3 .bss 00200000 001001ac 001001ac 001001ac 2**0
ALLOC
SYMBOL TABLE:
00100000 l d .text 00000000 .text
00100100 l d .eh_frame 00000000 .eh_frame
001001a0 l d .got.plt 00000000 .got.plt
001001ac l d .bss 00000000 .bss
00000000 l df *ABS* 00000000 boot.o
1badb002 l *ABS* 00000000 MAGIC
00000003 l *ABS* 00000000 FLAGS
e4524ffb l *ABS* 00000000 CHECKSUM
003001ac l .bss 00000000 kernel_stack
0010001d l .text 00000000 _stop
00000000 l df *ABS* 00000000 kernel.c
00000000 l df *ABS* 00000000
001001a0 l O .got.plt 00000000 _GLOBAL_OFFSET_TABLE_
001001a0 g .got.plt 00000000 start_ctors
001000e0 g F .text 00000000 .hidden __x86.get_pc_thunk.ax
001000c2 g F .text 0000001e kernel_main
001000e4 g F .text 00000000 .hidden __x86.get_pc_thunk.bx
001001a0 g .got.plt 00000000 end_ctors
00100088 g F .text 0000003a call_constructors
00100021 g F .text 00000067 _Z6printfPc
0010000c g .text 00000000 loader
I'm so sorry I wasted someone times. I checked 'Makefile' file and I figured out that I was missing 'LDPARAMS = -melf_i386'. Now it boot and print
Thanks anyway.
I have a very small bootloader sitting in front of the main firmware running on a custom-designed board based around the STM32F405VGT chip. It has a fairly minimally modified startup.s and linker files for both applications. The primary application runs fine when loaded into the root of the FLASH memory, but does not launch from the bootloader.
When stepping through the code, as soon as it tries to launch the app, the program ends up in the WWDG_IRQHandler, which is aliased to the Default_Handler and just sits and spins in the infinite loop (WWDG is disabled for the bootloader).
Bootloader Code:
uint32_t addr = 0x08010000;
/* Get the application stack pointer (First entry in the application vector table) */
uint32_t appStack = (uint32_t) *((__IO uint32_t*) addr);
/* Get the application entry point (Second entry in the application vector table) */
ApplicationEntryPoint entryPoint = (ApplicationEntryPoint)*((__IO uint32_t*)(addr + sizeof(uint32_t)));
/* would expect the value of entryPoint to be 0x802bc9c based on the values in the .map file as well as the actual values downloaded from the image using openocd. Instead, it comes back as 0x802bc9d, not sure if this is related to THUMB code */
/* Reconfigure vector table offset register to match the application location */
SCB->VTOR = addr;
/* Set the application stack pointer */
__set_MSP(appStack);
/* Start the application */
entryPoint();
Here is the .ld file for the application:
/* Include memory map */
/* Uncomment this section to use the real memory map */
MEMORY
{
BOOTLOADER (rx) : ORIGIN = 0x08000000, LENGTH = 32K
USER_PROPS (rw) : ORIGIN = 0x08008000, LENGTH = 16K
SYS_PROPS (r) : ORIGIN = 0x0800C000, LENGTH = 16K
APP_CODE (rx) : ORIGIN = 0x08010000, LENGTH = 448K
SWAP (rx) : ORIGIN = 0x08070000, LENGTH = 384K
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
BOOT_RAM (xrw) : ORIGIN = 0x2001E000, LENGTH = 8K
CCMRAM (rw) : ORIGIN = 0x10000000, LENGTH = 64K
}
/* Uncomment this section to load directly into root memory */
/*
MEMORY
{
APP_CODE (rx) : ORIGIN = 0x08000000, LENGTH = 1024K
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
MEMORY_B1 (rx) : ORIGIN = 0x60000000, LENGTH = 0K
CCMRAM (rw) : ORIGIN = 0x10000000, LENGTH = 64K
}
*/
/* Highest address of the user mode stack */
_estack = 0x20020000; /* end of 128K RAM */
/* Entry Point */
ENTRY(Reset_Handler)
/* Generate a link error if heap and stack don't fit into RAM */
_Min_Heap_Size = 0x000; /* required amount of heap (none) */
_Min_Stack_Size = 0x400; /* required amount of stack */
SECTIONS
{
/* The startup code goes first into EEPROM */
.isr_vector :
{
. = ALIGN(4);
KEEP(*(.isr_vector)) /* Startup code */
. = ALIGN(4);
} >APP_CODE
/* The program code and other data goes into EEPROM */
.text :
{
. = ALIGN(4);
*(.text) /* .text sections (code) */
*(.text*) /* .text* sections (code) */
*(.glue_7) /* glue arm to thumb code */
*(.glue_7t) /* glue thumb to arm code */
*(.eh_frame)
KEEP (*(.init))
KEEP (*(.fini))
. = ALIGN(4);
_etext = .; /* define a global symbols at end of code */
} >APP_CODE
/* Constant data goes into EEPROM */
.rodata :
{
. = ALIGN(4);
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
. = ALIGN(4);
} >APP_CODE
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array*))
PROVIDE_HIDDEN (__preinit_array_end = .);
} >APP_CODE
.init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array*))
PROVIDE_HIDDEN (__init_array_end = .);
} >APP_CODE
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array*))
PROVIDE_HIDDEN (__fini_array_end = .);
} >APP_CODE
/* used by the startup to initialize data */
_sidata = LOADADDR(.data);
/* Initialized data sections goes into RAM, load LMA copy after code */
.data :
{
. = ALIGN(4);
_sdata = .; /* create a global symbol at data start */
*(.data) /* .data sections */
*(.data*) /* .data* sections */
. = ALIGN(4);
_edata = .; /* define a global symbol at data end */
} >RAM AT> APP_CODE
/* Uninitialized data section */
. = ALIGN(4);
.bss :
{
/* This is used by the startup in order to initialize the .bss secion */
_sbss = .; /* define a global symbol at bss start */
__bss_start__ = _sbss;
*(.bss)
*(.bss*)
*(COMMON)
. = ALIGN(4);
_ebss = .; /* define a global symbol at bss end */
__bss_end__ = _ebss;
} >RAM
/* User_heap_stack section, used to check that there is enough RAM left */
._user_heap_stack :
{
. = ALIGN(8);
PROVIDE ( end = . );
PROVIDE ( _end = . );
. = . + _Min_Heap_Size;
. = . + _Min_Stack_Size;
. = ALIGN(8);
} >RAM
/* Remove information from the standard libraries */
/DISCARD/ :
{
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}
.ARM.attributes 0 : { *(.ARM.attributes) }
}
The bootloader .ld is identical, except all references to APP_CODE are replaced with BOOTLOADER
Here is the startup.s file for the bootloader. The startup.s file for the application is identical, except Boot_Reset_Handler is called Reset_Handler instead :
.syntax unified
.cpu cortex-m4
.fpu softvfp
.thumb
.global g_pfnVectors
.global Default_Handler
/* start address for the initialization values of the .data section.
defined in linker script */
.word _sidata
/* start address for the .data section. defined in linker script */
.word _sdata
/* end address for the .data section. defined in linker script */
.word _edata
/* start address for the .bss section. defined in linker script */
.word _sbss
/* end address for the .bss section. defined in linker script */
.word _ebss
/* stack used for SystemInit_ExtMemCtl; always internal RAM used */
/**
* #brief This is the code that gets called when the processor first
* starts execution following a reset event. Only the absolutely
* necessary set is performed, after which the application
* supplied main() routine is called.
* #param None
* #retval : None
*/
.section .text.Boot_Reset_Handler
.weak Boot_Reset_Handler
.type Boot_Reset_Handler, %function
Boot_Reset_Handler:
ldr sp, =_estack /* set stack pointer */
/* Copy the data segment initializers from flash to SRAM */
movs r1, #0
b LoopCopyDataInit
CopyDataInit:
ldr r3, =_sidata
ldr r3, [r3, r1]
str r3, [r0, r1]
adds r1, r1, #4
LoopCopyDataInit:
ldr r0, =_sdata
ldr r3, =_edata
adds r2, r0, r1
cmp r2, r3
bcc CopyDataInit
ldr r2, =_sbss
b LoopFillZerobss
/* Zero fill the bss segment. */
FillZerobss:
movs r3, #0
str r3, [r2], #4
LoopFillZerobss:
ldr r3, = _ebss
cmp r2, r3
bcc FillZerobss
/* Call the clock system intitialization function.*/
bl SystemInit
/* Call static constructors */
bl __libc_init_array
/* Call the application's entry point.*/
bl main
bx lr
.size Boot_Reset_Handler, .-Boot_Reset_Handler
/**
* #brief This is the code that gets called when the processor receives an
* unexpected interrupt. This simply enters an infinite loop, preserving
* the system state for examination by a debugger.
* #param None
* #retval None
*/
.section .text.Default_Handler,"ax",%progbits
Default_Handler:
Infinite_Loop:
b Infinite_Loop
.size Default_Handler, .-Default_Handler
.section .isr_vector,"a",%progbits
.type g_pfnVectors, %object
.size g_pfnVectors, .-g_pfnVectors
g_pfnVectors:
.word _estack
.word Boot_Reset_Handler
.word NMI_Handler
.word HardFault_Handler
.word MemManage_Handler
.word BusFault_Handler
.word UsageFault_Handler
.word 0
.word 0
.word 0
.word 0
.word SVC_Handler
.word DebugMon_Handler
.word 0
.word PendSV_Handler
.word SysTick_Handler
...
I want to point out that this is not a duplicate of Bootloader for Cortex M4 - Jump to loaded Application although the problem seems similar, the author of that post did not adequately explain how the problem was resolved.
Everything is built using standard gcc tools for embedded development.
I have used the following approach on various STM32 Cortex-M3 and M4 parts:
Given the following in-line assembly function:
__asm void boot_jump( uint32_t address )
{
LDR SP, [R0] ;Load new stack pointer address
LDR PC, [R0, #4] ;Load new program counter address
}
The bootloader switches to the application image thus:
// Switch off core clock before switching vector table
SysTick->CTRL = 0 ;
// Switch off any other enabled interrupts too
...
// Switch vector table
SCB->VTOR = APPLICATION_START_ADDR ;
//Jump to start address
boot_jump( APPLICATION_START_ADDR ) ;
Where APPLICATION_START_ADDR is the base address of the application area (addr in your example); this address is the start of the application's vector table, which starts with the initial stack pointer and reset vector, the boot_jump() function loads these into the SP and PC registers to start the application as if it had been started at reset. The application's reset vector contains the application's execution start address.
The obvious difference between this and your solution is the disabling of any interrupt generators before switching the vector table. You may of course not be using any interrupts in the bootloader.
I use a linker script to describe the memory map of my os kernel. In the linker script I defined many symbols to record location of section start/end. The linker script is as follow:
OUTPUT_FORMAT(binary)
SECTIONS {
/DISCARD/ : {
*(.comment)
*(.note.GNU-stack)
*(.eh_frame)
}
. = 0x100000;
kernel_load_addr = .;
.text : {
kernel_text_start = .;
*(.boot)
*(.text*)
kernel_text_end = .;
} = 0x90
.data : {
kernel_data_start = .;
*(.rodata*)
*(.data*)
kernel_data_end = .;
} = 0
.bss : {
kernel_bss_start = .;
*(COMMON)
*(.bss)
kernel_bss_end = .;
} = 0
kernel_end = .;
}
But if I print the address of these symbols out, the *_start symbol becomes same as *_end symbol.
I'm printing its value with following code:
extern char kernel_text_start;
extern char kernel_text_end;
extern char kernel_data_start;
extern char kernel_data_end;
extern char kernel_bss_start;
extern char kernel_bss_end;
...
raw_write(u64_to_str((uint64_t) &kernel_text_start, buf, 16), 0x0f, 0);
raw_write(u64_to_str((uint64_t) &kernel_text_end, buf, 16), 0x0f, 40);
raw_write(u64_to_str((uint64_t) &kernel_data_start, buf, 16), 0x0f, 80);
raw_write(u64_to_str((uint64_t) &kernel_data_end, buf, 16), 0x0f, 120);
raw_write(u64_to_str((uint64_t) &kernel_bss_start, buf, 16), 0x0f, 160);
raw_write(u64_to_str((uint64_t) &kernel_bss_end, buf, 16), 0x0f, 200);
and result is
The map file is:
Allocating common symbols
Common symbol size file
buddy_num 0x40 build/memory/page_alloc.c.o
buddy_map 0x40 build/memory/page_alloc.c.o
Discarded input sections
.comment 0x0000000000000000 0x4e build/kernel/main.c.o
.note.GNU-stack
0x0000000000000000 0x0 build/kernel/main.c.o
.eh_frame 0x0000000000000000 0x70 build/kernel/main.c.o
.comment 0x0000000000000000 0x4e build/memory/page_alloc.c.o
.note.GNU-stack
0x0000000000000000 0x0 build/memory/page_alloc.c.o
.eh_frame 0x0000000000000000 0xa8 build/memory/page_alloc.c.o
.comment 0x0000000000000000 0x4e build/memory/virt_alloc.c.o
.note.GNU-stack
0x0000000000000000 0x0 build/memory/virt_alloc.c.o
.comment 0x0000000000000000 0x4e build/library/bitmap.c.o
.note.GNU-stack
0x0000000000000000 0x0 build/library/bitmap.c.o
.eh_frame 0x0000000000000000 0x50 build/library/bitmap.c.o
.comment 0x0000000000000000 0x4e build/library/string.c.o
.note.GNU-stack
0x0000000000000000 0x0 build/library/string.c.o
.eh_frame 0x0000000000000000 0x150 build/library/string.c.o
Memory Configuration
Name Origin Length Attributes
*default* 0x0000000000000000 0xffffffffffffffff
Linker script and memory map
/DISCARD/
*(.comment)
*(.note.GNU-stack)
*(.eh_frame)
*(.comment)
*(.note.GNU-stack)
*(.eh_frame)
0x0000000000100000 . = 0x100000
0x0000000000100000 kernel_load_addr = .
0x0000000000100000 text_start_addr = .
.text 0x0000000000100000 0x262f
0x0000000000100000 kernel_text_start = .
*(.boot)
.boot 0x0000000000100000 0x29 build/boot/boot.asm.o
*(.text*)
*fill* 0x0000000000100029 0x7 90
.text 0x0000000000100030 0x0 build/boot/boot.asm.o
.text 0x0000000000100030 0x14f build/boot/init.asm.o
0x0000000000100030 wheel_init
*fill* 0x000000000010017f 0x1 90
.text 0x0000000000100180 0x73c build/kernel/main.c.o
0x0000000000100180 raw_write
0x0000000000100210 read_info
0x00000000001005e0 wheel_main
*fill* 0x00000000001008bc 0x4 90
.text 0x00000000001008c0 0x974 build/memory/page_alloc.c.o
0x00000000001008c0 page_alloc_init
0x0000000000100cb0 find_free_pages
0x0000000000100ef0 alloc_pages
0x00000000001010c0 free_pages
.text 0x0000000000101234 0x0 build/memory/virt_alloc.c.o
*fill* 0x0000000000101234 0xc 90
.text 0x0000000000101240 0x2ff build/library/bitmap.c.o
0x0000000000101240 bitmap_set
0x00000000001013c0 bitmap_clear
*fill* 0x000000000010153f 0x1 90
.text 0x0000000000101540 0x10ef build/library/string.c.o
0x0000000000101540 strlen
0x0000000000101650 strcpy
0x00000000001016c0 strncpy
0x0000000000101770 memcpy
0x0000000000101960 memset
0x0000000000101b60 u32_to_str
0x0000000000101c90 u64_to_str
0x0000000000101dd0 i32_to_str
0x0000000000101e60 i64_to_str
0x0000000000101ef0 vsprintf
0x00000000001025d0 sprintf
0x000000000010262f kernel_text_end = .
0x000000000010262f kernel_text_start = .
*(.boot)
*(.text*)
0x000000000010262f kernel_text_end = .
.data 0x0000000000102630 0x174
0x0000000000102630 kernel_data_start = .
*(.rodata*)
.rodata 0x0000000000102630 0x8 build/kernel/main.c.o
.rodata.str1.1
0x0000000000102638 0x82 build/kernel/main.c.o
*fill* 0x00000000001026ba 0x6 00000000
.rodata 0x00000000001026c0 0xa5 build/library/string.c.o
*(.data*)
*fill* 0x0000000000102765 0x3 00000000
.data 0x0000000000102768 0x3a build/boot/init.asm.o
*fill* 0x00000000001027a2 0x2 00000000
.data 0x00000000001027a4 0x0 build/kernel/main.c.o
.data 0x00000000001027a4 0x0 build/memory/page_alloc.c.o
.data 0x00000000001027a4 0x0 build/memory/virt_alloc.c.o
.data 0x00000000001027a4 0x0 build/library/bitmap.c.o
.data 0x00000000001027a4 0x0 build/library/string.c.o
0x00000000001027a4 kernel_data_end = .
0x00000000001027a4 kernel_data_start = .
*(.rodata*)
*(.data*)
0x00000000001027a4 kernel_data_end = .
0x00000000001027a4 data_end_addr = .
.bss 0x0000000000103000 0x6000
0x0000000000103000 kernel_bss_start = .
*(COMMON)
COMMON 0x0000000000103000 0x80 build/memory/page_alloc.c.o
0x0000000000103000 buddy_num
0x0000000000103040 buddy_map
*(.bss)
*fill* 0x0000000000103080 0xf80 00000000
.bss 0x0000000000104000 0x5000 build/boot/init.asm.o
0x0000000000104000 kernel_stack
0x0000000000105000 pml4t
.bss 0x0000000000109000 0x0 build/kernel/main.c.o
.bss 0x0000000000109000 0x0 build/memory/page_alloc.c.o
.bss 0x0000000000109000 0x0 build/memory/virt_alloc.c.o
.bss 0x0000000000109000 0x0 build/library/bitmap.c.o
.bss 0x0000000000109000 0x0 build/library/string.c.o
0x0000000000109000 kernel_bss_end = .
0x0000000000109000 kernel_bss_start = .
*(COMMON)
*(.bss)
0x0000000000109000 kernel_bss_end = .
0x0000000000109000 bss_end_addr = .
0x0000000000109000 kernel_end = .
LOAD build/boot/boot.asm.o
LOAD build/boot/init.asm.o
LOAD build/kernel/main.c.o
LOAD build/memory/page_alloc.c.o
LOAD build/memory/virt_alloc.c.o
LOAD build/library/bitmap.c.o
LOAD build/library/string.c.o
LOAD link.lds
0x0000000000100000 . = 0x100000
0x0000000000100000 kernel_load_addr = .
0x0000000000100000 text_start_addr = .
0x0000000000100000 data_end_addr = .
0x0000000000100000 bss_end_addr = .
0x0000000000100000 kernel_end = .
OUTPUT(build/kernel.bin binary)
You can see the value of these symbols got reassigned.
So how can I avoid this and get correct address in my program?