链接器错误:对'user_input'的未定义引用

时间:2017-03-10 05:43:17

标签: c linker kernel

我正在编写James M教程之后的内核,最近我添加了一个键盘驱动程序(来自bkerndev教程)以实现一个简单的shell。键盘驱动程序以前工作得很好,直到我添加了一种识别用户输入线的方法。它基本上只是将输入行作为字符串写入数组,然后将其用作文件'kernel.c中的'input'变量。但是,当我编译代码时,我从链接器收到以下错误:

keyboard.c:(.text+0x8c): undefined reference to `user_input'

引用在文件'kernel.h'中定义。

keyboard.c中

#include <kstdio.h>
#include <isr.h>
#include <keyboard.h>
#include <kernel.h>

u32int shiftKey;
static char letter;
static char upLetter;

static char key_buffer[256]; // The buffer line

#define RSHIFT    0x80 - 42
#define LSHIFT    0x80 - 54
#define ENTER     0x1C
#define BACKSPACE 0x0E

// kbdus is the scancode tables for English US
unsigned char kbdus[128] =
{
    0,  27, '1', '2', '3', '4', '5', '6', '7', '8', /* 9 */
  '9', '0', '-', '=', '\b', /* Backspace */
  '\t',         /* Tab */
  'q', 'w', 'e', 'r',   /* 19 */
  't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n', /* Enter key */
    0,          /* 29   - Control */
  'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', /* 39 */
 '\'', '`',   0,        /* Left shift */
 '\\', 'z', 'x', 'c', 'v', 'b', 'n',            /* 49 */
  'm', ',', '.', '/',   0,              /* Right shift */
  '*',
    0,  /* Alt */
  ' ',  /* Space bar */
    0,  /* Caps lock */
    0,  /* 59 - F1 key ... > */
    0,   0,   0,   0,   0,   0,   0,   0,
    0,  /* < ... F10 */
    0,  /* 69 - Num lock*/
    0,  /* Scroll Lock */
    0,  /* Home key */
    0,  /* Up Arrow */
    0,  /* Page Up */
  '-',
    0,  /* Left Arrow */
    0,
    0,  /* Right Arrow */
  '+',
    0,  /* 79 - End key*/
    0,  /* Down Arrow */
    0,  /* Page Down */
    0,  /* Insert Key */
    0,  /* Delete Key */
    0,   0,   0,
    0,  /* F11 Key */
    0,  /* F12 Key */
    0,  /* All other keys are undefined */
};

unsigned char upkbdus[128] =
{
    0,  27, '!', '@', '#', '$', '%', '^', '&', '*', /* 9 */
  '(', ')', '_', '+', '\b', /* Backspace */
  '\t',         /* Tab */
  'Q', 'W', 'E', 'R',   /* 19 */
  'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', '\n', /* Enter key */
    0,          /* 29   - Control */
  'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', /* 39 */
 '\'', '`',   0,        /* Left shift */
 '\\', 'Z', 'X', 'C', 'V', 'B', 'N',            /* 49 */
  'M', ',', '.', '/',   0,              /* Right shift */
  '*',
    0,  /* Alt */
  ' ',  /* Space bar */
    0,  /* Caps lock */
    0,  /* 59 - F1 key ... > */
    0,   0,   0,   0,   0,   0,   0,   0,
    0,  /* < ... F10 */
    0,  /* 69 - Num lock*/
    0,  /* Scroll Lock */
    0,  /* Home key */
    0,  /* Up Arrow */
    0,  /* Page Up */
  '-',
    0,  /* Left Arrow */
    0,
    0,  /* Right Arrow */
  '+',
    0,  /* 79 - End key*/
    0,  /* Down Arrow */
    0,  /* Page Down */
    0,  /* Insert Key */
    0,  /* Delete Key */
    0,   0,   0,
    0,  /* F11 Key */
    0,  /* F12 Key */
    0,  /* All other keys are undefined */
};              

/* Handles the keyboard interrupt */
void keyboard_handler(struct regs *r)
{
    unsigned char scancode;

    /* Read from the keyboard's data buffer */
    scancode = inb(0x60);

    /* If the top bit of the byte we read from the keyboard is
    *  set, that means that a key has just been released */
    if (scancode & 0x80)
    {
        if (scancode == LSHIFT || scancode == RSHIFT) {
            shiftKey = 1;
        }
        else {
            shiftKey = 0;
        }
    }
    else
    {
        letter = kbdus[scancode];
        upLetter = upkbdus[scancode];

        /* Here, a key was just pressed. Please note that if you
        *  hold a key down, you will get repeated key press
        *  interrupts. */

        /* Just to show you how this works, we simply translate
        *  the keyboard scancode into an ASCII value, and then
        *  display it to the screen. You can get creative and
        *  use some flags to see if a shift is pressed and use a
        *  different layout, or you can add another 128 entries
        *  to the above layout to correspond to 'shift' being
        *  held. If shift is held using the larger lookup table,
        *  you would add 128 to the scancode when you look for it */
        if (scancode == BACKSPACE) {
        backspace(key_buffer);
    } else if (scancode == ENTER) {
        user_input(key_buffer);
        kprintf("\n");
        key_buffer[0] = '\0';
    } else {
        /* Remember that kprint only accepts char[] */
        char str[2] = {letter, '\0'};
        append(key_buffer, letter);
        kprintf(str);
    }


        /* if (shiftKey == 0) {
            kputc(letter);
        }
        else if (shiftKey == 1) {
            kputc(upLetter);
        } */
    }
}

void keyboard_install() {
    register_interrupt_handler(IRQ1, &keyboard_handler);
}

keyboard.h

#ifndef KEYBOARD_H
#define KEYBOARD_H

void keyboard_install();

#endif

kernel.h当

#ifndef KERNEL_H
#define KERNEL_H

#include <keyboard.h>

void user_input(char *input);

#endif

生成文件

# Makefile for Sierra Kernel
# The C and C++ rules are already setup by default.
# The only one that needs changing is the assembler
# rule, as we use nasm instead of GNU as.
DESTDIR?=
INCLUDEDIR?=include
PREFIX?=/usr/local
EXEC_PREFIX?=$(PREFIX)
BOOTDIR?=$(EXEC_PREFIX)/boot

export AR=/Users/development/opt/cross/bin/i386-elf-ar
export AS=/Users/development/opt/cross/bin/i386-elf-as
export CC=/Users/development/opt/cross/bin/i386-elf-gcc
export GDB=/Users/development/opt/cross/bin/i386-elf-gdb

CFLAGS=-nostdlib -nostdinc -fno-builtin -I include
LDFLAGS=-Tlink.ld
ASFLAGS=-felf

SOURCES=boot/boot.o drivers/halt.o drivers/kstdio/screen.o drivers/kstdio/io.o kernel/sierra/kernel.o \
                kernel/tables/gdt.o kernel/tables/tables.o kernel/tables/isr.o kernel/timer.o kernel/tables/inter.o \
                drivers/keyboard.o

all: $(SOURCES) link

clean:
    rm -rf boot/*.o drivers/*.o drivers/kstdio/*.o kernel/sierra/*.o kernel/tables/*.o \
    *.o kernel/*.o *.kernel

link:
    /Users/development/opt/cross/i386-elf/bin/ld $(LDFLAGS) -o sierra.kernel $(SOURCES)

.s.o:
    nasm $(ASFLAGS) $<

install: install-headers install-kernel

install-headers:
    mkdir -p $(DESTDIR)$(INCLUDEDIR)
    cp -R --preserve=timestamps include/. $(DESTDIR)$(INCLUDEDIR)/.

install-kernel:
    mkdir -p $(DESTDIR)$(BOOTDIR)
    cp kernel $(DESTDIR)$(BOOTDIR)

image:
    ./update_image.sh

run:
    qemu-system-i386 -fda system.img

bundle:
    make clean
    make 
    make image
    make run

mac:
    make clean
    make

整个项目来源可在此处获取:https://github.com/sofferjacob/Sierra-Kernel/tree/testing

感谢您的帮助。

顺便说一句我在Ubuntu 16.10中使用交叉编译工具链(有时我在macOS 10.12中使用相同的工具链,但通常是Ubuntu)来编译内核。

1 个答案:

答案 0 :(得分:0)

对kernel.c的这一改变解决了它:

#include <kstdio.h>
#include <tables.h>
#include <timer.h>
#include <keyboard.h>
#include <keyboard.h>

extern int is_kernel = 0;
extern int is_user = 0;

int kernel_main(struct multiboot *mboot_ptr, u32int initial_stack) {
  is_kernel = 1;
  is_user   = 0;
  tables_int(); // Initialise all descriptor tables
  clear_screen(); // Initialise the screen.
  asm volatile("sti");
  timer_init(100); // Initialise timer to 100Hz (This MUST ALWAYS be set to 100 or bad things will happen)
  kprintf("System sucessfully initialised \n");
  show_system_time();
  kprintf("Welcome to Sierra Kernel! v.1.0 \n");
  keyboard_install();
}

void user_input(char *input) {
  if (strcmp(input, "test") == 0) {
    kprintf("TEST \n");
  }
  else {
    kprintf("ERROR \n");
    }
    kprintf("# ");
  }