Autor Thema: GCC Funktionen in Header "undefined reference"  (Gelesen 16360 mal)

OS_3000

  • Beiträge: 53
    • Profil anzeigen
Gespeichert
« am: 31. March 2012, 22:48 »
Ich habe das Problem, dass ich einige Methoden eines Headers einfach nicht aufrufen kann.  :cry:

Zb. in meiner "AsmAcess.h":
#ifndef ASMACCESS
#define ASMACCESS

#include <stdint.h>

inline uint8_t inb(uint16_t Port)
{
    unsigned char Data = 0;
    asm volatile ("inb %1, %0" : : "a" (Data), "Nd" (Port));
    return Data;
}
inline void outb(uint16_t Port, uint8_t Data)
{
    asm volatile ("outb %0, %1" : : "a" (Data), "Nd" (Port));
}
inline void halt()
{
    StopPoint:
    asm volatile ("cli");
    asm volatile ("hlt");
    goto StopPoint;
}

#endif
Diese Datei binde ich dann zb. in meinem Kernel ein:
#include "kernel\console.h"
#include "kernel\asmaccess.h"

void main()
{
    Console_ClearScreen();
    Console_WriteLine("Hallo!");
    Console_WriteLine("Ich heiße Compi!");
    Console_WriteLine("Ich bin ein Computer");
    Console_WriteLine("und lasse hier diesen sinnfreien Text anzeigen.");
    halt();
}

Wenn ich das Ganze dann mit folgendem Code kompilieren will:
del obj\*.o
SET C_COMPILE=i586-elf-gcc -m32 -ffreestanding -Wall -nostdinc -std=gnu99 -I stdlib
SET ASM_COMPILE=nasm -f elf

%ASM_COMPILE% -o obj\start_S.o start.S
%C_COMPILE% -o obj\kernel_c.o -c kernel.c

%C_COMPILE% -o obj\beep_c.o -c kernel\beep.c
%C_COMPILE% -o obj\console_c.o -c kernel\console.c

%C_COMPILE% -o obj\rand_c.o -c stdlib\rand.c

i586-elf-ld -T linkconf.ld -o obj\kernel.bin obj\*.o -Ttext=0x100000

copy obj\kernel.bin cd\kernel.bin
mkisofs -R -J -b boot/grub/stage2_eltorito -no-emul-boot -boot-load-size 4 -boot-info-table -o cdrom.iso cd/
Kommt beim Linken immer diese Fehlermeldung:
obj\kernel.o: In Funktion "[i]main[/i]":
kernel.c(.text+0x57): undefined reference to "halt"

Ich bin absolut ratlos, was das Problem auslöst.
Eigentlich müsste der Präprozessor "#include "kernel\asmaccess.h"" mit dem Code in der Datei ersetzen und abschliessend das Ganze inlinen.
Doch weshalb tut er das nicht?  :-o

Ich hoffe ihr könnt mir helfen.  :-)

rizor

  • Beiträge: 521
    • Profil anzeigen
Gespeichert
« Antwort #1 am: 01. April 2012, 00:36 »
Der Fehler ist komisch, aber nimm besser mal das goto raus. Du hast den Punkt nirgendwo definiert und hlt; stoppt die CPU.
Programmiertechnik:
Vermeide in Assembler zu programmieren wann immer es geht.

OS_3000

  • Beiträge: 53
    • Profil anzeigen
Gespeichert
« Antwort #2 am: 01. April 2012, 00:47 »
Hat leider nicht geholfen.  :cry:

Der Fehler tritt übrigens auch bei dem Aufruf der In\Out-Funktion auf.

Die "MoveCurser"-Funktion der "Console"-Datei verursacht so sogar 8 Linkerfehler.
void Console_MoveCurser()
{
    if (Console_ShowCurser)
    {
        //Curser auf Position setzen
        outb(0x3D4, 14);
        outb(0x3D5, (uint8_t)(Console_Curser >> 8));
        outb(0x3D4, 15);
        outb(0x3D5, (uint8_t)Console_Curser);
    }
    else
    {
        //Curser aus dem Bildschirm setzen
        outb(0x3D4, 14);
        outb(0x3D5, (uint8_t)(Console_CharCount >> 8));
        outb(0x3D4, 15);
        outb(0x3D5, (uint8_t)Console_CharCount);
    }
}

LittleFox

  • Beiträge: 306
    • Profil anzeigen
    • LF-Net.org
Gespeichert
« Antwort #3 am: 01. April 2012, 00:52 »
Hi,

einbinden tut der die header aber, oder? Das würde ich mal nachprüfen.
Schrein einfach mal ein "#error bla" in einen der header, dann können wir das schonmal ausschließen.

Grüße, LittleFox

--
Handy ..

micha

  • Beiträge: 141
    • Profil anzeigen
Gespeichert
« Antwort #4 am: 01. April 2012, 11:22 »
Diese Datei binde ich dann zb. in meinem Kernel ein:
#include "kernel\console.h"
#include "kernel\asmaccess.h"

void main()
{
    Console_ClearScreen();
    Console_WriteLine("Hallo!");
    Console_WriteLine("Ich heiße Compi!");
    Console_WriteLine("Ich bin ein Computer");
    Console_WriteLine("und lasse hier diesen sinnfreien Text anzeigen.");
    halt();
}

Liegt das vielleicht in deinem Kernelverzeichnis?

du solltest dann das nehmen:
#include "console.h"
#include "asmaccess.h"

statt dem:
Zitat
#include "kernel\console.h"
#include "kernel\asmaccess.h"
« Letzte Änderung: 01. April 2012, 11:23 von micha »

OS_3000

  • Beiträge: 53
    • Profil anzeigen
Gespeichert
« Antwort #5 am: 01. April 2012, 12:18 »
Bei "#Error Ich funktioniere nicht" kommt der Fehler beim kompilieren von "Console.c" und "Kernel.c" wie es sein soll.

Das das wegen dem Kernelverzeichnis streikt, schliess ich mal aus, da "kernel\Console.h" problemlos eingebunden werden kann.

Ich hab mal das Ganze angehängt, vielleicht hilfts bei der Fehlersuche.  :-)
(Die Datei, ist eine 7z-Datei, da ich solche aber leider nicht hochladen darf, habe ich noch ein ".txt" drangehängt. Zum entpacken einfach wieder ".7z" daraus machen.  :wink:)

MNemo

  • Beiträge: 547
    • Profil anzeigen
Gespeichert
« Antwort #6 am: 01. April 2012, 12:33 »
ich kann dir leider nicht sagen warum es so nicht funktioniert, aber static inline hilft.
„Wichtig ist nicht, besser zu sein als alle anderen. Wichtig ist, besser zu sein als du gestern warst!“

OS_3000

  • Beiträge: 53
    • Profil anzeigen
Gespeichert
« Antwort #7 am: 01. April 2012, 12:47 »
Ah, tausend Dank!
Kannst du mir auch noch sagen, was dieses "static" jetzt eigentlich bewirkt, also wozu es gut ist?

Bedauerlicherweiße kommt jetzt beim kompilieren von "Console.c" ein anderer Fehler:
Temp\cckJeKaN.s: Assembler messages:
Temp\cckJeKaN.s:30: Error suffix or operands invalid for "out"

Was stimmt denn jetzt schonwieder nicht?
Meine Funktionen heißen schliesslich immer "outb".

MNemo

  • Beiträge: 547
    • Profil anzeigen
Gespeichert
« Antwort #8 am: 01. April 2012, 13:10 »
static sagt das eine funktion nur in der aktuellen datei benutzt wird. Wenn du zwei Dateien hast die asmaccess.h includen hättest du ohne static die halt funktion zweimal definiert und es käme zu konfliketen beim linken. Static behebt das.

@Assembeler error messages
Es scheint als wäre dein uint8_t kein echter 8-Bit integer. So dass dir gcc z.B.
outb %eax, %dxstatt
outb %al, %dxbaut. Dann passt b (= 8bit) nicht zu eax (=32bit).
„Wichtig ist nicht, besser zu sein als alle anderen. Wichtig ist, besser zu sein als du gestern warst!“

OS_3000

  • Beiträge: 53
    • Profil anzeigen
Gespeichert
« Antwort #9 am: 01. April 2012, 13:26 »
Ich verstehe zwar nicht, weshalb das jetzt kein echter Integer sein soll,
aber auf jedenfall geht es jetzt.  :-D
Noch mal vielen Dank.  :-)

MNemo

  • Beiträge: 547
    • Profil anzeigen
Gespeichert
« Antwort #10 am: 01. April 2012, 13:40 »
Ein integer ist es schon, nur scheint er größer als 8-Bit zu sein.
if (sizeof(uint8_t) != 1) {
  puts("uint8_t hält _nicht_ was er verspricht!");
}

Edit: Ich hab mal nachgeguckt. Dein uint8_t ist OK. aber dein uint16_t nicht. Es lag also an %edx statt %dx. Da du "Nd" hast ist es übrigens nicht ratsam das als "%%dx" hart zu codieren sondern uint16_t zu fixen. (short statt int) bzw. ich nehme:
typedef unsigned uint8_t __attribute__((__mode__(__QI__)));
typedef unsigned uint16_t __attribute__((__mode__(__HI__)));
typedef unsigned uint32_t __attribute__((__mode__(__SI__)));
typedef unsigned uint64_t __attribute__((__mode__(__DI__)));
« Letzte Änderung: 01. April 2012, 13:52 von MNemo »
„Wichtig ist nicht, besser zu sein als alle anderen. Wichtig ist, besser zu sein als du gestern warst!“

micha

  • Beiträge: 141
    • Profil anzeigen
Gespeichert
« Antwort #11 am: 01. April 2012, 13:59 »
nochmal zu dem outb:
deine funktionen in asmaccess.h sind falsch. Sie könnten (sollten) so aussehen:
static inline void outb(uint16_t port, uint8_t data){
   asm("outb %0, %1" : : "a" (data), "Nd" (port));
}
static inline uint8_t inb(uint16_t port){
  unsigned char result = 0;
  asm("inb %1, %0" : "=a" (result) : "Nd" (port));
  return result;
}

OS_3000

  • Beiträge: 53
    • Profil anzeigen
Gespeichert
« Antwort #12 am: 01. April 2012, 14:09 »
Ja, stimmt, hab Blödsinn geschrieben.
Meinte natürlich, dass es eben kein 8-Bit Integer ist.  :roll:

Das mit dem "short" hab ich jetzt bereits selbst bemerkt, als die "Console.c" nicht so recht funktioniert hat.
Diese Definition hatte ich aus dem Internet.
Konnte ja nicht wissen, dass sie noch aus der 16-Bit-Zeit stammt.  :-o

typedef unsigned uint8_t __attribute__((__mode__(__QI__)));
typedef unsigned uint16_t __attribute__((__mode__(__HI__)));
typedef unsigned uint32_t __attribute__((__mode__(__SI__)));
typedef unsigned uint64_t __attribute__((__mode__(__DI__)));
Wenn das besser ist, mach ichs so.

EDIT:
Wo ist jetzt der Fehler in "outb"?
Der einzige Unterschied ist in "inb" das Istgleichzeichen vor dem "a".

« Letzte Änderung: 01. April 2012, 14:11 von OS_3000 »

MNemo

  • Beiträge: 547
    • Profil anzeigen
Gespeichert
« Antwort #13 am: 01. April 2012, 14:33 »
Dein outb ist korrekt.

Ich benutzte diese (u)intNN_t Definitionen weil C mir z.B. nicht garantiert das long 32-bit ist. Es ist halt gcc-only (und auch nur neuere).  Aber ich glaub es geht auch irgendwie die stdint.h von gcc zu nehmen, das wäre dann noch besser.
„Wichtig ist nicht, besser zu sein als alle anderen. Wichtig ist, besser zu sein als du gestern warst!“

micha

  • Beiträge: 141
    • Profil anzeigen
Gespeichert
« Antwort #14 am: 01. April 2012, 19:41 »
ich meinte ja eingentlich auch nur das inb.
Der Assembler hat mir nur Angezeit: Suffix or operands invalid for out
mit den Funktionen kommt das nicht
deshalb hab ich dir funktionierende Funktionen :wink: nochmal geschrieben

OS_3000

  • Beiträge: 53
    • Profil anzeigen
Gespeichert
« Antwort #15 am: 02. April 2012, 16:18 »
Eigentlich dachte ich, jetzt gehts endlich, als das heute wieder los ging.  :x
Jetzt kommt dauernd "undefined Reference to __moddi3", "undefined Reference to __divdi3", "undefined Reference to __umoddi3" und "undefined Reference to __udivdi3".

LittleFox

  • Beiträge: 306
    • Profil anzeigen
    • LF-Net.org
Gespeichert
« Antwort #16 am: 02. April 2012, 16:29 »
wenn ich mich richtig erinnere haben die Funktionen etwas mit uint64/int64 zu tun.
Ist vielleicht schonmal ein Ansatzpunkt.

Grüße

OS_3000

  • Beiträge: 53
    • Profil anzeigen
Gespeichert
« Antwort #17 am: 02. April 2012, 16:36 »
Hm...
Könnte gut sein, da der Fehler in "Console_WriteInt64" auftritt.
Mal noch der Quellcode:
void Console_WriteInt64(sint64_t Number)
{
    char String[21];
    //Negative Zahlen extra behandeln
    bool Negative = Number < 0;
    if (Negative)
    {
        String[0] = '-';
        Number = 0 - Number;
    }
   
    //Nummer in Ziffern aufteilen
    char TempDigits[10];
    int Index = 0;
    while(Number > 0)
    {
        TempDigits[Index++] = Number % 10;
        Number /= 10;
    }
   
    //String zusammenbauen
    int StringIndex = Negative ? 1 : 0;
    for (Index--; Index >= 0; Index--)
    {
        String[StringIndex] = TempDigits[Index] + 0x30;
        StringIndex++;
    }
    String[StringIndex] = 0;
    Console_Write(String);
}

EDIT: Weshalb gibts hier eigentlich kein Syntaxhighlighting?
So ist Quellcode fast unleserlich.
« Letzte Änderung: 02. April 2012, 16:38 von OS_3000 »

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #18 am: 02. April 2012, 17:03 »
Du musst die libgcc dazulinken.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

OS_3000

  • Beiträge: 53
    • Profil anzeigen
Gespeichert
« Antwort #19 am: 02. April 2012, 17:13 »
Wo finde ich das bzw. wie linke ich das?
Hab eben ein wenig im Internet rumgeschaut, aber nichts dazu gefunden.

 

Einloggen