I'm trying to make a small kernel, so far i've gotten to protected mode with A20 enabled, GDT loaded and kernel loaded from disk. In C i've tried function calls, but for some reason ld makes a wrong call instruction. Here is the C code:
asm(".code32");
int a(int *d);
int main() {
int c = 0;
c = a(&c);
c = a(&c);
c = a(&c);
while(1);
}
int a(int *d) {
int b = 1;
b *= 5;
b *= 7;
b -= 6;
b *= 9;
*d = b;
return b;
}
My makefile (reduced) is:
KERNEL-PARTFILE = int/parts/detailed-boot.prt
KERNEL-OBJECTFILE = int/detailed-boot.o
KERNEL-SOURCEFILE = src/detailed-boot.c
GCC = ~/opt/cross/bin/i686-elf-gcc
LD = ~/opt/cross/bin/i686-elf-ld
VM = qemu-system-x86_64
SYSFILE = lizard.bin
kernel:
$(GCC) -ffunction-sections -ffreestanding $(KERNEL-SOURCEFILE) -o $(KERNEL-OBJECTFILE) -nostdlib -Wall -Wextra -O0
$(LD) -o $(KERNEL-PARTFILE) -Ttext 0x7e00 --oformat binary $(KERNEL-OBJECTFILE) -e main --script=LDfile -O 0 -Ttext-segment 0x7e00 --verbose
run:
$(VM) $(SYSFILE)
debug:
$(VM) $(SYSFILE) -gdb tcp:localhost:6000 -S
LDfile:
ENTRY(main)
SECTIONS {
. = 0x7e00;
.text . : { *(.text) }
.data . : { *(.data) }
.bss . : { *(.bss ) }
}
The issue is in the linking. Running objdump
(cross compiled) on int/detailed-boot.o
produces:
int/detailed-boot.o: file format elf32-i386
Disassembly of section .text:
08048054 <main>:
8048054: 8d 4c 24 04 lea 0x4(%esp),%ecx
8048058: 83 e4 f0 and $0xfffffff0,%esp
804805b: ff 71 fc push -0x4(%ecx)
804805e: 55 push %ebp
804805f: 89 e5 mov %esp,%ebp
8048061: 51 push %ecx
8048062: 83 ec 14 sub $0x14,%esp
8048065: c7 45 f4 00 00 00 00 movl $0x0,-0xc(%ebp)
804806c: 83 ec 0c sub $0xc,%esp
804806f: 8d 45 f4 lea -0xc(%ebp),%eax
8048072: 50 push %eax
8048073: e8 2d 00 00 00 call 80480a5 <a>
8048078: 83 c4 10 add $0x10,%esp
804807b: 89 45 f4 mov %eax,-0xc(%ebp)
804807e: 83 ec 0c sub $0xc,%esp
8048081: 8d 45 f4 lea -0xc(%ebp),%eax
8048084: 50 push %eax
8048085: e8 1b 00 00 00 call 80480a5 <a>
804808a: 83 c4 10 add $0x10,%esp
804808d: 89 45 f4 mov %eax,-0xc(%ebp)
8048090: 83 ec 0c sub $0xc,%esp
8048093: 8d 45 f4 lea -0xc(%ebp),%eax
8048096: 50 push %eax
8048097: e8 09 00 00 00 call 80480a5 <a>
804809c: 83 c4 10 add $0x10,%esp
804809f: 89 45 f4 mov %eax,-0xc(%ebp)
80480a2: 90 nop
80480a3: eb fd jmp 80480a2 <main+0x4e>
080480a5 <a>:
80480a5: 55 push %ebp
80480a6: 89 e5 mov %esp,%ebp
80480a8: 83 ec 10 sub $0x10,%esp
80480ab: c7 45 fc 01 00 00 00 movl $0x1,-0x4(%ebp)
80480b2: 8b 55 fc mov -0x4(%ebp),%edx
80480b5: 89 d0 mov %edx,%eax
80480b7: c1 e0 02 shl $0x2,%eax
80480ba: 01 d0 add %edx,%eax
80480bc: 89 45 fc mov %eax,-0x4(%ebp)
80480bf: 8b 55 fc mov -0x4(%ebp),%edx
80480c2: 89 d0 mov %edx,%eax
80480c4: c1 e0 03 shl $0x3,%eax
80480c7: 29 d0 sub %edx,%eax
80480c9: 89 45 fc mov %eax,-0x4(%ebp)
80480cc: 83 6d fc 06 subl $0x6,-0x4(%ebp)
80480d0: 8b 55 fc mov -0x4(%ebp),%edx
80480d3: 89 d0 mov %edx,%eax
80480d5: c1 e0 03 shl $0x3,%eax
80480d8: 01 d0 add %edx,%eax
80480da: 89 45 fc mov %eax,-0x4(%ebp)
80480dd: 8b 45 08 mov 0x8(%ebp),%eax
80480e0: 8b 55 fc mov -0x4(%ebp),%edx
80480e3: 89 10 mov %edx,(%eax)
80480e5: 8b 45 fc mov -0x4(%ebp),%eax
80480e8: c9 leave
80480e9: c3 ret
Nothing unusual. Running ndisasm
on int/parts/detailed-boot.prt
produces:
00000000 8D4C24 lea cx,[si+0x24]
00000003 0483 add al,0x83
00000005 E4F0 in al,0xf0
00000007 FF71FC push word [bx+di-0x4]
0000000A 55 push bp
0000000B 89E5 mov bp,sp
0000000D 51 push cx
0000000E 83EC14 sub sp,byte +0x14
00000011 C745F40000 mov word [di-0xc],0x0
00000016 0000 add [bx+si],al
00000018 83EC0C sub sp,byte +0xc
0000001B 8D45F4 lea ax,[di-0xc]
0000001E 50 push ax
0000001F E82D00 call 0x4f
00000022 0000 add [bx+si],al
00000024 83C410 add sp,byte +0x10
00000027 8945F4 mov [di-0xc],ax
0000002A 83EC0C sub sp,byte +0xc
0000002D 8D45F4 lea ax,[di-0xc]
00000030 50 push ax
00000031 E81B00 call 0x4f
00000034 0000 add [bx+si],al
00000036 83C410 add sp,byte +0x10
00000039 8945F4 mov [di-0xc],ax
0000003C 83EC0C sub sp,byte +0xc
0000003F 8D45F4 lea ax,[di-0xc]
00000042 50 push ax
00000043 E80900 call 0x4f
00000046 0000 add [bx+si],al
00000048 83C410 add sp,byte +0x10
0000004B 8945F4 mov [di-0xc],ax
0000004E 90 nop
0000004F EBFD jmp short 0x4e
00000051 55 push bp
00000052 89E5 mov bp,sp
00000054 83EC10 sub sp,byte +0x10
00000057 C745FC0100 mov word [di-0x4],0x1
0000005C 0000 add [bx+si],al
0000005E 8B55FC mov dx,[di-0x4]
00000061 89D0 mov ax,dx
00000063 C1E002 shl ax,byte 0x2
00000066 01D0 add ax,dx
00000068 8945FC mov [di-0x4],ax
0000006B 8B55FC mov dx,[di-0x4]
0000006E 89D0 mov ax,dx
00000070 C1E003 shl ax,byte 0x3
00000073 29D0 sub ax,dx
00000075 8945FC mov [di-0x4],ax
00000078 836DFC06 sub word [di-0x4],byte +0x6
0000007C 8B55FC mov dx,[di-0x4]
0000007F 89D0 mov ax,dx
00000081 C1E003 shl ax,byte 0x3
00000084 01D0 add ax,dx
00000086 8945FC mov [di-0x4],ax
00000089 8B4508 mov ax,[di+0x8]
0000008C 8B55FC mov dx,[di-0x4]
0000008F 8910 mov [bx+si],dx
00000091 8B45FC mov ax,[di-0x4]
00000094 C9 leave
00000095 C3 ret
Note the following:
0000001F E82D00 call 0x4f
00000031 E81B00 call 0x4f
00000043 E80900 call 0x4f
0000004E 90 nop
0000004F EBFD jmp short 0x4e
The call instructions go to 4F
, the infinite loop! They should go to 51
, the function .
I followed the osdev.org cross compiler tutorial (https://wiki.osdev.org/GCC_Cross-Compiler), using i686-elf
and ~/opt/cross
.
If you need more info, I have a github repository public (https://github.com/saltq144/lizard)
Edit:
Running ndisasm -b 32
shows correct results. I'll finish my GDT and see what happens.
Edit 2:
After finishing my GDT, i tried make debug
. QEMU still jumps to 4F, not 51.
There was no problem, I used bad options with ndisasm.