“C.'de bir Assembler yazın.” Neden daha üst düzey bir dilde düşük düzeyli bir dil için bir makine kodu çevirmeni yazmalısınız?


13

Mikroişlemci sınıf eğitmenim bize bir ödev verdi ve şunları söyledi:

"C.'de bir Assembler yazın." - Sevgili Profesörüm

Bu yüzden benim için biraz mantıksız görünüyordu.

Yanılmıyorsam, Montaj Dili Makine Kodundan üst düzey dillerin yolculuğuna ilk adımdır. Yani C Meclis'ten daha üst düzey bir dildir. Peki bir Assembler yazmanın anlamı nedir? Geçmişte C dilinin yokluğunda ne yapıyorlardı? Assembler'ı Makine Kodunda mı yazıyorlardı?

Daha yüksek bir dilde düşük seviyeli bir dil için bir makine kodu çevirmeni yazmak benim için bir anlam ifade etmiyor.

Diyelim ki, bu mimari için bir C derleyicisi bile olmayan yepyeni bir mikroişlemci mimarisi oluşturduk. C ile yazılmış Assembler'ımız yeni mimariyi simüle edebilecek mi? Yani işe yaramaz mı olmayacak mı?

Bu arada GNU Assembler ve Netwide Assembler'ın C dilinde yazılmış olduğunun farkındayım. Neden C dilinde yazıldığını merak ediyorum.

Son olarak, Profesörümüzün bize verdiği basit bir montajcı için örnek kaynak kodu:

// to compile, gcc assembler.c -o assembler
// No error check is provided.
// Variable names cannot start with 0-9.
// hexadecimals are twos complement.
// first address of the code section is zero, data section follows the code section.
//fout tables are formed: jump table, ldi table, label table and variable table.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>


//Converts a hexadecimal string to integer.
int hex2int( char* hex)  
{
    int result=0;

    while ((*hex)!='\0')
    {
        if (('0'<=(*hex))&&((*hex)<='9'))
            result = result*16 + (*hex) -'0';
        else if (('a'<=(*hex))&&((*hex)<='f'))
            result = result*16 + (*hex) -'a'+10;
        else if (('A'<=(*hex))&&((*hex)<='F'))
            result = result*16 + (*hex) -'A'+10; 
        hex++;
    }
    return(result);
}


main()
{   
    FILE *fp;
        char line[100];
        char *token = NULL;
    char *op1, *op2, *op3, *label;
    char ch;
    int  chch;

    int program[1000];
    int counter=0;  //holds the address of the machine code instruction




// A label is a symbol which mark a location in a program. In the example 
// program above, the string "lpp", "loop" and "lp1" are labels.
    struct label  
    {
        int location;
        char *label;
    };
    struct label labeltable[50]; //there can be 50 labels at most in our programs
    int nooflabels = 0; //number of labels encountered during assembly.




// Jump instructions cannot be assembled readily because we may not know the value of 
// the label when we encountered a jump instruction. This happens if the label used by
// that jump instruction appear below that jump instruction. This is the situation 
// with the label "loop" in the example program above. Hence, the location of jump 
// instructions must be stored.
    struct jumpinstruction   
    {
        int location;
        char *label;
    };
    struct jumpinstruction jumptable[100]; //There can be at most 100 jumps
    int noofjumps=0;  //number of jumps encountered during assembly.    




// The list of variables in .data section and their locations.
    struct variable
    {
        int location;
        char *name;
    };
    struct variable variabletable[50]; //There can be 50 varables at most.
    int noofvariables = 0;




//Variables and labels are used by ldi instructions.
//The memory for the variables are traditionally allocated at the end of the code section.
//Hence their addresses are not known when we assemble a ldi instruction. Also, the value of 
//a label may not be known when we encounter a ldi instruction which uses that label.
//Hence, the location of the ldi instructions must be kept, and these instructions must be 
//modified when we discover the address of the label or variable that it uses.
    struct ldiinstruction   
    {
        int location;
        char *name;
    };
    struct ldiinstruction lditable[100];
    int noofldis=0;




    fp = fopen("name_of_program","r");

    if (fp != NULL)
    {
        while(fgets(line,sizeof line,fp)!= NULL)  //skip till .code section
        {
            token=strtok(line,"\n\t\r ");
            if (strcmp(token,".code")==0 )
                break;
        } 
        while(fgets(line,sizeof line,fp)!= NULL)
        {
            token=strtok(line,"\n\t\r ");  //get the instruction mnemonic or label

//========================================   FIRST PASS  ======================================================
            while (token)
            {
                if (strcmp(token,"ldi")==0)        //---------------LDI INSTRUCTION--------------------
                {
                    op1 = strtok(NULL,"\n\t\r ");                                //get the 1st operand of ldi, which is the register that ldi loads
                    op2 = strtok(NULL,"\n\t\r ");                                //get the 2nd operand of ldi, which is the data that is to be loaded
                    program[counter]=0x1000+hex2int(op1);                        //generate the first 16-bit of the ldi instruction
                    counter++;                                                   //move to the second 16-bit of the ldi instruction
                    if ((op2[0]=='0')&&(op2[1]=='x'))                            //if the 2nd operand is twos complement hexadecimal
                        program[counter]=hex2int(op2+2)&0xffff;              //convert it to integer and form the second 16-bit 
                    else if ((  (op2[0])=='-') || ((op2[0]>='0')&&(op2[0]<='9')))       //if the 2nd operand is decimal 
                        program[counter]=atoi(op2)&0xffff;                         //convert it to integer and form the second 16-bit 
                    else                                                           //if the second operand is not decimal or hexadecimal, it is a laber or a variable.
                    {                                                               //in this case, the 2nd 16-bits of the ldi instruction cannot be generated.
                        lditable[noofldis].location = counter;                 //record the location of this 2nd 16-bit  
                        op1=(char*)malloc(sizeof(op2));                         //and the name of the label/variable that it must contain
                        strcpy(op1,op2);                                        //in the lditable array.
                        lditable[noofldis].name = op1;
                        noofldis++;                                             
                    }       
                    counter++;                                                     //skip to the next memory location 
                }                                       

                else if (strcmp(token,"ld")==0)      //------------LD INSTRUCTION---------------------         
                {
                    op1 = strtok(NULL,"\n\t\r ");                //get the 1st operand of ld, which is the destination register
                    op2 = strtok(NULL,"\n\t\r ");                //get the 2nd operand of ld, which is the source register
                    ch = (op1[0]-48)| ((op2[0]-48) << 3);        //form bits 11-0 of machine code. 48 is ASCII value of '0'
                    program[counter]=0x2000+((ch)&0x00ff);       //form the instruction and write it to memory
                    counter++;                                   //skip to the next empty location in memory
                }
                else if (strcmp(token,"st")==0) //-------------ST INSTRUCTION--------------------
                {
                    //to be added
                }
                else if (strcmp(token,"jz")==0) //------------- CONDITIONAL JUMP ------------------
                {
                    //to be added
                }
                else if (strcmp(token,"jmp")==0)  //-------------- JUMP -----------------------------
                {
                    op1 = strtok(NULL,"\n\t\r ");           //read the label
                    jumptable[noofjumps].location = counter;    //write the jz instruction's location into the jumptable 
                    op2=(char*)malloc(sizeof(op1));         //allocate space for the label                  
                    strcpy(op2,op1);                //copy the label into the allocated space
                    jumptable[noofjumps].label=op2;         //point to the label from the jumptable
                    noofjumps++;                    //skip to the next empty location in jumptable
                    program[counter]=0x5000;            //write the incomplete instruction (just opcode) to memory
                    counter++;                  //skip to the next empty location in memory.
                }               
                else if (strcmp(token,"add")==0) //----------------- ADD -------------------------------
                {
                    op1 = strtok(NULL,"\n\t\r ");    
                    op2 = strtok(NULL,"\n\t\r ");
                    op3 = strtok(NULL,"\n\t\r ");
                    chch = (op1[0]-48)| ((op2[0]-48)<<3)|((op3[0]-48)<<6);  
                    program[counter]=0x7000+((chch)&0x00ff); 
                    counter++; 
                }
                else if (strcmp(token,"sub")==0)
                {
                    //to be added
                }
                else if (strcmp(token,"and")==0)
                {
                    //to be added
                }
                else if (strcmp(token,"or")==0)
                {
                    //to be added
                }
                else if (strcmp(token,"xor")==0)
                {
                    //to be added
                }                       
                else if (strcmp(token,"not")==0)
                {
                    op1 = strtok(NULL,"\n\t\r ");
                    op2 = strtok(NULL,"\n\t\r ");
                    ch = (op1[0]-48)| ((op2[0]-48)<<3);
                    program[counter]=0x7500+((ch)&0x00ff);  
                    counter++;
                }
                else if (strcmp(token,"mov")==0)
                {
                    //to be added
                }
                else if (strcmp(token,"inc")==0)
                {
                    op1 = strtok(NULL,"\n\t\r ");
                    ch = (op1[0]-48)| ((op1[0]-48)<<3);
                    program[counter]=0x7700+((ch)&0x00ff);  
                    counter++;
                }
                else if (strcmp(token,"dec")==0)
                {
                                    //to be added
                }
                else //------WHAT IS ENCOUNTERED IS NOT AN INSTRUCTION BUT A LABEL. UPDATE THE LABEL TABLE--------
                {
                    labeltable[nooflabels].location = counter;  //buraya bir counter koy. error check
                    op1=(char*)malloc(sizeof(token));
                    strcpy(op1,token);
                    labeltable[nooflabels].label=op1;
                    nooflabels++;
                } 
                token = strtok(NULL,",\n\t\r ");  
            }
        }


//================================= SECOND PASS ==============================

                //supply the address fields of the jump and jz instructions from the 
        int i,j;         
        for (i=0; i<noofjumps;i++)                                                                   //for all jump/jz instructions
        {
            j=0;
            while ( strcmp(jumptable[i].label , labeltable[j].label) != 0 )             //if the label for this jump/jz does not match with the 
                j++;                                                                // jth label in the labeltable, check the next label..
            program[jumptable[i].location] +=(labeltable[j].location-jumptable[i].location-1)&0x0fff;       //copy the jump address into memory.
        }                                                     




                // search for the start of the .data segment
        rewind(fp);  
        while(fgets(line,sizeof line,fp)!= NULL)  //skip till .data, if no .data, also ok.
        {
            token=strtok(line,"\n\t\r ");
            if (strcmp(token,".data")==0 )
                break;

        }


                // process the .data segment and generate the variabletable[] array.
        int dataarea=0;
        while(fgets(line,sizeof line,fp)!= NULL)
        {
            token=strtok(line,"\n\t\r ");
            if (strcmp(token,".code")==0 )  //go till the .code segment
                break;
            else if (token[strlen(token)-1]==':')
            {               
                token[strlen(token)-1]='\0';  //will not cause memory leak, as we do not do malloc
                variabletable[noofvariables].location=counter+dataarea;
                op1=(char*)malloc(sizeof(token));
                strcpy(op1,token);
                variabletable[noofvariables].name=op1;
                token = strtok(NULL,",\n\t\r ");
                if (token==NULL)
                    program[counter+dataarea]=0;
                else if (strcmp(token, ".space")==0)
                {
                    token=strtok(NULL,"\n\t\r ");
                    dataarea+=atoi(token);
                }
                else if((token[0]=='0')&&(token[1]=='x')) 
                    program[counter+dataarea]=hex2int(token+2)&0xffff; 
                else if ((  (token[0])=='-') || ('0'<=(token[0])&&(token[0]<='9'))  )
                    program[counter+dataarea]=atoi(token)&0xffff;  
                noofvariables++;
                dataarea++;
            }
        }






// supply the address fields for the ldi instructions from the variable table
        for( i=0; i<noofldis;i++)
        {
            j=0;
            while ((j<noofvariables)&&( strcmp( lditable[i].name , variabletable[j].name)!=0 ))
                j++;
            if (j<noofvariables)
                program[lditable[i].location] = variabletable[j].location;              
        } 

// supply the address fields for the ldi instructions from the label table
        for( i=0; i<noofldis;i++)
        {
            j=0;
            while ((j<nooflabels)&&( strcmp( lditable[i].name , labeltable[j].label)!=0 ))
                j++;
            if (j<nooflabels){
                program[lditable[i].location] = (labeltable[j].location)&0x0fff;
                printf("%d %d %d\n", i, j, (labeltable[j].location));   
            }           
        } 

//display the resulting tables
        printf("LABEL TABLE\n");
        for (i=0;i<nooflabels;i++)
            printf("%d %s\n", labeltable[i].location, labeltable[i].label); 
        printf("\n");
        printf("JUMP TABLE\n");
        for (i=0;i<noofjumps;i++)
            printf("%d %s\n", jumptable[i].location, jumptable[i].label);   
        printf("\n");
        printf("VARIABLE TABLE\n");
        for (i=0;i<noofvariables;i++)
            printf("%d %s\n", variabletable[i].location, variabletable[i].name);    
        printf("\n");
        printf("LDI INSTRUCTIONS\n");
        for (i=0;i<noofldis;i++)
            printf("%d %s\n", lditable[i].location, lditable[i].name);  
        printf("\n");
        fclose(fp);
        fp = fopen("RAM","w");
        fprintf(fp,"v2.0 raw\n");
        for (i=0;i<counter+dataarea;i++)
            fprintf(fp,"%04x\n",program[i]);
    }   
}

2
İzole edilmiş hiçbir cihaz yok. Çapraz takımlar özellikle küçük mimariler için çok yaygındır.
Lars Viklund

3
Bir "çapraz" derleyici / montajcı, hedeften farklı bir sistem üzerinde çalışır ve hedef sistemde kullanıma uygun yapay nesneler üretir. Eski zamanlarda, sistemler arasında veri alışverişinin olması gerekmiyordu, ancak bir sistemi kendi başına sıfırdan başlatmak zorunda kaldınız. Mimariler için hemen hemen tüm modern gelişim, yerleşik sistemlerde her şeyi çapraz derleyerek yapılır.
Lars Viklund

19
Montajcıyı C yerine makine koduyla yazmak ister misiniz? Profesörünüz size iyi davranıyor.
Winston Ewert

2
Neden tüm kodlarınızı mümkün olan en iyi programlama ortamında / dilde yazmaya çalışmıyorsunuz? Bir montajcı istisna değildir.
Erik Eidt

1
Belirli bir yönde sabit bir "yolculuk" yoktur.
whatsisname

Yanıtlar:


18

İnsanlar montajcıları makine koduyla yazdı. Daha sonra montaj dilinde de yazdılar - genellikle kendilerini tercüme ettikleri dilin bir alt kümesi, böylece montajcının basit bir "bootstrap" sürümü ile başlarlar, daha sonra montajcının kendisi için ihtiyaç duydukları gibi özellikler eklerler.

Ancak, bunların hiçbiri özellikle bir zorunluluk değildir. Sonunda, bir derleyici (genellikle oldukça) basit bir çeviri programıdır. Bir dosyayı bir (metin) biçiminde alır ve bir dosyayı başka bir biçimde (genellikle bir nesne dosyası biçiminde) yazar.

Girilen metnin metin biçimindeki makine talimatlarını temsil etmesi ve sonucun ikili formattaki aynı talimatları temsil etmesi, montajcıyı uygulamak için kullanılan dilde çok fazla fark yaratmaz - aslında, C'den daha yüksek diller SNOBOL ve Python oldukça iyi çalışabildiğinden - (oldukça) son zamanlarda Python'da yazılmış bir montajcı üzerinde çalıştım ve iş için oldukça iyi çalıştı.

Başlangıçta işleri nasıl önyüklediğinize göre: tipik olarak iyi geliştirme araçlarına ve benzeri bir makineye. Yeni donanım geliştiriyorsanız, genellikle yeni makine için yine de bir simülatör (veya en azından emülatör) yazarak işe başlarsınız, bu nedenle ilk önce kodu bazı durumlarda bir ana sistemde oluşturup çalıştırıyorsunuzdur.


3
"SNOBOL ve Python gibi C'den bile daha yüksek diller oldukça iyi çalışabilir" - bu çok iyi bir nokta. NASM için, hiçbir zaman C'den daha yüksek bir şey düşünmedik, ancak 1995 bugün performans bugün olduğundan çok daha önemliydi ve yüksek seviyeli diller bugün olduğundan çok daha az gelişmişti. Bu günlerde, kesinlikle alternatifleri düşünmeye değer.
Jules

1
1980'lerden beri SNOBOL adını duymadım.
pacmaninbw

Haskell'de bir kez derleyici yazdım. Tembel değerlendirme ve fonksiyon zincirleme, üretilen makine kodu için bir gözetleme deliği optimize edicisinin yazılmasını son derece basit hale getirdi.
Thorbjørn Ravn Andersen

11

Var olmayan bağlantıları görüyorsunuz.

"Bir montajcı yazın", diğer tüm programlama görevleri gibi bir programlama görevidir. Araçları, o görev için en iyi olan görevi gerçekleştirmek için kullanırsınız. Bir derleyici yazmakla ilgili özel bir şey yoktur; yüksek seviyede bir dilde yazmamak için hiçbir neden yoktur. C aslında oldukça düşük bir seviyededir ve muhtemelen C ++ veya başka bir üst düzey dili tercih ederim.

Montaj dili aslında böyle bir görev için tamamen uygun değildir. Montaj dilini makul şekilde kullanacağınız durumlar çok, çok nadirdir. Yalnızca daha üst düzey bir dilde ifade edilemeyen şeyler yapmanız gerektiğinde.


1
Diğer cevaplar çok iyi, ama bunun en açık olanı olduğunu düşünüyorum, özellikle ilk iki cümle ile. Soruyu okurken kendime aynı şeyi söylüyordum.
MetalMikester

Montaj dilini elle yazmak günümüzde yalnızca donanıma özel korsanlıklar için gereklidir. Örneğin, bazı CPU'larda korumalı modun ayarlanması için özel talimat sırası gerekir ve mantıksal olarak eşdeğer sıra yeterli değildir. Hemen hemen tüm normal programlar, yapmaları gereken görev için herhangi bir özel talimat sırası gerektirmez ve sonuç olarak belirli bir sıraya gerek duymak için bir neden yoktur, ancak sadece mantıksal olarak eşdeğer bazı talimatlar kümesi vardır. Optimizasyon derleyicileri yürütme performansını (komut sayısı, duvar saati zamanı, kod önbellek boyutu) artırmak için aynı şeyi yapar.
Mikko Rantalainen

9

Geçmişte C dilinin yokluğunda ne yapıyorlardı? Assembler'ı Makine Kodunda mı yazıyorlardı?

Montaj esasen makine kodu için bir anımsatıcıdır; makine dilindeki her opcode bir montaj anımsatıcısı verilir, yani x86'da NOP 0x90'dır. Bu, montajcının oldukça basit olmasını sağlar (nb çoğu montajcının iki geçişi vardır, biri çevirilecek ve diğeri adresleri / referansları oluşturmak / çözmek için.) İlk montajcı elle yazılmış ve (muhtemelen kağıt üzerinde) makine koduna çevrilmiştir. Daha iyi bir versiyon elle monte edilmiş montajcı ile yazılır ve monte edilir, bu şekilde yeni özellikler eklenir. Yeni diller için derleyiciler bu şekilde oluşturulabilir; geçmişte derleyicilerin montaj çıktısı alması ve arka uçları için bir montajcı kullanması yaygındı!

Daha yüksek bir dilde düşük seviyeli bir dil için bir makine kodu çevirmeni yazmak benim için bir anlam ifade etmiyor. ... [mevcut toplayıcılar] C dilinde yazıldı. Neden C dilinde yazıldıklarını merak ediyorum.

  • Daha karmaşık bir yazılım parçasını daha yüksek bir dilde yazmak genellikle daha kolaydır.
  • Genelde yaptığınız işi daha yüksek bir dilde daha yüksek bir dilde izlemek için daha fazla kod ve daha fazla zihinsel çaba gerektirir.
    • Tek bir C satırı, örn. C ++ 'da (veya C) basit bir atama genellikle en az 3 montaj talimatı (yükleme, değiştirme, saklama;) oluşturur, daha yüksek düzeyde tek bir satırla yapılabilecekleri yapmak için yirmi veya daha fazla talimat (muhtemelen yüzlerce) sürebilir dil (c ++ veya c gibi) Genellikle sorunu çözmek için zaman harcamak ve çözümün makine koduna nasıl uygulanacağını anlamak için zaman harcamak istemez.

İken kendi kendine barındırmayı bir programlama dili için ortak bir dönüm noktası / arzu edilir özellik, montaj çoğu programcılar daha yüksek bir düzeyde işe tercih edeceğini çok düşük seviyesidir. Yani kimse montajda bir montajcı yazmak istemiyor (ya da gerçekten başka bir şey)

Diyelim ki, bu mimari için bir C derleyicisi bile olmayan yepyeni bir mikroişlemci mimarisi oluşturduk.

Önyükleme , yeni bir mimaride bir takım zinciri edinme işlemidir.

temel süreç:

  • yeni CPU'nuz (veya MCU'nuz) için nasıl kod üretileceğini anlayan yeni bir arka uç yazın
  • arka ucunu derle ve test et
  • yeni arka ucunuzu kullanarak istediğiniz derleyiciyi (ve işletim sistemini vb.) çapraz derleyin
  • bu ikili dosyaları yeni sisteme aktar

Bunu yapmak için montajda (yeni veya eski) bir kez yazmanız gerekmez, montajcı / arka uç / kod üretecinizi yazmak için en iyi dili seçmelisiniz.

C ile yazılmış Assembler'ımız yeni mimariyi simüle edebilecek mi?

Montajcılar simüle etmiyor!

Biri yeni (veya mevcut) bir makine dili ile yeni bir CPU geliştiriyorsa, test için genellikle bir simülatör gereklidir; yani simülatör aracılığıyla rastgele talimatlar ve veriler çalıştırın ve çıktıyı prototip CPU'nuzdaki aynı talimatlar ve verilerle karşılaştırın. Sonra hataları bulun, hataları düzeltin, tekrarlayın.


3

C (veya herhangi bir üst düzey dilde) bir derleyici yazma nedenleri arasında, bu üst düzey dilde başka bir program yazmayı haklı çıkarmak için kullanabileceğiniz tüm nedenler vardır. Bu durumda olanlar arasında şef, muhtemelen taşınabilirlik ve kullanılabilirliktir.

Taşınabilirlik: Montajcınızı ana dilde yazarsanız, bu platformda bir montajcınız olur. C'ye yazarsanız, C derleyicisine sahip herhangi bir platformda bir montajcınız vardır. Bu, örneğin, gömülü platformunuz için kodu iş istasyonunuzda derlemenizi ve tümünü doğrudan hedef aygıtta yapmak yerine ikili dosyayı taşımanızı sağlar.

Kullanılabilirlik: Çoğu insan için, program daha yüksek düzeyde bir dilde olduğunda, programın derleyici veya (daha kötü) ham makine kodunda olduğundan çok daha doğaldır. Bu nedenle, montajcıyı daha üst düzey bir dilde geliştirmek ve sürdürmek daha kolaydır, çünkü daha düşük seviyelerde sorumlu olduğunuz minutiaları düşünmek yerine size daha yüksek seviyeli diller tarafından sağlanan soyutlamalar açısından düşünebilirsiniz.


3

Sorunun yalnızca bu kısmına özel olarak değinmek:

"Bu arada GNU Assembler ve Netwide Assembler'ın C dilinde yazılmış olduğunun farkındayım. Neden C'de yazıldıklarını merak ediyorum."

Başlangıçta Netwide Assembler'ı yazan ekibin bir parçası olarak, karar bizim için o kadar açık görünüyordu ki, temelde başka seçenekleri göz önünde bulundurmadık, ama yapsaydık, aynı sonuca varmıştık, aşağıdaki nedenler:

  • Daha düşük bir dilde yazmak daha zor ve çok daha zaman alıcı olurdu.
  • Daha yüksek bir dilde yazmak daha hızlı olabilirdi, ancak performansla ilgili konular vardı (derleyicinin arka ucu olarak kullanılan bir montajcı, özellikle, derleyicinin çok yavaşlamasını önlemek için çok hızlı olması gerekir çok büyük miktarda kod işlemek ve bu özellikle izin vermek istediğimiz bir kullanım örneğiydi) ve birincil yazarların ortak olarak daha yüksek seviyeli dilleri olduğuna inanmıyorum (bu Java popüler hale gelmeden önceydi, bu yüzden dünya bu tür diller o zamanlar parçalanmıştı). Bazı metaprogramlama görevleri için perl kullandık (kod üreteci arka ucu için kullanışlı bir formatta talimat tabloları oluşturma), ancak tüm program için gerçekten uygun olmazdı.
  • İşletim sistemi taşınabilirliği istedik
  • Donanım platformu taşınabilirliği istedik (çapraz derleyiciler üretmek için)

Bu kararı oldukça kolay hale getirdi: ANSI uyumlu C (bugünlerde C89 olarak da bilinir) o zaman tüm bu noktalara gerçekten vuran tek dildi. O zamanlar standart bir C ++ olsaydı , bunu düşünmüş olabilirdik, ancak farklı sistemler arasındaki C ++ desteği o zamanlar oldukça düzensizdi, bu nedenle taşınabilir C ++ yazmak bir kabus gibiydi.


1

Bir şeyin diğeriyle kesinlikle ilgisi yoktur. Web tarayıcıları kesinlikle html veya php veya başka bir web içerik dili kullanılarak mı yazılmalıdır? Hayır, neden olsunlar? Arabalar insanlar tarafından değil, sadece diğer arabalar tarafından kullanılabilir mi?

Bir bit bloğunu (bazı ascii) başka bir bit blobuna (bazı makine kodu) dönüştürmek sadece bir programlama görevidir, bu görev için kullandığınız programlama dili ne istersen. Birçok farklı dilde yazılmış montajcılar olabilirsiniz.

Yeni diller başlangıçta kendi dillerinde yazılamaz, çünkü onlar için henüz derleyici / montajcı yoktur. Yeni bir dil için mevcut bir derleyici yoksa, ilkini başka bir dilde yazmanız gerekir ve daha sonra bu bile bootstrap için mantıklıysa bootstrap yaparsınız. (html ve bir web tarayıcısı, bazı bitleri alan ve bazı bitleri tüküren bir program asla html ile yazılmaz, olamaz).

Yeni bir dil olmak zorunda değil, mevcut bir dil olabilir. Yeni C veya C ++ derleyicileri otomatik olarak kendilerini kapıdan derlemez.

Montaj dili ve C için hemen hemen tüm yeni veya değiştirilmiş komut setleri için ilk iki dil. Biz geçmişte değiliz, şimdideyiz. C veya java veya python'da veya henüz mevcut olmasa bile istediğimiz herhangi bir komut kümesi ve montaj dili için herhangi bir şekilde kolayca bir montajcı oluşturabiliriz. Benzer şekilde, montajcı henüz mevcut olmasa bile, istediğimiz herhangi bir montaj dili için montaj dilini çıkarabileceğimiz birçok yeniden hedeflenebilir C derleyicisi vardır.

Yeni bir talimat seti ile tam olarak bunu yapıyoruz. Yeni komut setimiz veya montajcı için derlenmeyen C derleyicisi ile yeni komut setimizde çalışmayan bazı bilgisayarları alın, bir çapraz birleştirici ve çapraz derleyici oluşturun. Mantığı oluştururken ve simüle ederken bunu geliştirin ve kullanın. İdeal olarak tüm araçlar ve mantık hazır olana kadar bir hata bulmak ve bir hatayı düzeltmek ve test etmek için normal geliştirme döngülerinden geçin. Ve hedefe bağlı olarak, bunun bir işletim sistemi çalıştıramayan bir mikrodenetleyici olduğunu söyleyin, hiçbir zaman önyükleme yapmak için bir nedeniniz olmaz, böylece araç zinciri yerel talimat setini kullanarak üretir ve çalışır. Her zaman derleme yaparsınız. Bir geri dönüş makinesi dışında, montajcıyı montajcıya yazmak asla mantıklı değildir.

Evet, geri dönebilir ya da geri dönüyormuş gibi davranırsanız, ilk toplayıcı kalem ve kâğıtlı bir insandı, bu onlara mantıklı bir şey yazdı ve sonra mantığa mantıklı gelen bitleri yazdı. Daha sonra bitleri makineye almak için anahtarlar veya başka bir yol (google pdp8 veya pdp11 veya altair 8800) kullandı ve bir şey yapmasını sağladı. Başlangıçta hiçbir bilgisayar simülatörü yoktu, sadece mantığa yeterince uzun süre bakarak ya da çipin birkaç devresini döndürerek doğru olmanız gerekiyordu. Araçlar bugün A0 başarısı elde edebileceğiniz kadar iyidir, çünkü bu şey sadece büyük bir dirençten daha fazlasıdır, birçoğu hala tamamen simüle edemediğiniz şeyler için bir dönüşe ihtiyacınız olabilir, ancak şimdi üçüncü veya dördüncü turu beklemek zorunda kalmadan ilk spi,

Wayback makinenizde beklediğiniz gibi, daha sonra elle monte edilmiş kodunuzu alırsınız ve bunu bant veya kartlardan bir program yüklemek için kullanırsınız. Ayrıca bir kodlayıcıyı makine kodunda da elle kodlayabilirsiniz, tam gelişmiş değil, programlamayı biraz daha kolaylaştıran bir kodlayıcı olabilir. Daha sonra bu araç, daha gelişmiş veya karmaşık bir dili (bir makro birleştirici) işleyebilen bir araç oluşturmak için kullanılır ve bu araç, daha karmaşık bir tane oluşturmak için kullanılır ve FORTRAN veya BASIC veya B veya başka bir şeyle sonuçlanırsınız. Ve sonra aynı dilde önyükleme yapmayı düşünmeye başlıyorsunuz, çapraz derleyiciyi yerel bir derleyici olarak yeniden yazıyorsunuz. elbette bunun için ideal bir ortama veya işletim sistemine ihtiyacınız var.

Silikon oluştururken veya test ederken, bir ve sıfır olan sinyallere bakmamız gerekir. Araçlar bize varsayılan olarak ikili veya onaltılık gösterecektir ve araçların bazı anımsatıcıları (belki de montajı) göstermesi için bazı araçlarla bile mümkündür, ancak çoğu zaman mühendisler (silikon / donanım ve yazılım) yeterince okuyabilir makine kodunu kullanın veya talimatları "görmek" için sökme / listeleme yöntemini kullanın.

Ne yaptığınıza bağlı olarak, testi yeniden yazmak ve yeniden derlemek veya yeniden birleştirmek yerine bazı makine kodlarında test vektörlerine girebilirsiniz. Örneğin, bir boru hattınız varsa ve belirli bir derinlikte önceden getirme yaparsanız, borunun tanımlanmamış talimatlara kusmaması için programın sonuna kadar bazı sayıda düğüm veya diğer gerçek talimatları doldurmanız gerekebilir veya doldurmak isteyebilirsiniz ve sadece Makine kodunu derleyiciyi, derleyiciyi veya bağlayıcıyı yapmaya çalışmak yerine en düşük düzeyde listeye / dosyaya doldurun.

İşlemciyi test ederken elbette tanımsızlarla uğraşmanız ve belki de bitlerle vb. İlgilenmemeniz gerekir. Bu nedenle, makine koduna girmeniz ve normal çalışan bir programdaki bir talimatta bir veya daha fazla belirli biti değiştirmeniz gerekir. Bunu yapmak ya da sadece elle yapmak için bir program yazmaya değer mi? Aynı şekilde ECC'yi test ederken bir veya daha fazla biti çevirmek ve düzeltildiklerini veya sıkıştıklarını görmek istersiniz. Verilen bir program yazmak çok daha kolay ya da sadece elle yapabilirsiniz.

Sonra tabii ki bir işlemci, erken pascal, java, python, vb üzerinde çalışan kod üretmeyen diller vardır. Sadece bu dilleri kullanmak için başka bir dilde yazılmış bir VM gerekir. Java derleyicinizi bir java vm yapmak için kullanamazsınız, dilin tasarımına dayanarak bir anlam ifade etmez.

(evet bu dillerin saf uygulanmasından sonra sonunda birileri bazen vm komut setini değil, gerçek talimat setlerini hedefleyebilecek saf olmayan bir arka uç oluşturur ve bu durumda dili kendiniz veya vm'yi gerçekten derlemek için kullanabilirsiniz. Örneğin, gcc'ye bir gnu java ön ucu).

Zaman içinde ve belki de hala C'de C derleyicileri yazmıyoruz. Kendimizi yazmak istemediğimiz C'yi üretmek için kullandığımız diğer programlama dillerini bizon / flex gibi şeyler kullanıyoruz. Bazı yüzdeler C cinsindendir, ancak bazı yüzdeler, bitleri giren ve diğer bitleri çıkaran başka bir derleyici kullanan başka bir dilde. Bazen bu yaklaşım bir montajcı oluşturmak için de kullanılır. Derleyicinin / montajcısının tasarımcısına (bitleri girmek ve daha sonra diğer bitleri çıkarmak gibi bir görevi olan programlar) nasıl uygulayacaklarına kadar. Program oluşturulan ayrıştırıcılar el programlanabilir emin, sadece zaman alıcı böylece bir kısayol aramak. Tıpkı montajcıda bir montajcı yazabileceğiniz gibi, insanlar da bir kısayol arar.

Bir web tarayıcısı sadece bazı bitleri alan ve diğer bitleri veren bir programdır. Bir derleyici sadece bazı bitleri alan ve diğer bitleri veren bir programdır. Derleyici sadece bazı bitleri alan ve diğer bitleri veren bir programdır. Vb Bunların tümü için, her programlama görevi için giriş bitleri ve çıkış bitleri için belgelenmiş bir dizi kural vardır. Bu görevler ve bitler, MEVCUT herhangi bir programlama dilinin kullanılabileceği kadar geneldir (bit / bayt manipülasyonu yapabilen ve girişler ve çıkışlarla ilgilenebilen). Burada anahtar var. Almak ve sıfırdan kitap / öğretici linux deneyin. Simüle edilmiş ön panelli bir pdp8 veya pdp11 veya altair 8800 veya başka bir simülatörü deneyin.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.