Search code examples
cx86ldosdev

ld makes wrong call instruction


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.


Solution

  • There was no problem, I used bad options with ndisasm.