0

In the code below I have lines 27-37 that work well and the same code called by a label (line 58) crash when executing the pop instructions. There is another label (line 48) which produces the same result without using pop and this works.

I'm in the context of building a x86_64 operating system.
Compile command : nasm -f elf
Linking command : ld -T link.ld -melf_i386
Iso generated using Grub 2.02 : grub-mkrescue
Run with VirtualBox version 5.2.32_Ubuntur132056

Following pop Instruction not supported in 64-bit mode using NASM? I tried with pop and/or push instructions in uppercase and got same result.

loader:                                   ; the loader label (defined as entry point in linker script)
    mov esp, kernel_stack + STACK_SIZE    ; point esp to the start of the stack (end of memory area)
    push dword 0x71
    push dword 'C'
    push dword 0x50                       ; first pushes to test directly the function
    pop edx
    pop eax
    pop ebx
    mov ah, bl
    mov ebx, FRAMEBUFFER
    add ebx, edx
    mov byte [ebx], al
    mov byte [ebx + 1], ah                ; should print a C with a blue foreground and a light grey background on the 40'th case of the frame buffer
    push dword 0x71
    push dword 'C'
    push dword 0x52
    call fb_write_chara

.loop:
    nop
    jmp .loop                             ; loop forever


fb_write_chara:                            ; void fb_write_char(unsigned int offset, char character, unsigned char color)
    mov ah, [esp + 12]                    ; color
    mov al, [esp + 8]                     ; character
    mov edx, [esp + 4]                    ; offset
    mov ebx, FRAMEBUFFER
    add ebx, edx                          ; ebx is now at the right position
    mov byte [ebx], al                    ; write char
    mov byte [ebx + 1], ah                ; write color
    ret

fb_write_char:                           ; void fb_write_char(unsigned int offset, char character, unsigned char color)
    pop edx
    pop eax
    pop ebx
    mov ah, bl
    mov ebx, FRAMEBUFFER
    add ebx, edx                          ; ebx is now at the right position
    mov byte [ebx], al                    ; write char
    mov byte [ebx + 1], ah                ; write color
    ret

Result when executing with fb_write_chara:

eax=00007143 ebx=000b8052 ecx=00000000 edx=00000052 esi=00000000 edi=00000000
eip=00100033 esp=00101ff4 ebp=00000000 iopl=0 nv up di pl nz na pe nc
cs=0010 ds=0018 es=0018 fs=0018 gs=0018 ss=0018               eflags=00200002
0010:00100033 90                      nop

State of the registers when trying with fb_write_char:

eax=00004352 ebx=001b8033 ecx=00000000 edx=00100033 esi=00000000 edi=00000000
eip=00000077 esp=00101ffc ebp=00000000 iopl=0 rf nv up di pl nz na pe nc
cs=0010 ds=0018 es=0018 fs=0018 gs=0018 ss=0018               eflags=00210002
0010:00000077 f0 c7 ef 00 f0 ed 57    Illegal opcode
Nonoreve
  • 115
  • 1
  • 11

1 Answers1

0

CALL pushes the return address (.loop in your case) before jumping to fb_write_char. So your first POP pops the return address. When RET runs, it uses the only thing left on the stack, which is 0x71 in your case, as the return address. Of course the problem will crashes.

When you use stack to pass parameters, use [ESP + 4] to access the last pushed parameter, [ESP + 8] to access the second-last pushed parameter, and so on. To clean up the stack, use RET 12 (callee cleanup) or use RET and ADD ESP, 12 after CALL (caller cleanup).

Read more about call stack before you continue to code in assembly: https://en.wikipedia.org/wiki/Call_stack

W. Chang
  • 494
  • 3
  • 10