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