Page 1 of 1

[SOLVED] GCC 6.3.0 bug ?

Posted: Sun Apr 09, 2017 10:48 am
by Ankeraout
Hello guys,
I just wanna share something with you that I discovered during my keyboard driver's debug phase.

Here is my function to write a byte to the keyboard :

Code: Select all

void Keyboard_writeByte(uint8_t value) {
	while(Keyboard_waitingForAck) {
		hlt;
	}

	Keyboard_waitingForAck = true;
	Keyboard_lastCommand = value;

	PS2_data_write(Keyboard_port, value);
}
In assembly, it gives this (as seen by IDA Pro) :

Code: Select all

.text:08000000 ; void __cdecl Keyboard_writeByte(uint8_t value)
.text:08000000                 public Keyboard_writeByte
.text:08000000 Keyboard_writeByte proc near            ; CODE XREF: Keyboard_init+11p
.text:08000000                                         ; Keyboard_init+1Dp ...
.text:08000000
.text:08000000 value           = dword ptr  4
.text:08000000
.text:08000000                 sub     esp, 0Ch
.text:08000003                 cmp     ds:Keyboard_waitingForAck, 0
.text:0800000A                 mov     eax, [esp+0Ch+value]
.text:0800000E                 jz      short loc_8000013
.text:08000010
.text:08000010 loc_8000010:                            ; CODE XREF: Keyboard_writeByte+11j
.text:08000010                 hlt
.text:08000011 ; ---------------------------------------------------------------------------
.text:08000011                 jmp     short loc_8000010
.text:08000013 ; ---------------------------------------------------------------------------
.text:08000013
.text:08000013 loc_8000013:                            ; CODE XREF: Keyboard_writeByte+Ej
.text:08000013                 sub     esp, 8
.text:08000016                 mov     ds:Keyboard_lastCommand, al
.text:0800001B                 movzx   eax, al
.text:0800001E                 push    eax
.text:0800001F                 push    ds:Keyboard_port
.text:08000025                 mov     ds:Keyboard_waitingForAck, 1
.text:0800002C                 call    PS2_data_write
.text:08000031                 add     esp, 1Ch
.text:08000034                 retn
.text:08000034 Keyboard_writeByte endp
My keyboard ISR sets Keyboard_waitingForAck to false when the keyboard sends an ACK.

But as you can see in the assembly code, it is never going to check if Keyboard_waitingForAck's value has changed, even if in the C code, the while loop should exit if Keyboard_waitingForAck is false.

So I decided to change my C code :

Code: Select all

void Keyboard_writeByte(uint8_t value) {
	while(Keyboard_waitingForAck) {
		Console_write("\0");
		hlt;
	}

	Keyboard_waitingForAck = true;
	Keyboard_lastCommand = value;

	PS2_data_write(Keyboard_port, value);
}
In assembly, it gives that :

Code: Select all

.text:08000000 ; void __cdecl Keyboard_writeByte(uint8_t value)
.text:08000000                 public Keyboard_writeByte
.text:08000000 Keyboard_writeByte proc near            ; CODE XREF: Keyboard_init+11p
.text:08000000                                         ; Keyboard_init+1Dp ...
.text:08000000
.text:08000000 value           = dword ptr  4
.text:08000000
.text:08000000                 push    ebx
.text:08000001                 sub     esp, 8
.text:08000004                 cmp     ds:Keyboard_waitingForAck, 0
.text:0800000B                 mov     ebx, [esp+0Ch+value]
.text:0800000F                 jz      short loc_800003A
.text:08000011                 jmp     short loc_8000020
.text:08000011 ; ---------------------------------------------------------------------------
.text:08000013                 align 10h
.text:08000020
.text:08000020 loc_8000020:                            ; CODE XREF: Keyboard_writeByte+11j
.text:08000020                                         ; Keyboard_writeByte+38j
.text:08000020                 sub     esp, 0Ch
.text:08000023                 push    offset unk_80001A0
.text:08000028                 call    Console_write
.text:0800002D                 hlt
.text:0800002E ; ---------------------------------------------------------------------------
.text:0800002E                 add     esp, 10h
.text:08000031                 cmp     ds:Keyboard_waitingForAck, 0
.text:08000038                 jnz     short loc_8000020
.text:0800003A
.text:0800003A loc_800003A:                            ; CODE XREF: Keyboard_writeByte+Fj
.text:0800003A                 sub     esp, 8
.text:0800003D                 mov     ds:Keyboard_lastCommand, bl
.text:08000043                 movzx   ebx, bl
.text:08000046                 push    ebx
.text:08000047                 push    ds:Keyboard_port
.text:0800004D                 mov     ds:Keyboard_waitingForAck, 1
.text:08000054                 call    PS2_data_write
.text:08000059                 add     esp, 10h
.text:0800005C                 add     esp, 8
.text:0800005F                 pop     ebx
.text:08000060                 retn
.text:08000060 Keyboard_writeByte endp
The call to Console_write() does absolutely nothing, but as GCC does not know what it can do, it checks for Keyboard_waitingForAck because Console_write() could have changed its value (logical).

And guess what, it works !

Do you guys have an idea why GCC is doing this and how I can fix it ?

PS : My compile line is

Code: Select all

i686-elf-gcc -Wall -Wextra -O2 -ffreestanding -nostdlib -g -c -std=gnu99 $< -o $@
And my linking line is

Code: Select all

i686-elf-gcc -T linker.ld -Wall -Wextra -O2 -ffreestanding -lgcc -nostdlib -g

Re: GCC 6.3.0 bug ?

Posted: Sun Apr 09, 2017 11:06 am
by FallenAvatar
Is "Keyboard_waitingForAck" declared as volatile?

- Monk

Re: GCC 6.3.0 bug ?

Posted: Sun Apr 09, 2017 11:08 am
by Ankeraout
No, it was declared immediately after the #include instructions, as global variable.

Code: Select all

bool Keyboard_waitingForAck = false;
(Thanks btw, now I know what volatile is)