Ni daŭrigas ĉi tiun serion da afiŝoj pri kiel krei nian operaciumon. Hodiaŭ ni ne celos unu temon, sed ni difinos iujn utilajn funkciojn de nun. Unue ni difinos 3 funkciojn, kiuj plenumas la funkcion de memcpy, memeset y memcmp:
void* ND::Memory::Set(void* buf, int c, size_t len)
{
unsigned char* tmp=(unsigned char*)buf;
while(len--)
{
*tmp++=c;
}
return buf;
}
void* ND::Memory::Copy(void* dest,const void* src, size_t len)
{
const unsigned char* sp=(const unsigned char*)src;
unsigned char* dp=(unsigned char*)dest;
for(;len!=0;len--) *dp++=*sp++;
return dest;
}
int ND::Memory::Compare(const void* p1, const void* p2, size_t len)
{
const char* a=(const char*)p1;
const char* b=(const char*)p2;
size_t i=0;
for(;i<len;i++)
{
if(a[i] < b[i]) return -1; else if(a[i] > b[i])
return 1;
}
return 0;
}
Ĉiuj estas memefektivigaj. Ĉi tiujn funkciojn mi prenis de malgranda C-biblioteko, la efektivigo kutime similas en ĉiuj operaciumoj. Nun ni faros 3 simulitajn funkciojn sed manipuli kordojn. Ili plenumus la funkcion de strcpy, strcat y strcmp.
size_t ND::String::Length(const char* src)
{
size_t i=0;
while(*src--)
i++;
return i;
}
int ND::String::Copy(char* dest, const char* src)
{
int n = 0;
while (*src)
{
*dest++ = *src++;
n++;
}
*dest = '';
return n;
}
int ND::String::Compare(const char *p1, const char *p2)
{
int i = 0;
int failed = 0;
while(p1[i] != '' && p2[i] != '')
{
if(p1[i] != p2[i])
{
failed = 1;
break;
}
i++;
}
if( (p1[i] == '' && p2[i] != '') || (p1[i] != '' && p2[i] == '') )
failed = 1;
return failed;
}
char *ND::String::Concatenate(char *dest, const char *src)
{
int di = ND::String::Length(dest);
int si = 0;
while (src[si])
dest[di++] = src[si++];
dest[di] = '';
return dest;
}
Ni iras nun kun sufiĉe interesaj funkcioj. Per ĉi tiuj funkcioj ni povas legi kaj skribi al la aparatoj. Ĉi tio kutime fariĝas per ASM kaj respondas (ĉe x86) al la instrukcioj in y eksteren. Por facile voki ASM de C, uzu la instrukcion asm, kun la danĝero, ke ĝi implicas, ke ĝi ne estas portebla. Al ĉi tiu frazo ni aldonas la flamiĝemaj por ke GCC ne provu optimumigi tiun tekston. Aliflanke, la asm-instrukcio havas kuriozan manieron akcepti parametrojn, sed mi pensas, ke oni pli bone komprenas ĝin rigardante la ekzemplojn.
void ND::Ports::OutputB(uint16_t port, uint8_t value)
{
asm volatile("outb %1, %0" : : "dN"(port), "a"(value));
}
uint8_t ND::Ports::InputB(uint16_t _port)
{
unsigned char rv;
asm volatile("inb %1, %0" : "=a"(rv) : "dN"(_port));
return rv;
}
Kaj ĝis nun post 3, hodiaŭ ni faris nenion okulfrapan, sed ni difinis funkciojn, kiuj utilos por la estonteco. Rimarku al 64-bitaj uzantoj, ke mi laboras pri riparado de cimo kio malebligas kompili ĝuste en 64 bitoj. En la sekva afiŝo ni vidos gravan eron de la x86-arkitekturo, la GDT.
9 komentoj, lasu la viajn
Ni vidu, ĉu vi komentas kiel solvi la cimon, ĉar mi ne antaŭeniris de la unua parto.
Mi pensas, ke ili komentis la eraron en la komentoj de afiŝo 2. Ili pensis, ke ĝi estas io de la larvo, se mi bone memoras
Ĉu kopii ĝis revido?
Bajto post bajto evidente ..., 2 sinsekvaj malsukcesoj ne sukcesas, konfirmite.
Koran dankon pro la tre bona afiŝo kaj mi sekvas ĝin, mi havas iujn demandojn:
1. Kiam vi diras 'Por facile voki ASM de C la asm-instrukcio estas uzata, kun la danĝero, ke ĝi implicas, ke ĝi ne estas portebla', kion vi celas, kiam vi diras, 'kun la danĝero, ke ĝi implicas, ke ĝi ne estas portebla. '?
2. Se 'profesia' operaciumo kreiĝus (por tiel diri) ĉi tiu parto de aliro al la Aparataro fariĝus en Assembler.
3. Kiel ĝi estus farita en Asemblisto?
Dankon, ke vi sekvis ĝin, mi respondos la demandojn unu post la alia:
1- Nu, la problemo kun la asm-instrukcio estas, ke ĝi ne ekzistas en iu ajn C-normo, do ĉiu kompililo efektivigas ĝin laŭ sia maniero (se ĝi efektivigas ĝin). Ĉi-kaze ĝi kompileblas kun GCC kaj Clang (ĝi aspektas tre kiel GCC tiurilate) sed vi ne povos en aliaj kompililoj kiel Intel C (ĉi tio uzas Intel-Sintakson en ASM).
2- Profesie, unu parto kaj alia estu klare apartigitaj per arkitekturoj kaj alia komuna parto. Ne necesas fari ĝin en asemblero (Linukso havas ĝin en C)
3- Ankaŭ en muntilo ĝi estas tre simpla, sed vi havas ĝin en aparta dosiero. Aliflanke, havante argumentojn ni devas unue transdoni ĝin al la registroj kaj tio povas fuŝi iomete pli, tiam outb aŭ inb estas alvokitaj kaj la funkcio estas deklarita kiel tutmonde videbla. Tiam de C vi devas fari kaplinion, kiu deklaras "eksteran" funkcion. En NASM (Intel-Sintakso) estus io tia:
outb:
puŝi ebp
mov ebp, esp
mov eax, [ebp + 12]
mov edx, [ebp + 8]
ekster dx, al
mov esp, ebp
pop ebp
malakcepto
Demando, kian sintakson vi uzas? Mi ne komprenas kial tiom da malsamaj asm xD MASM, FASM, NASM, AT & T ...
Kaj se vi havas tempon, ĉu vi povus klarigi la linion:
asm volatile ("outb% 1,% 0" :: "dN" (haveno), "a" (valoro));
Ĝis "asm volatile" ĉu mi komprenis xD "outbyte 1,0?"
Aŭ ĉu ĝi estas 1 -> »dN» (haveno), 0 -> «a» (valoro)?
Se ĝi estas ĉi-lasta, mi ne komprenas kio estas "dn" kaj kio estas "a" ...
Koran dankon pro viaj kontribuoj! Nekredebla !!
La sintakso, kiun mi uzas, estas AT&T, kion GCC uzas interne kvankam ĝi povas esti farita senprobleme en NASM (adaptante la sintakson). Pri tiu kompleksa aserto de asm volatile, mi povas nur diri al vi, ke ĝi estas la kazo pro la GCC, ĉar ĝi uzas iujn parametrojn por scii kiel la datumoj devas esti transdonitaj. Ekzemple "a" estas speciala x86-operando, kiu estas uzata por reprezenti la registron. La tuta listo estas ĉi tie: http://gcc.gnu.org/onlinedocs/gcc/Constraints.html#Constraints
nu, mi vere bezonas helpon, mi novas pri tio kaj mi tute ne scias, kion fari kun tio, kio estas skribita en la fina stacio, ĉu iu povas helpi min?