Lowlevel

Lowlevel => Lowlevel-Coding => Thema gestartet von: bitmaster am 11. January 2009, 17:46

Titel: outportb in C
Beitrag von: bitmaster am 11. January 2009, 17:46
Hallöchen,

ich bin gerade dabei mir eine C-Funktion zu schreiben, mit der man einen Byte großen Wert an einen Port schicken lassen können soll. Na ja, aber ich bin ja noch nicht so wirklich gut in C und in AT&T-ASM auch nicht wirklich. So, ich verwende gcc und der kennt ja leider nur die AT&T-syntax (bzw. dessen Assembler). Also so sieht das Ganze bei mir zurzeit aus:

void outportb(unsigned short port, unsigned char val)
{
asm("out val,port"); //tjo und das ist ja falsch
}

Irgendwie raffe ich die Erklärung des gcc inline Assemblers nicht. Man kann ja leider nicht direkt die Variablennamen val und port verwenden. Von daher weiß ich jetzt nicht weiter. Evtl. könnt ihr, die ihr schon lange mit C und dem ganzen Quatsch rumhantiert, mir helfen. Ich wäre euch dankbar.

bitmaster
Titel: Re: outportb in C
Beitrag von: MNemo am 11. January 2009, 18:49
Zitat
Irgendwie raffe ich die Erklärung des gcc inline Assemblers nicht.
Du meinst aber nicht diesen Artikel (http://lowlevel.brainsware.org/wiki/index.php/Inline-Assembler_mit_GCC), oder?
Ich empfinde den Artikel als gut gelungen.

Trozdem hier mal der code den ich verwende.
static inline void outb( t_port port, uint8_t value )
{
    asm volatile ("out %1, %0" : : "Nd" (port), "a" (value) );
}

Edit:
Ich werde mir grad unsicher ob das wirklich optimal ist(nicht das gcc da für %1 ax oder eax nimmt).
Um sicher zu gehen solltest du besser 'outb' benutzen.
Titel: Re: outportb in C
Beitrag von: bitmaster am 11. January 2009, 20:34
Ah cool, danke für den Link und die Lösung.

Noch was, mein gcc übersetzt folgendes nicht (ich habs mit objdump net gefunden):

tmp | 0x20
Wobei tmp eine unsigned char Variable ist. Also er sollte das machen was in asm so aussehen würde:

or [tmp],20h
thx

ARG ich trottel, es muss ja so lauten:

tmp = tmp | 0x20
^^
Titel: Re: outportb in C
Beitrag von: kevin am 11. January 2009, 21:02
Genau. Oder abkürzend tmp |= 0x20. ;)
Titel: Re: outportb in C
Beitrag von: bitmaster am 12. January 2009, 08:06
Genau. Oder abkürzend tmp |= 0x20. ;)
Jo danke, aber die Schreibweise gefällt mir nicht.  :-P

Werde aber bald wahrscheinlich wieder was zum Fragen haben. Also bis denn.  :-D
Titel: Re: outportb in C
Beitrag von: bluecode am 12. January 2009, 08:35
Was machst du denn momentan eigentlich in C, wenn man Fragen darf? :-)
Titel: Re: outportb in C
Beitrag von: bitmaster am 12. January 2009, 15:22
Was machst du denn momentan eigentlich in C, wenn man Fragen darf? :-)
http://www.os-64.de  :-D
Titel: Re: outportb in C
Beitrag von: kevin am 12. January 2009, 18:39
Viele Details sind da aber noch nicht zu erkennen.

Vor allem nicht, wieso es plötzlich langsam sein darf. :P
Titel: Re: outportb in C
Beitrag von: bitmaster am 12. January 2009, 22:35
Viele Details sind da aber noch nicht zu erkennen.

Vor allem nicht, wieso es plötzlich langsam sein darf. :P
Was interessiert mich mein Geschwätz von gestern.

Ich bin Linux User, schreibe mein OS in C (und natürlich ein wenig ASM) und das ist gut so.  :wink:

EDIT: Äh ich habe mir mal so den disassemblierten Code meines Kernels mittels objdump angeschaut. Da macht C aber wirklich etwas langsam. Wie bringe ich gcc dazu aus einer Variablen keinen Speicherzugriff zu machen sondern ein schnelleres Register zu benutzen.

Also z.B. das hier:

unsigned short a;

a = blabla_memory[bla];
blabla_memory[bla+x] = a;

Da ist a nur ein Dummy. In ASM würde ich dafür ein Register benutzen. Aber gcc macht da einen Speicherzugriff raus (mittels Stack und ebp etc.). Da gibt es doch sicherlich Möglichkeiten dem zu sagen, dass die Variable nicht "ewig" gebraucht wird und er also ein Register benutzen kann, oder?

thx
Titel: Re: outportb in C
Beitrag von: kevin am 12. January 2009, 23:23
Optimierungen einschalten. ;)

gcc -O3 sollte selbst dich zufriedenstellen.
Titel: Re: outportb in C
Beitrag von: bitmaster am 15. January 2009, 19:32
So, nachdem ich jetzt 2 Tage dank einer Grippe nur im Bett gelegen habe, brauche ich jetzt mal wieder - wie angekündigt - Hilfe. Also folgendes:

Ich bin gerade dabei meine types.h zu schreiben. Also ich weiß, dass unter gcc

char8 Bit
short16 Bit
int32 Bit

groß sind. Aber was ist mit long? Ich dachte das wären dann 64 Bit. Aber mein Compiler sagt zu meinem Code:

unsigned long main()
{
return 0x100000000;
}

Zitat
cc1: warnings being treated as errors
ztest.c: In function ‘main’:
ztest.c:3: error: integer constant is too large for ‘long’ type
ztest.c:3: error: large integer implicitly truncated to unsigned type

Hmm... jetzt weiß ich nicht mehr weiter. Und was genau ist eigentlich long long? Damit funktioniert es nämlich auch nicht.

thx

bitmaster
Titel: Re: outportb in C
Beitrag von: bluecode am 15. January 2009, 20:09
Unter einem 32Bit System mit gcc ist long 32bit unter einem 64Bit System mit gcc 64Bit. Nur long long ist einheitlich 64Bit.
Titel: Re: outportb in C
Beitrag von: bitmaster am 15. January 2009, 20:42
Unter einem 32Bit System mit gcc ist long 32bit unter einem 64Bit System mit gcc 64Bit. Nur long long ist einheitlich 64Bit.
thx

Aber wenn ich long long anstatt long schreibe, sagt gcc trotzdem "error: integer constant is too large for ‘long’ type".  :?

Und wie bringe ich gcc dazu meine Header-Dateien zu durchsuchen und nicht die des Standardverzeichnisses. Ich hab es mit --sysroot=<directory> versucht, aber irgendwie findet er die Dateien trotzdem nicht.
Titel: Re: outportb in C
Beitrag von: Jidder am 15. January 2009, 20:52
0x100000000 braucht mindestens 33 Bit Platz. Deswegen meckert GCC. Die Zahl bekommt nicht durch den Rückgabetyp der Funktion den Typ long long, sondern durch ein Suffix: 0x100000000ULL (ULL = unsigned long long). Es gibt auch LL für signed long long. Außerdem UL und L für unsigned long/long.
Titel: Re: outportb in C
Beitrag von: bitmaster am 15. January 2009, 21:00
0x100000000 braucht mindestens 33 Bit Platz. Deswegen meckert GCC. Die Zahl bekommt nicht durch den Rückgabetyp der Funktion den Typ long long, sondern durch ein Suffix: 0x100000000ULL (ULL = unsigned long long). Es gibt auch LL für signed long long. Außerdem UL und L für unsigned long/long.
Danke, mit ULL funktioniert es. Aber wofür dann ein "Rückgabetyp der Funktion" wenn es damit sowieso nicht geht?  :-o

Ach ja: es stehen noch Fragen offen:  :-D
Titel: Re: outportb in C
Beitrag von: MNemo am 15. January 2009, 21:31
gcc Optionen:

-nostdinc     : um die standard Verzeichnisse zu ignorieren
-iquote <dir> : Include Verzeichnis nur für #include "foo.h"
-I <dir >     : include Verzeichnis für #include <foo.h> und #include "foo.h"
Titel: Re: outportb in C
Beitrag von: bitmaster am 15. January 2009, 21:50
gcc Optionen:

-nostdinc     : um die standard Verzeichnisse zu ignorieren
-iquote <dir> : Include Verzeichnis nur für #include "foo.h"
-I <dir >     : include Verzeichnis für #include <foo.h> und #include "foo.h"
Jou vielen dank, jetzt geht es. Sagt mal wie kommt man eigentlich an die ganzen Infos zu allen gcc Parametern ran. Ein gcc --help gibt mir nicht allzu viel aus.

thx

bitmaster
Titel: Re: outportb in C
Beitrag von: MNemo am 15. January 2009, 21:54
wenn du die gcc-doc installiert hast
man gccoder noch ausführlicher hier (http://gcc.gnu.org/onlinedocs/) bzw.
http://gcc.gnu.org/onlinedocs/gcc-4.3.2/gcc/
Titel: Re: outportb in C
Beitrag von: bitmaster am 15. January 2009, 22:31
wenn du die gcc-doc installiert hast
man gccoder noch ausführlicher hier (http://gcc.gnu.org/onlinedocs/) bzw.
http://gcc.gnu.org/onlinedocs/gcc-4.3.2/gcc/
ah cool, vielen dank

Und schon wieder ein Problem:

Gcc sagt:

Zitat
video.c:74: error: conflicting types for ‘PrintC’
../include/video.h:12: error: previous declaration of ‘PrintC’ was here

Weiß jetzt nicht was ich falsch gemacht haben soll. Also ich habe eine kernel.c, eine video.c und eine video.h. In der kernel.c rufe ich die Funktionen Print und PrintC auf. In der video.c ist der code der Print und PrintC. Print ruft selbst aber auch PrintC auf (dürfte doch kein Problem sein, oder kommt der dann durcheinander?). Jo und in der video.h habe ich dann noch mal schön das da stehen:

#ifndef _VIDEO_H_
#define _VIDEO_H_

//print a message
void Print(char* msg);

//print a character
void PrintC(unsigned character);

#endif // ifndef _VIDEO_H_

ALso ich sehe da keinen Fehler.  :?

bitmaster
Titel: Re: outportb in C
Beitrag von: kevin am 15. January 2009, 22:48
Damit man es genau sagen kann, müßtest du noch Zeile 74 in der video.c herzeigen. Anscheinend hast du die Funktion dort anders definiert als in der Headerdatei. Und das geht natürlich nicht.
Titel: Re: outportb in C
Beitrag von: bitmaster am 15. January 2009, 23:44
Damit man es genau sagen kann, müßtest du noch Zeile 74 in der video.c herzeigen. Anscheinend hast du die Funktion dort anders definiert als in der Headerdatei. Und das geht natürlich nicht.
Ah shit. Beim Kopieren und Einfügen hierhin habe ich es bemerkt. Na ja, muss wohl wirklich so sein, dass man 1.000 mal schaut und erst beim 1.001. mal den Fehler findet. Gerade bei mir dürfte das nicht Untypisch sein.  :-D Aber vielen dank dir.
Titel: Re: outportb in C
Beitrag von: kevin am 15. January 2009, 23:59
Naja, der Compiler sagt ja nicht umsonst, wo und was du falsch gemacht hast. ;)
Titel: Re: outportb in C
Beitrag von: bitmaster am 21. January 2009, 14:28
Ist zwar eigentlich ein anderes Thema, aber dafür wollte ich jetzt nicht ein neues aufmachen. Also folgendes, was ist eigentlich der Unterschied zwischen:

mov $0x10, %eax
und

mov $0x10, %%eax
Also % sagt ja dem gcc (bzw. dessem Assembler) dass es sich um ein Register handelt. Aber was sagen zwei %, also %%?

thx

bitmaster
Titel: Re: outportb in C
Beitrag von: Jidder am 21. January 2009, 16:04
Zwei %% verwendet man im Inline Assembler, wenn man Operanden (hinter den Doppelpunkten) angibt. Die Operanden werden dann mit %0, %1, ... durchnummeriert und man muss %% für Register verwenden, um diese von den Operanden zu unterscheiden. Wenn du keine Operanden angibst, musst du % für Register verwenden.
Titel: Re: outportb in C
Beitrag von: bitmaster am 21. January 2009, 19:19
Zwei %% verwendet man im Inline Assembler, wenn man Operanden (hinter den Doppelpunkten) angibt. Die Operanden werden dann mit %0, %1, ... durchnummeriert und man muss %% für Register verwenden, um diese von den Operanden zu unterscheiden. Wenn du keine Operanden angibst, musst du % für Register verwenden.
Ah OK, vielen dank. Sagt mal wie mache ich eigentlich einen FAR-Jump? Also in Intel-Syntax lautet das ja jmp SEG:OFF aber wie siehts mit der AT&T-Syntax aus?

thx

bitmaster
Titel: Re: outportb in C
Beitrag von: kevin am 21. January 2009, 19:27
ljmp Segment, Offset
Titel: Re: outportb in C
Beitrag von: bitmaster am 21. January 2009, 19:35
ljmp Segment, Offset
hmm also das funktioniert bei mir net:

asm ("ljmp 0x08, .1"
".1:");

Wofür steht eigentlich das l von ljmp?

thx

bitmaster
Titel: Re: outportb in C
Beitrag von: bitmaster am 21. January 2009, 20:08
So, also so funktioniert es jetzt:

asm ("ljmp $0x08, $.1;"
     ".1:");

Aber ich würde gerne eine definierte Konstante nutzen anstatt den direkten Wert $0x08. Die Konstante ist so definiert:
#define CODE_SEL 1 << 3
Wenn ich jetzt aber


asm ("ljmp CODE_SEL, $1f;"
     "1:");

schreibe, dann sagt mir gcc

Zitat
Error: suffix or operands invalid for `ljmp'

Und wenn ich

asm ("ljmp $CODE_SEL, $1f;"
     "1:");

schreibe, dann sagt mir gcc

Zitat
Error: can't handle non absolute segment in `ljmp'

Also wie kann ich die Konstante einbauen?

vielen dank!!!
Titel: Re: outportb in C
Beitrag von: MNemo am 21. January 2009, 20:34
Versuchs mal mit Klammern:
#define CODE_SEL  (1<<3)

asm(" ljmp $CODE_SEL, $.1");

Zitat
Wofür steht eigentlich das l von ljmp?
ich schätze mal für 'long'
Titel: Re: outportb in C
Beitrag von: kevin am 21. January 2009, 20:40
Der Präprozessor ersetzt #defines nicht in Strings. Wär ja noch schöner. ;)

asm("ljmp %0, $.1" : : "i" (CODE_SEL)); könnte es tun (also als Immediate-Wert reingeben).
Titel: Re: outportb in C
Beitrag von: bitmaster am 21. January 2009, 23:04
Der Präprozessor ersetzt #defines nicht in Strings. Wär ja noch schöner. ;)

asm("ljmp %0, $.1" : : "i" (CODE_SEL)); könnte es tun (also als Immediate-Wert reingeben).
Ah sry dass ich so spät antworte. Ich habe noch ein wenig Sport gemacht und geduscht (und natürlich auch noch meine Zähne geputzt). Das alles braucht ja Zeit. Aber danke, das funktioniert wunderbar. Jetzt kann ich mit ruhigem Gewissen schlafen gehen.  :-D

bitmaster