Difference between OUTPUT_ARCH(arm) and OUTPUT_ARCH(armv4) in linker script - c

Among other things I am trying to understand the difference between OUTPUT_ARCH(arm) and OUTPUT_ARCH(armv4).
Assume we have next files (I have used linker script example from here as a basis):
main.c:
int main(void)
{
test_1();
test_2();
return 0;
}
main.lds:
OUTPUT_ARCH(arm)
SECTIONS
{
. = 0x10000;
.text : { *(.text) }
. = 0x8000000;
.data : { *(.data) }
.bss : { *(.bss) }
}
test_1.c:
void test_1(void)
{
return;
}
test_2.c:
void test_2(void)
{
return;
}
If we compile it and dump its content we have next:
c:\SysGCC\arm-elf\bin>arm-elf-gcc.exe test_1.c -c
c:\SysGCC\arm-elf\bin>arm-elf-gcc.exe test_2.c -c
c:\SysGCC\arm-elf\bin>arm-elf-objdump.exe -x test_1.o
test_1.o: file format elf32-littlearm
test_1.o
architecture: arm, flags 0x00000010:
HAS_SYMS
start address 0x00000000
private flags = 200: [APCS-32] [FPA float format] [software FP]
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 00000014 00000000 00000000 00000034 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
1 .data 00000000 00000000 00000000 00000048 2**0
CONTENTS, ALLOC, LOAD, DATA
2 .bss 00000000 00000000 00000000 00000048 2**0
ALLOC
3 .comment 00000012 00000000 00000000 00000048 2**0
CONTENTS, READONLY
4 .ARM.attributes 00000010 00000000 00000000 0000005a 2**0
CONTENTS, READONLY
SYMBOL TABLE:
00000000 l df *ABS* 00000000 test_1.c
00000000 l d .text 00000000 .text
00000000 l d .data 00000000 .data
00000000 l d .bss 00000000 .bss
00000000 l d .comment 00000000 .comment
00000000 l d .ARM.attributes 00000000 .ARM.attributes
00000000 g F .text 00000014 test_1
c:\SysGCC\arm-elf\bin>arm-elf-gcc.exe -static -nostartfiles -T main.lds -o main.elf test_1.o test_2.o
c:\SysGCC\arm-elf\bin>arm-elf-objdump.exe -x main.elf
main.elf: file format elf32-littlearm
main.elf
architecture: arm, flags 0x00000112:
EXEC_P, HAS_SYMS, D_PAGED
start address 0x00010000
Program Header:
LOAD off 0x00008000 vaddr 0x00010000 paddr 0x00010000 align 2**15
filesz 0x00000028 memsz 0x00000028 flags r-x
private flags = 200: [APCS-32] [FPA float format] [software FP]
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 00000028 00010000 00010000 00008000 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
1 .comment 00000011 00000000 00000000 00008028 2**0
CONTENTS, READONLY
2 .ARM.attributes 00000010 00000000 00000000 00008039 2**0
CONTENTS, READONLY
SYMBOL TABLE:
00010000 l d .text 00000000 .text
00000000 l d .comment 00000000 .comment
00000000 l d .ARM.attributes 00000000 .ARM.attributes
00000000 l df *ABS* 00000000 test_1.c
00000000 l df *ABS* 00000000 test_2.c
00010014 g F .text 00000014 test_2
00010000 g F .text 00000014 test_1
But if I change OUTPUT_ARCH(arm) to OUTPUT_ARCH(armv4), I get an error from linker:
c:\SysGCC\arm-elf\bin>arm-elf-gcc.exe -static -nostartfiles -T main.lds -o main.elf test_1.o test_2.o
c:/sysgcc/arm-elf/bin/../lib/gcc/arm-elf/4.6.3/../../../../arm-elf/bin/ld.exe: error: test_1.o uses software FP, whereas main.elf uses hardware FP
c:/sysgcc/arm-elf/bin/../lib/gcc/arm-elf/4.6.3/../../../../arm-elf/bin/ld.exe: failed to merge target specific data of file test_1.o
c:/sysgcc/arm-elf/bin/../lib/gcc/arm-elf/4.6.3/../../../../arm-elf/bin/ld.exe: error: test_2.o uses software FP, whereas main.elf uses hardware FP
c:/sysgcc/arm-elf/bin/../lib/gcc/arm-elf/4.6.3/../../../../arm-elf/bin/ld.exe: failed to merge target specific data of file test_2.o
collect2: ld returned 1 exit status
It can be fixed by specifying -mfloat-abi=hard option. In this case there is a difference in private flags comparing with previous output:
c:\SysGCC\arm-elf\bin>arm-elf-gcc.exe -mfloat-abi=hard test_1.c -c
c:\SysGCC\arm-elf\bin>arm-elf-gcc.exe -mfloat-abi=hard test_2.c -c
c:\SysGCC\arm-elf\bin>arm-elf-objdump.exe -x test_1.o
test_1.o: file format elf32-littlearm
test_1.o
architecture: arm, flags 0x00000010:
HAS_SYMS
start address 0x00000000
private flags = 0: [APCS-32] [FPA float format]
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 00000014 00000000 00000000 00000034 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
1 .data 00000000 00000000 00000000 00000048 2**0
CONTENTS, ALLOC, LOAD, DATA
2 .bss 00000000 00000000 00000000 00000048 2**0
ALLOC
3 .comment 00000012 00000000 00000000 00000048 2**0
CONTENTS, READONLY
4 .ARM.attributes 00000010 00000000 00000000 0000005a 2**0
CONTENTS, READONLY
SYMBOL TABLE:
00000000 l df *ABS* 00000000 test_1.c
00000000 l d .text 00000000 .text
00000000 l d .data 00000000 .data
00000000 l d .bss 00000000 .bss
00000000 l d .comment 00000000 .comment
00000000 l d .ARM.attributes 00000000 .ARM.attributes
00000000 g F .text 00000014 test_1
c:\SysGCC\arm-elf\bin>arm-elf-gcc.exe -static -nostartfiles -T main.lds -o main.elf test_1.o test_2.o
c:\SysGCC\arm-elf\bin>arm-elf-objdump.exe -x main.elf
main.elf: file format elf32-littlearm
main.elf
architecture: arm, flags 0x00000112:
EXEC_P, HAS_SYMS, D_PAGED
start address 0x00010000
Program Header:
LOAD off 0x00008000 vaddr 0x00010000 paddr 0x00010000 align 2**15
filesz 0x00000028 memsz 0x00000028 flags r-x
private flags = 0: [APCS-32] [FPA float format]
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 00000028 00010000 00010000 00008000 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
1 .comment 00000011 00000000 00000000 00008028 2**0
CONTENTS, READONLY
2 .ARM.attributes 00000010 00000000 00000000 00008039 2**0
CONTENTS, READONLY
SYMBOL TABLE:
00010000 l d .text 00000000 .text
00000000 l d .comment 00000000 .comment
00000000 l d .ARM.attributes 00000000 .ARM.attributes
00000000 l df *ABS* 00000000 test_1.c
00000000 l df *ABS* 00000000 test_2.c
00010014 g F .text 00000014 test_2
00010000 g F .text 00000014 test_1
Does it mean that OUTPUT_ARCH(armv4) causes linker to generate output solely for hard float?
In general, what is the difference between OUTPUT_ARCH(arm) and OUTPUT_ARCH(armv4)?
According to ld manual OUTPUT_ARCH() specifies a particular output machine architecture.
The argument is one of the names used by the BFD library.
But I have found no clear information about BFD library except general information.
I use arm-elf toolchain from here (Binutils 2.22, GCC 4.6.3, Newlib 1.2.0, GDB 7.4).
Thank you in advance for help.
UPDATE 1:
This update is a reply for the comment below.
Compiler -v output from old toolchain we use now:
Using built-in specs.
Target: arm-elf
Configured with: ../gcc-4.4.1/configure --target=arm-elf --host=i686-pc-mingw32 --with-cpu=xscale --without-stabs -nfp --prefix=/c/cross-gcc/4.4.1 --disable-nls --disable-shared --disable-__cxa_atexit
--enable-threads --with-gnu-gcc --with-gnu-ld --with-gnu-as --with-dwarf2 --enable-languages=c,c++ --enable-interwork --disable-multilib --with-gmp=/c/cross-gcc/4.4.1 --with-mpfr=/c/cross-gcc/4.4.1 -
-with-newlib --with-headers=../../newlib-1.17.0/newlib-1.17.0/newlib/libc/include --disable-libssp --disable-libstdcxx-pch --disable-libmudflap --disable-libgomp -v
Thread model: single
gcc version 4.4.1 (GCC)
Compiler -v output from newer toolchain I used in the examples (SysGCC arm-elf):
Using built-in specs.
COLLECT_GCC=arm-elf-gcc.exe
COLLECT_LTO_WRAPPER=c:/sysgcc/arm-elf/bin/../libexec/gcc/arm-elf/4.6.3/lto-wrapper.exe
Target: arm-elf
Configured with: ../gcc-4.6.3/configure --target arm-elf --enable-win32-registry=SysGCC-arm-elf-4.6.3 --prefix /c/gnu/auto/bu-2.22+gcc-4.6.3+gmp-4.2.4+mpfr-2.4.1+mpc-0.8+newlib-1.20.0-arm-elf/ --enabl
e-languages=c,c++ --disable-nls --with-newlib --with-headers=../newlib-1.20.0/newlib/libc/include --enable-interwork --enable-multilib --with-float=soft
Thread model: single
gcc version 4.6.3 (GCC)
There is no difference between linker output for OUTPUT_ARCH(arm) and OUTPUT_ARCH(armv4) for old compiler. I think I should have checked it before.
Seems that it is an answer to this question.
My goal is to use the combination -mfpu=vfpv3 -mfloat-abi=hard, but according to Debian documentation and GCC 4.4.7 manual this combination is not supported by GCC 4.4.
In fact if I try to compile with -mfpu=vfpv3 -mfloat-abi=hard by old compiler, it returns error:
sorry, unimplemented: -mfloat-abi=hard and VFP
Still and all it is possible to use -mfpu=vfpv3 -mfloat-abi=softfp with old compiler, but according to this comparison it gives big overhead for small routines.

Related

String literal not working if passed as argument

I'm trying to write a bootloader in c and I noticed that string literals only worked if I passed them as a char *.
If it Could help:
when I converted both versions to assembly I found one difference that was only in the working version which is
mov DWORD PTR -8[ebp], eax
push DWORD PTR -8[ebp]
just before calling puts
Here's my code :
asm("jmp main");
void putc(char c) {
asm volatile("mov %%al, %0" :: "a"(c));
asm volatile("mov %ah, 0x0e");
asm volatile("int 0x10");
}
void puts(const char *s) {
while(*s) putc(*s++);
}
void newl() {
char s[] = { 0x0D, 0x0A, 0 };
puts(s);
}
void clear() {
asm volatile("mov ah, 0");
asm volatile("mov al, 0x3");
asm volatile("int 0x10");
}
void __attribute__((optimize("-O0"))) main() {
clear();
char * a = "Hello World";
puts(a); // WORKS
puts("Hello World"); // DOESN'T WORK (DOES NOT WRITE ANYTHING)
newl();
}
LD.LD :
ENTRY(main)
SECTIONS
{
. = 0x7C00;
.text : AT(0x7C00)
{
*(.text);
}
.sig : AT(0x7C00 + 510)
{
SHORT(0xaa55);
}
/DISCARD/ : {
*(.comment)
*(.eh_frame)
}
}
How I compiled:
gcc -m16 -c -ffreestanding -fno-pie -fno-exceptions -masm=intel -s -Os -static -Wall -ffunction-sections -fdata-sections main.cpp -o main.o
ld -m elf_i386 -o main.elf -T ld.ld main.o
objcopy -O binary main.elf main.bin
and I ran it with : qemu-system-x86_64 -fda main.bin
with char * a = "Hello World"; puts(a); :
objdump -h:
Idx Name Size VMA LMA File off Algn
0 .text 00000003 00000000 00000000 00000034 2**0
CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
1 .data 00000000 00000000 00000000 00000037 2**0
CONTENTS, ALLOC, LOAD, DATA
2 .bss 00000000 00000000 00000000 00000037 2**0
ALLOC
3 .rodata 0000000c 00000000 00000000 00000037 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
4 .text.main 00000051 00000000 00000000 00000043 2**0
CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
5 .text.putc 00000014 00000000 00000000 00000094 2**0
CONTENTS, ALLOC, LOAD, READONLY, CODE
6 .text.puts 0000002f 00000000 00000000 000000a8 2**0
CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
7 .text.newl 00000029 00000000 00000000 000000d7 2**0
CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
8 .text.clear 00000008 00000000 00000000 00000100 2**0
CONTENTS, ALLOC, LOAD, READONLY, CODE
9 .comment 0000001f 00000000 00000000 00000108 2**0
CONTENTS, READONLY
10 .note.GNU-stack 00000000 00000000 00000000 00000127 2**0
CONTENTS, READONLY
11 .eh_frame 000000b8 00000000 00000000 00000128 2**2
CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
with puts("Hello World");:
objdump -h:
Idx Name Size VMA LMA File off Algn
0 .text 00000003 00000000 00000000 00000034 2**0
CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
1 .data 00000000 00000000 00000000 00000037 2**0
CONTENTS, ALLOC, LOAD, DATA
2 .bss 00000000 00000000 00000000 00000037 2**0
ALLOC
3 .rodata 0000000c 00000000 00000000 00000037 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
4 .text.main 00000047 00000000 00000000 00000043 2**0
CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
5 .text.putc 00000014 00000000 00000000 0000008a 2**0
CONTENTS, ALLOC, LOAD, READONLY, CODE
6 .text.puts 0000002f 00000000 00000000 0000009e 2**0
CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
7 .text.newl 00000029 00000000 00000000 000000cd 2**0
CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
8 .text.clear 00000008 00000000 00000000 000000f6 2**0
CONTENTS, ALLOC, LOAD, READONLY, CODE
9 .comment 0000001f 00000000 00000000 000000fe 2**0
CONTENTS, READONLY
10 .note.GNU-stack 00000000 00000000 00000000 0000011d 2**0
CONTENTS, READONLY
11 .eh_frame 000000b8 00000000 00000000 00000120 2**2
CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA

simple linker.ld file broke the executable MinGW

I have tried a simple linker script in MinGW using the following commands
gcc -Wall -c boot.c
ld boot.o -o boot.exe -T linker.ld
boot.c contains
int my_main(void){
return 0x1000;
}
linker.ld contains
ENTRY(my_main)
SECTIONS
{
.text : { *(.text) }
.data : { *(.data) }
.bss : { *(.bss) }
}
the linker output is warning warning: cannot find entry symbol my_main; defaulting to 00000000
and the virtual addresses of the sections are weird values:
C:\src>objdump -h boot.exe
boot.exe: file format pei-i386
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 0000000c 00000000 00000000 00000200 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
1 .rdata 00000024 00001000 00001000 00000400 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
2 .eh_fram 00000038 00002000 00002000 00000600 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
and when i try to execute it, windows says "This app can't run in your PC"

"kernel must be loaded first"

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.

Object file created by objcopy is not compatible

I have created an object file from a binary file using objcopy as below:
objcopy -I binary -O elf32-little --rename-section .data=.text file.bin file.o
In one of the linker script sections I have included the following to place that file into that section:
file.o (.text)
But I get the following error:
skipping incompatible file.o when searching for file.o
error: ld returned 1 exit status
I am developing for a arm microcontroller so I believe the file format "elf32-little" is correct.
Any help is much appreciated.
#####################################################################
UPDATE FOLLOWING THE INCBIN path:
I have tried a new approach and although I have made some progress still not quite yet there.
This is my assembly file:
.section .text.audio_binary
.global audio_start
audio_start:
.incbin "AudioData.bin"
.global audio_start
audio_end:
.byte 0
.global audio_size
audio_size:
.int audio_start - audio_start
This is the object file I get:
raw_audio_binary.o: file format elf32-little
SYMBOL TABLE:
00000000 l d .text 00000000 .text
00000000 l d .data 00000000 .data
00000000 l d .bss 00000000 .bss
00000000 l d .text.audio_binary 00000000 .text.audio_binary
00069a78 l .text.audio_binary 00000000 audio_end
00000000 l .text.audio_binary 00000000 $d
00000000 l d .ARM.attributes 00000000 .ARM.attributes
00000000 g .text.audio_binary 00000000 audio_start
00069a79 g .text.audio_binary 00000000 audio_size
And this is the section I have in my linker script:
.text_Flash3 : ALIGN(4)
{
FILL(0xff)
*(.text.$Flash3*)
*(.text.$AUDIO*) *(.rodata.$Flash3*)
*(.text.audio_binary*) /* audio binary */
*(.rodata.$AUDIO*) } > AUDIO
For some reason the linker does NOT place the data in this section (or in any).
Any ideas what is wrong?
I apologise in advance if something is very wrong here, I am new to linker scripts so still understanding them...
If you have a sufficiently recent version of GAS, you can use this to create an object file from a binary input file using the .incbin directive:
.section .rodata
.globl input_wav
input_wav:
.incbin "input.wav"
.globl input_wav_size
input_wav_size:
.long . - input_wav

ld ignores size of nobits input section

When working on a small 32-bit kernel for the x86 architecture I discovered something strange with how ld handles nobits sections.
In my kernel I define a .bootstrap_stack section which holds a temporary stack for the initialisation part of the system. I also hold symbols for the beginning and end of the stack. This input section is redirected to the .bss output section. Each output section of my kernel has a symbol for the beginning and end of the section.
The problem is that in the final executable the symbol for the end of the stack is after the end of the .bss section. In the below examples the symbols stack_top and _kernel_ebss (and _kernel_end) have the same value, which isn't what I wanted.
I expected _kernel_ebss to equal stack_bottom.
However once I rename .bootstrap_stack to .bss this does not happen. Removing nobits also works, but the resulting binary is considerably larger.
Here are the stripped files that reproduce my issue:
boot.s
section .bootstrap_stack, nobits ; this does not work
;section .bootstrap_stack ; this works
;section .bss ; this also works
stack_top:
resb 8096
stack_bottom:
section .text
global _start
_start:
hlt
jmp _start
linker.ld
ENTRY(_start)
SECTIONS
{
. = 0xC0100000;
_kernel_start = .;
.text ALIGN(4K) : AT(ADDR(.text) - 0xC0000000)
{
_kernel_text = .;
*(.multiboot)
*(.text)
_kernel_etext = .;
}
.bss ALIGN(4K) : AT(ADDR(.bss) - 0xC0000000)
{
_kernel_bss = .;
*(COMMON)
*(.bss)
*(.bootstrap_stack)
_kernel_ebss = .;
}
_kernel_end = .;
}
Here are the symbols:
$ objdump -t kernel | sort
00000000 l df *ABS* 00000000 boot.s
c0100000 g .text 00000000 _kernel_start
c0100000 g .text 00000000 _kernel_text
c0100000 g .text 00000000 _start
c0100000 l d .text 00000000 .text
c0100003 g .text 00000000 _kernel_etext
c0101000 g .text 00000000 _kernel_bss
c0101000 g .text 00000000 _kernel_ebss
c0101000 g .text 00000000 _kernel_end
c0101000 l .bootstrap_stack, 00000000 stack_top
c0101000 l d .bootstrap_stack, 00000000 .bootstrap_stack,
c0102fa0 l .bootstrap_stack, 00000000 stack_bottom
By renaming .bootstrap_stack to .bss I get what I expected.
00000000 l df *ABS* 00000000 boot.s
c0100000 g .text 00000000 _kernel_start
c0100000 g .text 00000000 _kernel_text
c0100000 g .text 00000000 _start
c0100000 l d .text 00000000 .text
c0100003 g .text 00000000 _kernel_etext
c0101000 g .bss 00000000 _kernel_bss
c0101000 l .bss 00000000 stack_top
c0101000 l d .bss 00000000 .bss
c0102fa0 g .bss 00000000 _kernel_ebss
c0102fa0 g .bss 00000000 _kernel_end
c0102fa0 l .bss 00000000 stack_bottom
My question is whether this is expected behaviour of ld. If yes, what is the problem with my example, because as far as I understand .bss is also a nobits section, but it produces the expected result?
Okay I figured it out.
Apparently you're not supposed to have a comma right after the name of the section. objdump includes the comma in the name of the section so that clearly shows that that is the mistake.
So
section .bootstrap_stack, nobits
should be
section .bootstrap_stack nobits

Resources