Page 1 of 1

extern char getkb() apparently has no effect(MEATY SKELETON)

Posted: Mon Feb 08, 2016 2:38 pm
by bilsch01
Please see the modified version of file tty.c below from MEATY SKELETON.
This question concerns 1) the statement at the beginning:
extern char getkb();
and 2) the third function from the bottom: void terminal_getkb(void).

Label getkb is the entry point to an assembly routine.
The function line: c = getkb()
gets the error: undefined reference to `getkb'
as though the statement: extern char getkb() has no effect.
It should not get that error even if the assembly routine is deleted.

If the compile or link lines in the makefile were wrong I would expect
a different message like: file foo.bar not found. I suspect I cannot
use the line: extern char getkb(void) in this code because it violates
something about these OS programming files.
MY QUESTION: why the error: undefined reference to getkb

TIA Bill S.


#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <kernel/vga.h>

extern char getkb(void);
char c='A';

size_t terminal_row;
size_t terminal_column;
uint8_t terminal_color;
uint16_t* terminal_buffer;

void terminal_initialize(void)
{
terminal_row = 0;
terminal_column = 0;
terminal_color = make_color(COLOR_MAGENTA, COLOR_BLACK);
terminal_buffer = VGA_MEMORY;
for ( size_t y = 0; y < VGA_HEIGHT; y++ )
{
for ( size_t x = 0; x < VGA_WIDTH; x++ )
{
const size_t index = y * VGA_WIDTH + x;
terminal_buffer[index] = make_vgaentry(' ', terminal_color);
}
}
}

void scrolldn(){
for (size_t i = 0; i<VGA_WIDTH*VGA_HEIGHT; i++)
terminal_buffer = terminal_buffer[i+VGA_WIDTH];
}

void terminal_setcolor(uint8_t color)
{
terminal_color = color;
}

void terminal_putentryat(char c, uint8_t color, size_t x, size_t y)
{
const size_t index = y * VGA_WIDTH + x;
terminal_buffer[index] = make_vgaentry(c, color);
}

void terminal_putchar(char c) {
if (c != '\n'){
terminal_putentryat(c, terminal_color, terminal_column, terminal_row);
if (++terminal_column == VGA_WIDTH) {
terminal_column = 0;
if (++terminal_row == VGA_HEIGHT)
scrolldn();
}
}
else
{
terminal_column = 0;
terminal_row++;
if (terminal_row == VGA_HEIGHT)
scrolldn();
}
}

void terminal_getkb(void)
{
while (1)
{ c = getkb();
terminal_putchar(c);
}
}

void terminal_write(const char* data, size_t size)
{
for ( size_t i = 0; i < size; i++ )
terminal_putchar(data);
}

//void terminal_writestring(const char* data)
//{
// terminal_write(data, strlen(data));
//}

Re: extern char getkb() apparently has no effect(MEATY SKELE

Posted: Mon Feb 08, 2016 2:51 pm
by Roman
"undefined reference" is a linker error, not a compiler error. It has nothing to do with your C code directly. It means that there is an unresolved symbol during linking.

Re: extern char getkb() apparently has no effect(MEATY SKELE

Posted: Tue Feb 09, 2016 4:14 am
by bilsch01
The assembly file is as follows:

Code: Select all

;	kb1.asm		nasm -f elf32 kb1.asm -o kb1.o
global getkb

SECTION	.text

getkb:
		push bp
		mov bp,sp
lup2:
		mov cx,0xffff
lup1:
		dec cx
		nop
		nop
		nop
		cmp cx,0	;0 means 65536 loops
		jne lup1
		mov ah,1	;check for key
		int 0x16
		jnz lup2	;zf=1 if no key avail
		mov ah,0
		int 0x16	;get ASCII byte in al
		pop bp
		iret
And the pertinent lines from the makefile are:

Code: Select all

#  this rule added by bilsch01
$(ARCHDIR)/tty.o: $(ARCHDIR)/kb1.o $(ARCHDIR)/tty.o
	i686-elf-gcc -c $(ARCHDIR)/kb1.o $(ARCHDIR)/tty.o -o $(ARCHDIR)/tty.o $(CFLAGS) $(CPPFLAGS)

myos.kernel: $(OBJ_LINK_LIST) $(ARCHDIR)/linker.ld
	$(CC) -T $(ARCHDIR)/linker.ld -o $@ $(CFLAGS) $(OBJ_LINK_LIST) $(LDFLAGS) $(LIBS)

%.o: %.c
	$(CC) -c $< -o $@ -std=gnu11 $(CFLAGS) $(CPPFLAGS)

%.o: %.S
	$(CC) -c $< -o $@ $(CFLAGS) $(CPPFLAGS)
The added line results in a newer tty.o than the version of tty.c therefore the newer tty.o does not get recompiled (thus not wiped out) by the next rule - as desired.

I do not see why the build gets the error: 'undefined reference to getkb'

Re: extern char getkb() apparently has no effect(MEATY SKELE

Posted: Tue Feb 09, 2016 6:00 am
by iansjack
What is your OBJ_LINK_LIST?

Re: extern char getkb() apparently has no effect(MEATY SKELE

Posted: Tue Feb 09, 2016 9:16 am
by bilsch01
OBJ_LINK_LIST:=\

$(CRTI_OBJ) \
$(CRTBEGIN_OBJ) \
$(OBJS) \
$(CRTEND_OBJ) \
$(CRTN_OBJ) \

which is:

myos/kernel/arch/i386/crti.o \
i686-elf-gcc $(CFLAGS) $(LDFLAGS) -print-file-name=crtbegin.o) \
myos/kernel/arch/i386/boot.o \
myos/kernel/arch/i386/tty.o \
myos/kernel/kernel/kernel.o \
i686-elf-gcc $(CFLAGS) $(LDFLAGS) -print-file-name=crtend.o) \
myos/kernel/arch/i386/crtn.o

Re: extern char getkb() apparently has no effect(MEATY SKELE

Posted: Tue Feb 09, 2016 9:21 am
by Roman
Obviously, you're missing kb1.o. By the way, your assembly code won't work, because BIOS interrupts are not available in 32-bit protected mode.

Re: extern char getkb() apparently has no effect(MEATY SKELE

Posted: Tue Feb 09, 2016 10:04 am
by bilsch01
Ok. adding kb1.o works. Thanks. One more question: I'm not in protected mode yet so I expect this (still) real mode system to get my keyboard input and display it on the screen - just for the hell of it. But it doesn't do it.

Re: extern char getkb() apparently has no effect(MEATY SKELE

Posted: Tue Feb 09, 2016 10:07 am
by FallenAvatar
If you are writing C code, you are in protected mode. If you aren't in protected mode, you can't use C.

- Monk

P.S. There are ways to write real mode C, all of which are out of date, broken, or just not recommended.

Re: extern char getkb() apparently has no effect(MEATY SKELE

Posted: Tue Feb 09, 2016 11:44 am
by Roman
The "Meaty skeleton" tutorial uses GRUB, which enables protected mode before booting a multiboot-compliant kernel. Although, you still must setup your own GDT, because the GDT setup by GRUB is unreliable.