What is "ld -Ttext" option doing? - linker

I am following this half-completed tutorial to develop a simple OS. One step (on page 50) is to compile a simple kernel with $ld -o kernel.bin -Ttext 0x1000 kernel.o --oformat binary. However I don't really understand what is the option -Ttext doing.
To make the question specific, why in the following experiment are md5s of kernel_1000.bin & kernel.bin equal, kernel_1001.bin & kernel_1009.bin equal, and kernel_1007.bin & kernel_1017.bin equal, while all other pairs are not equal?
My experiment
I tried to compile several different kernels with different -Ttext like the in the following Makefile:
...
kernel.o: kernel.c
gcc -ffreestanding -c kernel.c
kernel.bin: kernel.o
ld -o $# kernel.o --oformat binary
kernel_1000.bin: kernel.o
ld -o $# -Ttext 0x1000 kernel.o --oformat binary
kernel_1001.bin: kernel.o
ld -o $# -Ttext 0x1001 kernel.o --oformat binary
...
And then I checked their md5:
$ ls *.bin | xargs md5sum
d9248440a2c816e41527686cdb5118e4 kernel_1000.bin
65db5ab465301da1176b523dec387a40 kernel_1001.bin
819a5638827494a4556b7a96ee6e14b2 kernel_1007.bin
d9248440a2c816e41527686cdb5118e4 kernel_1008.bin
65db5ab465301da1176b523dec387a40 kernel_1009.bin
216b24060abce034911642acfa880403 kernel_1015.bin
e92901b1d12d316c564ba7916abca20c kernel_1016.bin
819a5638827494a4556b7a96ee6e14b2 kernel_1017.bin
d9248440a2c816e41527686cdb5118e4 kernel.bin
kernel.c
void main() {
char* video_memory = (char*) 0xb8000;
*video_memory = 'X';
}
Development environment
$ gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/4.9/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Debian 4.9.2-10' --with-bugurl=file:///usr/share/doc/gcc-4.9/README.Bugs --enable-languages=c,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.9 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.9 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --disable-vtable-verify --enable-plugin --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-4.9-amd64/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-4.9-amd64 --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-4.9-amd64 --with-arch-directory=amd64 --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --enable-objc-gc --enable-multiarch --with-arch-32=i586 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 4.9.2 (Debian 4.9.2-10)
$ uname -a
Linux localhost 3.16.0-4-amd64 #1 SMP Debian 3.16.7-ckt20-1+deb8u1 (2015-12-14) x86_64 GNU/Linux

The -Ttext option puts the .text section of your program by the given address. For example if you are compile this assembly code:
section .text
global _start
_start:
mov al, '!'
jmp l
l: mov ah, 0x0e
mov bh, 0x00
mov bl, 0x07
int 0x10
jmp $
times 510-($-$$) db 0
db 0x55
db 0xaa
with:
nasm -f elf64 -o test.o test.S
ld -o test test.o
And will look on it with the objdump, you will see that it was linked by default address, something around 0x0000000000400000 for the x86_64:
~$ objdump -D test
test: file format elf64-x86-64
Disassembly of section .text:
0000000000400080 <_start>:
400080: b0 21 mov $0x21,%al
400082: eb 00 jmp 400084 <l>
0000000000400084 <l>:
400084: b4 0e mov $0xe,%ah
...
...
...
And all addresses in the program (at least in the .text section) will be relative to this address. If you will add the -Ttext 1000 option, you will see:
~$ objdump -D test
test: file format elf64-x86-64
Disassembly of section .text:
0000000000001000 <_start>:
1000: b0 21 mov $0x21,%al
1002: eb 00 jmp 1004 <l>
0000000000001004 <l>:
1004: b4 0e mov $0xe,%ah
That you program will be linked to start at 0x1000 address and all addresses (including jmp and etc.) will be relative to the 0x1000 to.
This important for two things. In short words, when an operating system kernel loads your program, it loads your executable which is in elf format or in other binary format and reads where the .text section starts. In our case, you can link your kernel.bin as you want, because there are no loaders as an operating system kernel and your are master of all memory space.
So if you will link your kernel.bin to start at 0x1000, you will know where the code starts to work (of course if it will actually loaded at this place in memory) and if you know the base address of your code, you can get all addresses inside it, something like my_label_inside_program - _start.

Related

Errors compiling sqrt function for RaspberryPI2 and BeableBoneBlack with arm-none-eabi-gcc compiler

i'm new in this type of coding and i'm trying to do some test executing bare-metal software for Cortex-A processors. I have experience with Cortex-M MCU and i compiled code with an IDE like ARM-Keil and with SDK by Nordic for some BLE jobs. Now i want to try to understand better the world of Cortex-A and i would learn coding in a bare-metal way, starting from some examples that i found online. I had some experiences with freeRTOS with Cortex-M, so i found online some git repository from some good guy that makes a porting of freeRTOS for RaspberryPI and BeableBoneBlack. From now on i will just explain my problem for the BeableBoneBlack, beacouse for the RaspberryPI it's similar.
I'm on linux, i installed gcc-arm-none-eabi compiler, so i cloned the BeagleBone Black with freeRTOS repository from this link.
I usually use VS Code to write code, so in the integrated terminal when i run the command make everything it's working and the of my BBB flashes correctly.
So now i would like to improve my code, and in order to do some tests i would like to use the rand() function, from stdlib.h. Unhappily I find that there are some errors: undefined reference to rand.
The last months, before doing tests with the BBB, i found other repos for RPi2 and i learn something about the linker of the arm-none-eabi compiler, that needs the addition of some parameters in order link library files during the process.
From this repo now i have two files: makedefs_ti and makefile. Opening the make file i found in line 26-27 the part of the generation of the file app, so where the linker is called. In this lines there are references to LIB_GCC and LIB_C, which are defined in the makedefs_ti. In lines 49-50 there are the references to the directory where the compiler is installed (I changed 4.7.3 with the correct one installed on my linux pc that is 9.2.1).
In the makefile, after -L$(LIB_C), if i add the linker parameters like -lc or -lg and try to recompile, i had error like arm-none-eabi-ld: cannot find -lc.
With some understanding from online resources i modified the the makedefs_ti as following:
# Toolchain/library path. LIB_PATH is an exported environmental variable which
# shall point to the installation of toolchain
#
#LIB_GCC=${LIB_PATH}/lib/gcc/arm-none-eabi/4.7.3/
#LIB_C=${LIB_PATH}/arm-none-eabi/lib/
LIB_GCC= /usr/lib/gcc/arm-none-eabi/9.2.1
LIB_C= /usr/lib/arm-none-eabi/lib
and the makefile :
$(LD) -o $#.out $< -T bbb.ld -Map bbb.map $(APP_LIB) $(LDFLAGS) $(RUNTIMELIB) -L $(LPATH) \
-L $(LIB_GCC) -lgcc -L $(LIB_C) -lc -lg
In this way my main.c file that calls a rand() function compile correctly.
During another test i tried to compile another code. Now i wrote a pair of .c and .h file (i placed them in the rtos directory in order to exploit the same makefile that is present there) that have inside a function that calls sqrt(). So, calling the function in the main() and compiling, even if i include everywhere <math.h> i have the error:
undefined reference to `sqrt'
and obviously the compilation stops.
Starting from this i tried to add another parameter to the linker, so i modified the makefile as following:
$(LD) -o $#.out $< -T bbb.ld -Map bbb.map $(APP_LIB) $(LDFLAGS) $(RUNTIMELIB) -L $(LPATH) \
-L $(LIB_GCC) -lgcc -L $(LIB_C) -lc -lg -lm
and i get other errors which i am unable to resolve in any way:
arm-none-eabi-ld: /usr/lib/arm-none-eabi/lib/libm.a(lib_a-w_sqrt.o): in function `sqrt':
/build/newlib-CVVEyx/newlib-3.3.0/build/arm-none-eabi/newlib/libm/math/../../../../../newlib/libm/math/w_sqrt.c:62: undefined reference to `__aeabi_dcmpun'
arm-none-eabi-ld: /build/newlib-CVVEyx/newlib-3.3.0/build/arm-none-eabi/newlib/libm/math/../../../../../newlib/libm/math/w_sqrt.c:63: undefined reference to `__aeabi_dcmplt'
arm-none-eabi-ld: /build/newlib-CVVEyx/newlib-3.3.0/build/arm-none-eabi/newlib/libm/math/../../../../../newlib/libm/math/w_sqrt.c:64: undefined reference to `__errno'
arm-none-eabi-ld: /build/newlib-CVVEyx/newlib-3.3.0/build/arm-none-eabi/newlib/libm/math/../../../../../newlib/libm/math/w_sqrt.c:65: undefined reference to `__aeabi_ddiv'
arm-none-eabi-ld: /usr/lib/arm-none-eabi/lib/libm.a(lib_a-e_sqrt.o): in function `__ieee754_sqrt':
/build/newlib-CVVEyx/newlib-3.3.0/build/arm-none-eabi/newlib/libm/machine/arm/../../../../../../newlib/libm/machine/arm/../../math/e_sqrt.c:110: undefined reference to `__aeabi_dmul'
arm-none-eabi-ld: /build/newlib-CVVEyx/newlib-3.3.0/build/arm-none-eabi/newlib/libm/machine/arm/../../../../../../newlib/libm/machine/arm/../../math/e_sqrt.c:110: undefined reference to `__aeabi_dadd'
arm-none-eabi-ld: /build/newlib-CVVEyx/newlib-3.3.0/build/arm-none-eabi/newlib/libm/machine/arm/../../../../../../newlib/libm/machine/arm/../../math/e_sqrt.c:117: undefined reference to `__aeabi_dsub'
arm-none-eabi-ld: /build/newlib-CVVEyx/newlib-3.3.0/build/arm-none-eabi/newlib/libm/machine/arm/../../../../../../newlib/libm/machine/arm/../../math/e_sqrt.c:117: undefined reference to `__aeabi_ddiv'
make: *** [makefile:26: app] Errore 1
I would remark that, calling the sqrt() in the main works correctly, the problem happens when i call the sqrt() in other .c file. Instead the rand() function in the .c additional file works correctly.
I don't know how to resolve those errors, someone could help me?
What i tried another day is to write the same code in a Code Composer Studio project and it worked (with same functions that call sqrt and rand in additional .c file. What is the difference?
I'm very sorry if this is a long explanation, but i didn't find another way to explain my situation.
Thanks a lot in advance.
Salvo
start.s
.globl _start
_start:
;# enable fpu
mrc p15, 0, r0, c1, c0, 2
orr r0,r0,#0x300000 ;# single precision
orr r0,r0,#0xC00000 ;# double precision
mcr p15, 0, r0, c1, c0, 2
mov r0,#0x40000000
fmxr fpexc,r0
mov sp,#0x8000
bl notmain
hang: b hang
notmain.c
double notmain ( double a, double b )
{
return(a+b);
}
(not a real baremetal app, derived from one)
build for hard float
arm-none-eabi-as --warn --fatal-warnings -mcpu=arm1176jzf-s -march=armv6 -mfpu=vfp start.s -o start.o
arm-none-eabi-gcc -Wall -O2 -ffreestanding -mcpu=arm1176jzf-s -mtune=arm1176jzf-s -mhard-float -mfpu=vfp -c notmain.c -o notmain.o
arm-none-eabi-ld -nostdlib -nostartfiles start.o notmain.o -T memmap -o notmain.elf
arm-none-eabi-objdump -D notmain.elf > notmain.list
arm-none-eabi-objcopy --srec-forceS3 notmain.elf -O srec notmain.srec
arm-none-eabi-objcopy notmain.elf -O binary kernel.img
hardware float used
00008024 <notmain>:
8024: ee300b01 vadd.f64 d0, d0, d1
8028: e12fff1e bx lr
build for soft float
arm-none-eabi-as --warn --fatal-warnings -mcpu=arm1176jzf-s -march=armv6 -mfpu=vfp start.s -o start.o
arm-none-eabi-gcc -Wall -O2 -ffreestanding -mcpu=arm1176jzf-s -mtune=arm1176jzf-s -c notmain.c -o notmain.o
arm-none-eabi-ld -nostdlib -nostartfiles start.o notmain.o -T memmap -o notmain.elf
arm-none-eabi-ld: notmain.o: in function `notmain':
notmain.c:(.text+0x4): undefined reference to `__aeabi_dadd'
Makefile:33: recipe for target 'notmain.elf' failed
make: *** [notmain.elf] Error 1
It needs gcclib.
Using gcc as a linker (I know how horrible a thought that is).
arm-none-eabi-as --warn --fatal-warnings -mcpu=arm1176jzf-s -march=armv6 -mfpu=vfp start.s -o start.o
arm-none-eabi-gcc -Wall -O2 -ffreestanding -mcpu=arm1176jzf-s -mtune=arm1176jzf-s -c notmain.c -o notmain.o
arm-none-eabi-gcc -Wall -O2 -ffreestanding -mcpu=arm1176jzf-s -mtune=arm1176jzf-s -nostdlib -nostartfiles start.o notmain.o -T memmap -o notmain.elf -lgcc
arm-none-eabi-objdump -D notmain.elf > notmain.list
arm-none-eabi-objcopy --srec-forceS3 notmain.elf -O srec notmain.srec
arm-none-eabi-objcopy notmain.elf -O binary kernel.img
...
00008024 <notmain>:
8024: e92d4010 push {r4, lr}
8028: eb000003 bl 803c <__adddf3>
802c: e8bd8010 pop {r4, pc}
00008030 <__aeabi_drsub>:
8030: e2211102 eor r1, r1, #-2147483648 ; 0x80000000
8034: ea000000 b 803c <__adddf3>
00008038 <__aeabi_dsub>:
8038: e2233102 eor r3, r3, #-2147483648 ; 0x80000000
0000803c <__adddf3>:
803c: e92d4030 push {r4, r5, lr}
gcc is passing these to ld.
[0][/opt/gnuarm/lib/gcc/arm-none-eabi/10.2.0/../../../../arm-none-eabi/bin/ld]
[1][-plugin]
[2][/opt/gnuarm/libexec/gcc/arm-none-eabi/10.2.0/liblto_plugin.so]
[3][-plugin-opt=/opt/gnuarm/libexec/gcc/arm-none-eabi/10.2.0/lto-wrapper]
[4][-plugin-opt=-fresolution=/tmp/ccRiWZtk.res]
[5][-X]
[6][-o]
[7][notmain.elf]
[8][-L/opt/gnuarm/lib/gcc/arm-none-eabi/10.2.0]
[9][-L/opt/gnuarm/lib/gcc/arm-none-eabi/10.2.0/../../../../arm-none-eabi/lib]
[10][start.o]
[11][notmain.o]
[12][-lgcc]
[13][-T]
[14][memmap]
find | grep libgcc
./lib/gcc/arm-none-eabi/10.2.0/libgcc.a
./lib/gcc/arm-none-eabi/10.2.0/thumb/libgcc.a
./lib/gcc/arm-none-eabi/10.2.0/thumb/autofp/v7/fpu/libgcc.a
./lib/gcc/arm-none-eabi/10.2.0/arm/autofp/v5te/fpu/libgcc.a
So to use ld then
arm-none-eabi-as --warn --fatal-warnings -mcpu=arm1176jzf-s -march=armv6 -mfpu=vfp start.s -o start.o
arm-none-eabi-gcc -Wall -O2 -ffreestanding -mcpu=arm1176jzf-s -mtune=arm1176jzf-s -c notmain.c -o notmain.o
arm-none-eabi-ld -nostdlib -nostartfiles start.o notmain.o -T memmap -o notmain.elf -L/opt/gnuarm/lib/gcc/arm-none-eabi/10.2.0/ -lgcc
arm-none-eabi-objdump -D notmain.elf > notmain.list
arm-none-eabi-objcopy --srec-forceS3 notmain.elf -O srec notmain.srec
arm-none-eabi-objcopy notmain.elf -O binary kernel.img
Why does it use addf3 now? do not know.
00008024 <notmain>:
8024: e92d4010 push {r4, lr}
8028: eb000003 bl 803c <__adddf3>
802c: e8bd8010 pop {r4, pc}
00008030 <__aeabi_drsub>:
8030: e2211102 eor r1, r1, #-2147483648 ; 0x80000000
8034: ea000000 b 803c <__adddf3>
00008038 <__aeabi_dsub>:
8038: e2233102 eor r3, r3, #-2147483648 ; 0x80000000
0000803c <__adddf3>:
803c: e92d4030 push {r4, r5, lr}
8040: e1a04081 lsl r4, r1, #1
8044: e1a05083 lsl r5, r3, #1
That is how you deal with the aeabi stuff, you need to either use hard float or include the path to gcclib or just add it to the line
arm-none-eabi-as --warn --fatal-warnings -mcpu=arm1176jzf-s -march=armv6 -mfpu=vfp start.s -o start.o
arm-none-eabi-gcc -Wall -O2 -ffreestanding -mcpu=arm1176jzf-s -mtune=arm1176jzf-s -c notmain.c -o notmain.o
arm-none-eabi-ld -nostdlib -nostartfiles start.o notmain.o -T memmap -o notmain.elf /opt/gnuarm/lib/gcc/arm-none-eabi/10.2.0/libgcc.a
#arm-none-eabi-gcc -Wall -O2 -ffreestanding -mcpu=arm1176jzf-s -mtune=arm1176jzf-s -nostdlib -nostartfiles start.o notmain.o -T memmap -o notmain.elf -lgcc
arm-none-eabi-objdump -D notmain.elf > notmain.list
arm-none-eabi-objcopy --srec-forceS3 notmain.elf -O srec notmain.srec
arm-none-eabi-objcopy notmain.elf -O binary kernel.img
Now sqrt() is a C library thing not a gcc library thing so you need a C library (looks like you are trying to use newlib) and you need to build the C library to match gcc so you need to build it for hard or soft float and need to include the right library. Which I do not have...well....
arm-none-eabi-as --warn --fatal-warnings -mcpu=arm1176jzf-s -march=armv6 -mfpu=vfp start.s -o start.o
arm-none-eabi-gcc -Wall -O2 -ffreestanding -mcpu=arm1176jzf-s -mtune=arm1176jzf-s -c notmain.c -o notmain.o
arm-none-eabi-ld -nostdlib -nostartfiles start.o notmain.o -T memmap -o notmain.elf /home/so/gcc-arm-none-eabi-9-2019-q4-major/lib/gcc/arm-none-eabi/9.2.1/libgcc.a
arm-none-eabi-objdump -D notmain.elf > notmain.list
arm-none-eabi-objcopy --srec-forceS3 notmain.elf -O srec notmain.srec
arm-none-eabi-objcopy notmain.elf -O binary kernel.img
so
double sqrt(double x);
double notmain ( double a )
{
return(sqrt(a));
}
looks familiar
arm-none-eabi-gcc -Wall -O2 -ffreestanding -mcpu=arm1176jzf-s -mtune=arm1176jzf-s -c notmain.c -o notmain.o
arm-none-eabi-ld -nostdlib -nostartfiles start.o notmain.o -T memmap -o notmain.elf /home/so/gcc-arm-none-eabi-9-2019-q4-major/lib/gcc/arm-none-eabi/9.2.1/libgcc.a /home/so/gcc-arm-none-eabi-9-2019-q4-major/arm-none-eabi/lib/libm.a
arm-none-eabi-ld: /home/so/gcc-arm-none-eabi-9-2019-q4-major/arm-none-eabi/lib/libm.a(lib_a-w_sqrt.o): in function `sqrt':
w_sqrt.c:(.text.sqrt+0x34): undefined reference to `__aeabi_dcmpun'
arm-none-eabi-ld: w_sqrt.c:(.text.sqrt+0x6c): undefined reference to `__aeabi_dcmplt'
arm-none-eabi-ld: w_sqrt.c:(.text.sqrt+0xc4): undefined reference to `__aeabi_ddiv'
arm-none-eabi-ld: w_sqrt.c:(.text.sqrt+0xd8): undefined reference to `__errno'
arm-none-eabi-ld: w_sqrt.c:(.text.sqrt+0x120): undefined reference to `__errno'
arm-none-eabi-ld: /home/so/gcc-arm-none-eabi-9-2019-q4-major/arm-none-eabi/lib/libm.a(lib_a-e_sqrt.o): in function `__ieee754_sqrt':
e_sqrt.c:(.text.__ieee754_sqrt+0x200): undefined reference to `__aeabi_dmul'
arm-none-eabi-ld: e_sqrt.c:(.text.__ieee754_sqrt+0x20c): undefined reference to `__aeabi_dadd'
arm-none-eabi-ld: e_sqrt.c:(.text.__ieee754_sqrt+0x22c): undefined reference to `__aeabi_dsub'
arm-none-eabi-ld: e_sqrt.c:(.text.__ieee754_sqrt+0x238): undefined reference to `__aeabi_ddiv'
Makefile:33: recipe for target 'notmain.elf' failed
make: *** [notmain.elf] Error 1
find
./arm-none-eabi/lib/libm.a
./arm-none-eabi/lib/thumb/v7e-m/nofp/libm.a
./arm-none-eabi/lib/thumb/v6-m/nofp/libm.a
./arm-none-eabi/lib/thumb/v8-m.base/nofp/libm.a
./arm-none-eabi/lib/thumb/v7/nofp/libm.a
./arm-none-eabi/lib/thumb/v8-m.main+dp/hard/libm.a
./arm-none-eabi/lib/thumb/v8-m.main+dp/softfp/libm.a
./arm-none-eabi/lib/thumb/v7e-m+dp/hard/libm.a
./arm-none-eabi/lib/thumb/v7e-m+dp/softfp/libm.a
./arm-none-eabi/lib/thumb/v7-r+fp.sp/hard/libm.a
./arm-none-eabi/lib/thumb/v7-r+fp.sp/softfp/libm.a
./arm-none-eabi/lib/thumb/v7e-m+fp/hard/libm.a
./arm-none-eabi/lib/thumb/v7e-m+fp/softfp/libm.a
./arm-none-eabi/lib/thumb/v8-m.main+fp/hard/libm.a
./arm-none-eabi/lib/thumb/v8-m.main+fp/softfp/libm.a
./arm-none-eabi/lib/thumb/v7-m/nofp/libm.a
./arm-none-eabi/lib/thumb/nofp/libm.a
./arm-none-eabi/lib/thumb/v7+fp/hard/libm.a
./arm-none-eabi/lib/thumb/v7+fp/softfp/libm.a
./arm-none-eabi/lib/thumb/v8-m.main/nofp/libm.a
./arm-none-eabi/lib/arm/v5te/hard/libm.a
./arm-none-eabi/lib/arm/v5te/softfp/libm.a
armv5te should work for armv6
arm-none-eabi-ld -nostdlib -nostartfiles start.o notmain.o -T memmap -o notmain.elf /home/so/gcc-arm-none-eabi-9-2019-q4-major/lib/gcc/arm-none-eabi/9.2.1/libgcc.a /home/so/gcc-arm-none-eabi-9-2019-q4-major/arm-none-eabi/lib/arm/v5te/softfp/libm.a
arm-none-eabi-ld: /home/so/gcc-arm-none-eabi-9-2019-q4-major/arm-none-eabi/lib/arm/v5te/softfp/libm.a(lib_a-w_sqrt.o): in function `sqrt':
w_sqrt.c:(.text.sqrt+0x94): undefined reference to `__errno'
arm-none-eabi-ld: w_sqrt.c:(.text.sqrt+0xdc): undefined reference to `__errno'
Makefile:33: recipe for target 'notmain.elf' failed
make: *** [notmain.elf] Error 1
errno is a global variable. that the C library probably wants to use for the soft float.
int __errno;
double sqrt(double x);
double notmain ( double a )
{
return(sqrt(a));
}
and now the tool is happy
arm-none-eabi-as --warn --fatal-warnings -mcpu=arm1176jzf-s -march=armv6 -mfpu=vfp start.s -o start.o
arm-none-eabi-gcc -Wall -O2 -ffreestanding -mcpu=arm1176jzf-s -mtune=arm1176jzf-s -c notmain.c -o notmain.o
arm-none-eabi-ld -nostdlib -nostartfiles start.o notmain.o -T memmap -o notmain.elf /home/so/gcc-arm-none-eabi-9-2019-q4-major/lib/gcc/arm-none-eabi/9.2.1/libgcc.a /home/so/gcc-arm-none-eabi-9-2019-q4-major/arm-none-eabi/lib/arm/v5te/softfp/libm.a
arm-none-eabi-objdump -D notmain.elf > notmain.list
arm-none-eabi-objcopy --srec-forceS3 notmain.elf -O srec notmain.srec
arm-none-eabi-objcopy notmain.elf -O binary kernel.img
but this is hard float not soft.
00008024 <notmain>:
8024: eaffffff b 8028 <sqrt>
00008028 <sqrt>:
8028: e52de004 push {lr} ; (str lr, [sp, #-4]!)
802c: ed2d8b02 vpush {d8}
8030: e1a02000 mov r2, r0
8034: e1a03001 mov r3, r1
8038: e24dd02c sub sp, sp, #44 ; 0x2c
803c: ec432b18 vmov d8, r2, r3
8040: eb000038 bl 8128 <__ieee754_sqrt>
8044: e59f30d4 ldr r3, [pc, #212] ; 8120 <sqrt+0xf8>
8048: eeb48b48 vcmp.f64 d8, d8
804c: e1d3c0d0 ldrsb ip, [r3]
8050: eef1fa10 vmrs APSR_nzcv, fpscr
You get the idea though as to what the path to take to solve this is. You need a properly matched/built library then you need to link it. Keil and others simply do that for you in the toolchain, matching things based on the project. And/or a C library that is integrated with the toolchain.
Building for hard float
arm-none-eabi-as --warn --fatal-warnings -mcpu=arm1176jzf-s -march=armv6 -mfpu=vfp start.s -o start.o
arm-none-eabi-gcc -Wall -O2 -ffreestanding -mcpu=arm1176jzf-s -mtune=arm1176jzf-s -mhard-float -mfpu=vfp -c notmain.c -o notmain.o
arm-none-eabi-ld -nostdlib -nostartfiles start.o notmain.o -T memmap -o notmain.elf /home/so/gcc-arm-none-eabi-9-2019-q4-major/lib/gcc/arm-none-eabi/9.2.1/libgcc.a /home/so/gcc-arm-none-eabi-9-2019-q4-major/arm-none-eabi/lib/arm/v5te/hard/libm.a
arm-none-eabi-objdump -D notmain.elf > notmain.list
arm-none-eabi-objcopy --srec-forceS3 notmain.elf -O srec notmain.srec
arm-none-eabi-objcopy notmain.elf -O binary kernel.img
tool is happy.
00008024 <notmain>:
8024: eaffffff b 8028 <sqrt>
00008028 <sqrt>:
8028: e52de004 push {lr} ; (str lr, [sp, #-4]!)
802c: ed2d8b02 vpush {d8}
8030: eeb08b40 vmov.f64 d8, d0
8034: e24dd02c sub sp, sp, #44 ; 0x2c
8038: eb000038 bl 8120 <__ieee754_sqrt>
803c: eeb48b48 vcmp.f64 d8, d8
8040: e59f30d0 ldr r3, [pc, #208] ; 8118 <sqrt+0xf0>
8044: e1d310d0 ldrsb
Would have to make this a real application main calls another function that has a call to sqrt in it. And then run it on hardware and/or examine these instructions. Or even better get a C library implementation of sqrt and build it in the project so that it matches the target and instruction sets. (same story with the libgcc calls as needed, test them or build them).

C kernel compilation: GCC LD undefined reference to `___main'

So I'm trying to compile a C file to .bin and then add it to an .img file after my first stage bootloader.
I have found these bash commands in this answer by user Michael Petch:
gcc -g -m32 -c -ffreestanding -o kernel.o kernel.c -lgcc
ld -melf_i386 -Tlinker.ld -nostdlib --nmagic -o kernel.elf kernel.o
objcopy -O binary kernel.elf kernel.bin
and used this C code (taken from the same answer, saved as kernel.c):
/* This code will be placed at the beginning of the object by the linker script */
__asm__ ("jmp _main\r\n");
int main(){
/* Do Stuff Here*/
return 0; /* return back to bootloader */
}
I executed those commands in cygwin and it produced the following result:
ld: kernel.o: in function `main':
/cygdrive/d/Work/asm/kernel.c:4: undefined reference to `___main'
objcopy: 'kernel.elf': No such file
The linker.ld file is here:
OUTPUT_FORMAT(elf32-i386)
ENTRY(_main)
SECTIONS
{
. = 0x9000;
.text : { *(.text.start) *(.text) }
.data : { *(.data) }
.bss : { *(.bss) *(COMMON) }
}
I have dissasembled the kernel.o file using objdump, the result of which is here:
> objdump -d -j .text kernel.o
kernel.o: file format pe-i386
Disassembly of section .text:
00000000 <.text>:
0: eb 00 jmp 2 <_main>
00000002 <_main>:
2: 55 push %ebp
3: 89 e5 mov %esp,%ebp
5: 83 e4 f0 and $0xfffffff0,%esp
8: e8 00 00 00 00 call d <_main+0xb>
d: b8 00 00 00 00 mov $0x0,%eax
12: c9 leave
13: c3 ret
Here is the result of gcc -v if that helps also:
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-pc-cygwin/10/lto-wrapper.exe
Target: x86_64-pc-cygwin
Configured with: /mnt/share/cygpkgs/gcc/gcc.x86_64/src/gcc-10.2.0/configure --srcdir=/mnt/share/cygpkgs/gcc/gcc.x86_64/src/gcc-10.2.0 --prefix=/usr --exec-prefix=/usr --localstatedir=/var --sysconfdir=/etc --docdir=/usr/share/doc/gcc --htmldir=/usr/share/doc/gcc/html -C --build=x86_64-pc-cygwin --host=x86_64-pc-cygwin --target=x86_64-pc-cygwin --without-libiconv-prefix --without-libintl-prefix --libexecdir=/usr/lib --with-gcc-major-version-only --enable-shared --enable-shared-libgcc --enable-static --enable-version-specific-runtime-libs --enable-bootstrap --enable-__cxa_atexit --with-dwarf2 --with-tune=generic --enable-languages=c,c++,fortran,lto,objc,obj-c++ --enable-graphite --enable-threads=posix --enable-libatomic --enable-libgomp --enable-libquadmath --enable-libquadmath-support --disable-libssp --enable-libada --disable-symvers --with-gnu-ld --with-gnu-as --with-cloog-include=/usr/include/cloog-isl --without-libiconv-prefix --without-libintl-prefix --with-system-zlib --enable-linker-build-id --with-default-libstdcxx-abi=gcc4-compatible --enable-libstdcxx-filesystem-ts
Thread model: posix
Supported LTO compression algorithms: zlib zstd
gcc version 10.2.0 (GCC)
What am I doing wrong? Is this caused by cygwin? If yes, is there any other option I could use on windows? (I tried MSVC but that is just plainly horrible)
Also, my bootloader is not using any .section pseudo-ops (I have no idea on how to correctly work with them), will this cause any problems in the future and will it work correctly with the compiled C program?
By deeper searching, it can be easily found out that the __main (with an additional underscore internally) is the actual entry point for programs.
The same problem is mentioned in the following two answers:
https://stackoverflow.com/a/32164910/14320958
https://stackoverflow.com/a/45442576/14320958
Both of which claim some form of a connection to the -lgcc option and the libgcc library.
Renaming main to __main works, but is not recommended (the entry point for kernels is apparently by convention kmain as seen in other questions and answers)
The __main function is what a OS calls when starting a program and it usually contains (for example) a call to exit() (passing the return code from main if it's return type is int) and some other underlying system calls (which are probably system specific, more research would need to be done here)
GCC expects you to include a __main function even on standalone compilations, since it's by specification (or that's what I seen people claim) the default entry point for all applications

How can I change objdump output format?

Hi I'm learning c compiler with this book. https://www.sigbus.info/compilerbook
I want to show the same result as the book shows. What should I do it? I think I need to change the version of gcc, objdump or options.
This book says that it is possible to compile too from the following expected assemble output.
expected
.intel_syntax noprefix
.global main
main:
mov rax, 42
ret
actual
00000000000005fa <main>:
5fa: 55 push rbp
5fb: 48 89 e5 mov rbp,rsp
5fe: b8 2a 00 00 00 mov eax,0x2a
603: 5d pop rbp
604: c3 ret
605: 66 2e 0f 1f 84 00 00 nop WORD PTR cs:[rax+rax*1+0x0]
60c: 00 00 00
60f: 90 nop
what I did
root#686394c78009:/zcc# uname -a
Linux 686394c78009 4.9.125-linuxkit #1 SMP Fri Sep 7 08:20:28 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
root#686394c78009:/zcc# objdump -v
GNU objdump (GNU Binutils for Ubuntu) 2.30
Copyright (C) 2018 Free Software Foundation, Inc.
This program is free software; you may redistribute it under the terms of
the GNU General Public License version 3 or (at your option) any later version.
This program has absolutely no warranty.
root#686394c78009:/zcc# gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/7/lto-wrapper
OFFLOAD_TARGET_NAMES=nvptx-none
OFFLOAD_TARGET_DEFAULT=1
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 7.4.0-1ubuntu1~18.04.1' --with-bugurl=file:///usr/share/doc/gcc-7/README.Bugs --enable-languages=c,ada,c++,go,brig,d,fortran,objc,obj-c++ --prefix=/usr --with-gcc-major-version-only --program-suffix=-7 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-libmpx --enable-plugin --enable-default-pie --with-system-zlib --with-target-system-zlib --enable-objc-gc=auto --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 7.4.0 (Ubuntu 7.4.0-1ubuntu1~18.04.1)
root#686394c78009:/zcc# cat test1.c
int main() {
return 42;
}
root#686394c78009:/zcc# gcc -o test1 test1.c
root#686394c78009:/zcc# ./test1
root#686394c78009:/zcc# echo $?
42
root#686394c78009:/zcc# objdump -d -M intel ./test1
Update 1
Generated assembly code with the -S option. Compiling worked from the generated assembly code.
Still there are some differences from my reference book but I will learn more.
And one another curious thing is that the different register name is used respectively. I will look into it too. (I have realized I need to learn from basic..)
// expected
mov rax, 42
// actual
mov eax, 42
root#686394c78009:/zcc# gcc -S -masm=intel test1.c
root#686394c78009:/zcc# cat test1.s
.file "test1.c"
.intel_syntax noprefix
.text
.globl main
.type main, #function
main:
.LFB0:
.cfi_startproc
push rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
mov rbp, rsp
.cfi_def_cfa_register 6
mov eax, 42
pop rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Ubuntu 7.4.0-1ubuntu1~18.04.1) 7.4.0"
.section .note.GNU-stack,"",#progbits
root#686394c78009:/zcc# gcc -o test1 test1.s
root#686394c78009:/zcc# ./test1
root#686394c78009:/zcc# echo $?
42
Instead of dumping with objdump, try to directly generate assembly code with the -S option for the compiler. With -masm=intel, the output should look similar to what you expect.
Do not expect the compiler to generate the exact same code though. Different compilers and different compiler versions or even the same compiler with different flags may make different choices and generate different assembly for the same code. That's normal.

logical and physical adress in C code in real mode

Suppose I write boot loader on C. What happens when I create some global variable? What is it's logical address? How does it correspond to physical address? For example if I created some string (global)
const char* s = "some string";
Am I right that s stored in .data section? What would be the physical address of s and what would be a logical one? Should we do some extra work to make this addresses correspond each other.
My OS is Linux and I compile my code like this:
as --32 boot.S -o boot.o
gcc -c -m32 -g -Os -ffreestanding -Wall -Werror -I. -o mbr.o mbr.c
ld -Tlinker.ld -nostdlib -o mbr boot.o mbr.o
boot.S is just where I initilize some registers and call c code:
.code16
.text
.global _start
_start:
cli
xor %ax, %ax
mov %ax, %ds
mov %ax, %es
mov %ax, %ss
mov $0x7c00, %sp
ljmp $0, $mmain
mmain -- function in C code. My linker script is:
OUTPUT_FORMAT(binary)
OUTPUT_ARCH(i8086)
ENTRY(_start)
SECTIONS
{
. = 0x7C00;
.text : { *(.text) }
.sig : AT(0x7DFE)
{
SHORT(0xaa55);
}
}

Assembly function call from c

I cannot combine my kernel_entry.asm and main.c. My main.c calls an asm function Sum. Both nasm and gcc compiles respective files. However, the linker gives an error.
Kernel_entry.asm:
[bits 32]
[extern _start]
[global _Sum]
....
_Sum:
push ebp
mov ebp, esp
mov eax, [ebp+8]
mov ecx, [ebp+12]
add eax, ecx
pop ebp
ret
main.c:
....
extern int Sum();
void start() {
....
int x = Sum(4, 5);
....
}
To compile source files, I use following commands:
nasm kernel_entry.asm -f win32 -o kernel_entry.o
gcc -ffreestanding -c main.c -o main.o
....
ld -T NUL -o kernel.tmp -Ttext 0x1000 kernel_entry.o main.o mem.o port_in_out.o screen.o idt.o
Linker gives following error:main.o:main.c:(.text+0xa82): undifened reference to 'Sum'. I tried everything but couldn't find any solution. When I remove asm function call from main.c, it works.
The TL;DR version of the answer is that mixing nasm's -f win32 generates an object file that is not compatible with the GNU toolchain on Windows - you need to use -f elf if you want to link using ld. That is described in NASM's documentation here under sections 7.5 and 7.9.
The hint for me was that by running nm kernel_entry.o generated:
00000000 a .absolut
00000000 t .text
00000001 a #feat.00
U _start
U _Sum
Which basically shows Sum as an undefined symbol. After compiling as ELF, I got:
U _start
00000000 T _Sum
indicating Sum as a recognised symbol in the text section.

Resources