undefined reference to function, despite giving reference in c

Posted by Jamie Edwards on Stack Overflow See other posts from Stack Overflow or by Jamie Edwards
Published on 2012-04-08T22:25:22Z Indexed on 2012/04/08 23:30 UTC
Read the original article Hit count: 331

Filed under:
|

I'm following a tutorial, but when it comes to compiling and linking the code I get the following error:

/tmp/cc8gRrVZ.o: In function `main':
main.c:(.text+0xa): undefined reference to `monitor_clear'
main.c:(.text+0x16): undefined reference to `monitor_write'
collect2: ld returned 1 exit status
make: *** [obj/main.o] Error 1

What that is telling me is that I haven't defined both 'monitor_clear' and 'monitor_write'. But I have, in both the header and source files.

They are as follows:

monitor.c:

// monitor.c -- Defines functions for writing to the monitor.
//             heavily based on Bran's kernel development tutorials,
//             but rewritten for JamesM's kernel tutorials.

#include "monitor.h"

// The VGA framebuffer starts at 0xB8000.
u16int *video_memory = (u16int *)0xB8000;
// Stores the cursor position.
u8int cursor_x = 0;
u8int cursor_y = 0;

// Updates the hardware cursor.
static void move_cursor()
{
    // The screen is 80 characters wide...
    u16int cursorLocation = cursor_y * 80 + cursor_x;
    outb(0x3D4, 14);                  // Tell the VGA board we are setting the high cursor byte.
    outb(0x3D5, cursorLocation >> 8); // Send the high cursor byte.
    outb(0x3D4, 15);                  // Tell the VGA board we are setting the low cursor byte.
    outb(0x3D5, cursorLocation);      // Send the low cursor byte.
}

// Scrolls the text on the screen up by one line.
static void scroll()
{

    // Get a space character with the default colour attributes.
    u8int attributeByte = (0 /*black*/ << 4) | (15 /*white*/ & 0x0F);
    u16int blank = 0x20 /* space */ | (attributeByte << 8);

    // Row 25 is the end, this means we need to scroll up
    if(cursor_y >= 25)
    {
        // Move the current text chunk that makes up the screen
        // back in the buffer by a line
        int i;
        for (i = 0*80; i < 24*80; i++)
        {
            video_memory[i] = video_memory[i+80];
        }

        // The last line should now be blank. Do this by writing
        // 80 spaces to it.
        for (i = 24*80; i < 25*80; i++)
        {
            video_memory[i] = blank;
        }
        // The cursor should now be on the last line.
        cursor_y = 24;
        }
    }

    // Writes a single character out to the screen.
    void monitor_put(char c)
    {
        // The background colour is black (0), the foreground is white (15).
        u8int backColour = 0;
        u8int foreColour = 15;

        // The attribute byte is made up of two nibbles - the lower being the 
        // foreground colour, and the upper the background colour.
        u8int  attributeByte = (backColour << 4) | (foreColour & 0x0F);
        // The attribute byte is the top 8 bits of the word we have to send to the
        // VGA board.
        u16int attribute = attributeByte << 8;
        u16int *location;

        // Handle a backspace, by moving the cursor back one space
        if (c == 0x08 && cursor_x)
        {
            cursor_x--;
        }

        // Handle a tab by increasing the cursor's X, but only to a point
        // where it is divisible by 8.
        else if (c == 0x09)
        {
              cursor_x = (cursor_x+8) & ~(8-1);
        }

        // Handle carriage return
        else if (c == '\r')
        {
            cursor_x = 0;
        }

       // Handle newline by moving cursor back to left and increasing the row
       else if (c == '\n')
       {
            cursor_x = 0;
            cursor_y++;
       }
       // Handle any other printable character.
       else if(c >= ' ')
       {
           location = video_memory + (cursor_y*80 + cursor_x);
           *location = c | attribute;
           cursor_x++;
       }

       // Check if we need to insert a new line because we have reached the end
       // of the screen.
       if (cursor_x >= 80)
       {
           cursor_x = 0;
           cursor_y ++;
       }

       // Scroll the screen if needed.
       scroll();
       // Move the hardware cursor.
       move_cursor();

}

// Clears the screen, by copying lots of spaces to the framebuffer.
void monitor_clear()
{
    // Make an attribute byte for the default colours
    u8int attributeByte = (0 /*black*/ << 4) | (15 /*white*/ & 0x0F);
    u16int blank = 0x20 /* space */ | (attributeByte << 8);

    int i;
    for (i = 0; i < 80*25; i++)
    {
         video_memory[i] = blank;
    }

    // Move the hardware cursor back to the start.
    cursor_x = 0;
    cursor_y = 0;
    move_cursor();
}

// Outputs a null-terminated ASCII string to the monitor.
void monitor_write(char *c)
{
    int i = 0;
    while (c[i])
    {
        monitor_put(c[i++]);
    }
}

void monitor_write_hex(u32int n)
{
    s32int tmp;

    monitor_write("0x");

    char noZeroes = 1;

    int i;
    for (i = 28; i > 0; i -= 4)
    {
        tmp = (n >> i) & 0xF;
        if (tmp == 0 && noZeroes != 0)
        {
            continue;
        }

        if (tmp >= 0xA)
        {
            noZeroes = 0;
            monitor_put (tmp-0xA+'a' );
        }
        else
        {
            noZeroes = 0;
            monitor_put( tmp+'0' );
        }
    }

    tmp = n & 0xF;
    if (tmp >= 0xA)
    {
         monitor_put (tmp-0xA+'a');
    }
    else
    {
        monitor_put (tmp+'0');
    }

}

void monitor_write_dec(u32int n)
{

    if (n == 0)
    {
        monitor_put('0');
        return;
    }

    s32int acc = n;
    char c[32];
    int i = 0;
    while (acc > 0)
    {
        c[i] = '0' + acc%10;
        acc /= 10;
        i++;
    }
    c[i] = 0;

    char c2[32];
    c2[i--] = 0;
    int j = 0;
    while(i >= 0)
    {
         c2[i--] = c[j++];
    }
    monitor_write(c2);

}

monitor.h:

// monitor.h -- Defines the interface for monitor.h
//              From JamesM's kernel development tutorials.

#ifndef MONITOR_H
#define MONITOR_H

#include "common.h"

// Write a single character out to the screen.
void monitor_put(char c);

// Clear the screen to all black.
void monitor_clear();

// Output a null-terminated ASCII string to the monitor.
void monitor_write(char *c);

#endif // MONITOR_H

common.c:

// common.c -- Defines some global functions.
//             From JamesM's kernel development tutorials.

#include "common.h"

// Write a byte out to the specified port.
void outb ( u16int port, u8int value )
{
        asm volatile ( "outb %1, %0"  : : "dN" ( port ), "a" ( value ) );
}

u8int inb ( u16int port )
{
    u8int ret;
asm volatile ( "inb %1, %0" : "=a" ( ret ) : "dN" ( port ) );
return ret;
}

u16int inw ( u16int port )
{
u16int ret;
asm volatile ( "inw %1, %0" : "=a" ( ret ) : "dN" ( port ) );
return ret;
}

// Copy len bytes from src to dest.
void memcpy(u8int *dest, const u8int *src, u32int len)
{
const u8int *sp = ( const u8int * ) src;
u8int *dp = ( u8int * ) dest;
for ( ; len != 0; len-- ) *dp++ =*sp++;
}

// Write len copies of val into dest.
void memset(u8int *dest, u8int val, u32int len)
{
u8int *temp = ( u8int * ) dest;
for ( ; len != 0; len-- ) *temp++ = val;
}

// Compare two strings. Should return -1 if 
// str1 < str2, 0 if they are equal or 1 otherwise.
int strcmp(char *str1, char *str2)
{
int i = 0;
int failed = 0;
while ( str1[i] != '\0' && str2[i] != '\0' )
{
    if ( str1[i] != str2[i] )
    {
        failed = 1;
        break;
    }
    i++;
}
// Why did the loop exit?
if ( ( str1[i] == '\0' && str2[i] != '\0' || (str1[i] != '\0' && str2[i] =='\0' ) )
    failed =1;

return failed;
}

// Copy the NULL-terminated string src into dest, and
// return dest.
char *strcpy(char *dest, const char *src)
{
do
{
    *dest++ = *src++;
}
while ( *src != 0 );
}

// Concatenate the NULL-terminated string src onto
// the end of dest, and return dest.
char *strcat(char *dest, const char *src)
{
while ( *dest != 0 )
{
    *dest = *dest++;
}

do 
{
    *dest++ = *src++;
}
while ( *src != 0 );

return dest;
}

common.h:

// common.h -- Defines typedefs and some global functions.
//             From JamesM's kernel development tutorials.

#ifndef COMMON_H
#define COMMON_H

// Some nice typedefs, to standardise sizes across platforms.
// These typedefs are written for 32-bit x86.
typedef unsigned    int     u32int;
typedef         int         s32int;
typedef unsigned    short           u16int;
typedef         short       s16int;
typedef unsigned    char        u8int;
typedef         char            s8int;

void outb ( u16int port, u8int value );
u8int inb ( u16int port );
u16int inw ( u16int port );

#endif //COMMON_H

main.c:

// main.c -- Defines the C-code kernel entry point, calls initialisation routines.
//           Made for JamesM's tutorials <www.jamesmolloy.co.uk>

#include "monitor.h"

int main(struct multiboot *mboot_ptr)
{
    monitor_clear();

monitor_write ( "hello, world!" );

return 0;
}

here is my makefile:

C_SOURCES=  main.c monitor.c common.c
S_SOURCES= boot.s
C_OBJECTS=$(patsubst %.c, obj/%.o, $(C_SOURCES))
S_OBJECTS=$(patsubst %.s, obj/%.o, $(S_SOURCES))
CFLAGS=-nostdlib -nostdinc -fno-builtin -fno-stack-protector -m32 -Iheaders
LDFLAGS=-Tlink.ld -melf_i386 --oformat=elf32-i386
ASFLAGS=-felf

all: kern/kernel

.PHONY: clean
clean:
-rm -f kern/kernel

kern/kernel: $(S_OBJECTS) $(C_OBJECTS)
ld $(LDFLAGS) -o $@ $^

$(C_OBJECTS): obj/%.o : %.c 
gcc $(CFLAGS) $< -o $@

vpath %.c source

$(S_OBJECTS): obj/%.o : %.s
    nasm $(ASFLAGS) $< -o $@

vpath %.s asem

Hopefully this will help you understand what is going wrong and how to fix it :L

Thanks in advance.

Jamie.

© Stack Overflow or respective owner

Related posts about c

    Related posts about undefined

    • Error in running script [closed]

      as seen on Programmers - Search for 'Programmers'
      I'm trying to run heathusf_v1.1.0.tar.gz found here I installed tcsh to make build_heathusf work. But, when I run ./build_heathusf, I get the following (I'm running that on a Fedora Linux system from Terminal): $ ./build_heathusf Compiling programs to build a library of image processing functions… >>> More

    • Not able to compile dbus-ping-pong

      as seen on Ask Ubuntu - Search for 'Ask Ubuntu'
      I have downloaded files from http://cgit.collabora.com/git/user/alban/dbus-ping-pong.git/tree/ I am trying to compile it using the command gcc pkg-config --libs --cflags dbus-1 dbus-glib-1-2 glib-2.0 -o dbus-ping-pong dbus-ping-pong.c However, I get errors: /tmp/ccmJkxXb.o: In function g_once_init_enter: dbus-ping-pong… >>> More

    • Qt Linking Error.

      as seen on Stack Overflow - Search for 'Stack Overflow'
      Hi, I configure qt-x11 with following options ./configure -prefix /iTalk/qtx11 -prefix-install -bindir /iTalk/qtx11-install/bin -libdir /iTalk/qtx11-install/lib -docdir /iTalk/qtx11-install/doc -headerdir /iTalk/qtx11-install/include -datadir /iTalk/qtx11-install/data -examplesdir /iTalk/qtx11-install/examples… >>> More

    • QtOpenCl make errors. Please help.

      as seen on Stack Overflow - Search for 'Stack Overflow'
      So I downloaded the ATI Stream SDK. I don't have a gpu now so I use the '-device cpu' and got the programs/examples in the OpenCl directory working by adding the directory to LD_LIBRARY_PATH etc. Now the problem is when installing QtOpenCl. configure script gives me: skkard@skkard-desktop:~/Applications/qt-labs-opencl$… >>> More

    • Handling Erlang inets http client errors

      as seen on Stack Overflow - Search for 'Stack Overflow'
      I have an Erlang app which makes a large number of http calls to external sites using inets, using the code below case http:request(get, {Url, []}, [{autoredirect, false}], []) of {ok, {{_, Code, _}, _, Body}}-> case Code of 200 -> HandlerFn(Body); _ -> {error… >>> More