Sök…


Anmärkningar

Montering är ett allmänt namn som används för många människoläsbara former av maskinkod. Det skiljer sig naturligtvis mycket mellan olika CPU: er (Central Processing Unit), men även på en enda CPU kan det finnas flera oförenliga samlingsdialekter, vardera sammanställda av olika monterare, till samma maskinkod som definieras av CPU-skaparen.

Om du vill ställa fråga om ditt eget monteringsproblem, ange alltid vilken HW och vilken montering du använder, annars blir det svårt att besvara din fråga i detalj.

Att lära sig montering av en enskild CPU kommer att hjälpa till att lära sig grunderna på olika CPU, men varje HW-arkitektur kan ha betydande skillnader i detaljer, så att lära sig ASM för en ny plattform kan vara nära att lära sig från grunden.

länkar:

X86 församling Wikibook

Introduktion

Monteringsspråk är en mänsklig läsbar form av maskinspråk eller maskinkod som är den faktiska sekvensen för bitar och byte på vilka processorns logik fungerar. Det är i allmänhet lättare för människor att läsa och programmera i mnemonics än binärt, oktalt eller hex, så människor skriver vanligtvis kod på monteringsspråk och använder sedan ett eller flera program för att konvertera det till det maskinspråkformat som processorn förstår.

EXEMPEL:

mov eax, 4
cmp eax, 5
je point

En monterare är ett program som läser installationsspråkprogrammet, analyserar det och producerar motsvarande maskinspråk. Det är viktigt att förstå att det till skillnad från ett språk som C ++ som är ett enda språk som definieras i standarddokument, det finns många olika monteringsspråk. Varje processorarkitektur, ARM, MIPS, x86, etc har en annan maskinkod och därmed ett annat monteringsspråk. Dessutom finns det ibland flera olika monteringsspråk för samma processorarkitektur. Speciellt har x86-processorfamiljen två populära format som ofta kallas gassyntax ( gas är namnet på den körbara för GNU Assembler) och Intel-syntax (uppkallad efter upphovsmannen till x86-processorfamiljen). De är olika men likvärdiga i det att man vanligtvis kan skriva valfritt program i antingen syntax.

Generellt dokumenterar processorns uppfinnare processorn och dess maskinkod och skapar ett monteringsspråk. Det är vanligt att det specifika monteringsspråket är det enda som används, men till skillnad från kompilatorförfattare som försöker anpassa sig till en språkstandard, är monteringsspråket som definieras av processorns uppfinnare vanligtvis men inte alltid den version som används av personerna som skriver monterare .

Det finns två generella typer av processorer:

  • CISC (Complex Instruction Set Computer): har många olika och ofta komplexa maskinspråkinstruktioner

  • RISC (Reducerad instruktionsuppsättning datorer): har däremot färre och enklare instruktioner

För en monteringsspråkprogrammerare är skillnaden att en CISC-processor kan ha många instruktioner att lära sig, men det finns ofta instruktioner som är lämpade för en viss uppgift, medan RISC-processorer har färre och enklare instruktioner, men varje given åtgärd kan kräva programmeringsspråkprogrammeraren att skriva fler instruktioner för att göra samma sak.

Andra programmeringsspråkskompilatorer producerar ibland assembler först, som sedan sammanställs till maskinkod genom att ringa en assembler. Till exempel, GCC använder sin egen gas assembler i slutskedet av sammanställningen. Producerad maskinkod lagras ofta i objektfiler , som kan kopplas till körbara av länkprogrammet.

En komplett "verktygskedja" består ofta av en kompilator, monterare och länkare. Man kan sedan använda den samlaren och länken direkt för att skriva program på monteringsspråk. I GNU-världen innehåller binutils- paketet monteraren och länken och relaterade verktyg; de som enbart är intresserade av monteringsspråksprogrammering behöver inte gcc eller andra kompilatorpaket.

Små mikrokontroller programmeras ofta rent på monteringsspråk eller i en kombination av monteringsspråk och ett eller flera högre nivåspråk som C eller C ++. Detta görs eftersom man ofta kan använda de speciella aspekterna av instruktionsuppsättningsarkitekturen för sådana enheter för att skriva mer kompakt, effektiv kod än vad som skulle vara möjligt på ett högre nivå språk och sådana enheter har ofta begränsat minne och register. Många mikroprocessorer används i inbäddade system som är andra enheter än allmänna datorer som råkar ha en mikroprocessor inuti. Exempel på sådana inbäddade system är tv-apparater, mikrovågsugnar och motorstyrenheten i en modern bil. Många sådana enheter har inget tangentbord eller skärm, så en programmerare skriver vanligtvis programmet på en dator med allmänt syfte, kör en korsmonterare (så kallad eftersom denna typ av assembler producerar kod för en annan typ av processor än den som den kör på ) och / eller en tvärkompilerare och tvärbindare för att producera maskinkod.

Det finns många leverantörer för sådana verktyg, som är lika varierande som de processorer som de producerar kod för. Många, men inte alla processorer har också en open source-lösning som GNU, sdcc, llvm eller annat.

Maskinkod

Maskinkod är term för data i särskilt inbyggt maskinformat, som behandlas direkt av maskinen - vanligtvis av processorn som kallas CPU (Central Processing Unit).

Vanlig datorarkitektur ( von Neumann-arkitektur ) består av processor för allmänna ändamål (CPU), minne för allmänt bruk - lagrar både program (ROM / RAM) och bearbetade data och in- och utgångsenheter (I / O-enheter).

Den stora fördelen med denna arkitektur är relativ enkelhet och universalitet för var och en av komponenterna - jämfört med datormaskiner tidigare (med hårddiskprogram i maskinkonstruktion), eller konkurrerande arkitekturer (till exempel Harvard-arkitekturen som separerar programminne från minne från data). Nackdelen är lite sämre allmän prestanda. På lång sikt möjliggjorde universaliteten för flexibel användning, vilket vanligtvis uppvägde prestandakostnaden.

Hur relaterar detta till maskinkod?

Program och data lagras i dessa datorer som nummer i minnet. Det finns inget riktigt sätt att skilja koden från data, så operativsystemen och maskinoperatörerna ger CPU-tips, vid vilken inmatningspunkt för minnet startar programmet efter att ha laddat alla nummer i minnet. CPU läser sedan instruktionen (numret) lagrat vid startpunkten och bearbetar den noggrant och läser i följd nästa nummer som ytterligare instruktioner, såvida inte själva programmet berättar CPU att fortsätta med körning någon annanstans.

Exempelvis är två 8-bitarsnummer (8 bitar grupperade tillsammans lika med 1 byte, det är ett osignerat heltal inom 0-255-intervallet): 60 201 , när den körs som kod på Zilog Z80 CPU kommer att behandlas som två instruktioner: INC a (inkrementeringsvärde i register a en) och RET (återvänder från underrutinen, pekar CPU för att köra instruktioner från olika delar av minnet).

För att definiera detta program kan en människa ange dessa nummer av någon minne / filredigerare, till exempel i hex-editor som två byte: 3C C9 (decimaltal 60 och 201 skrivna i bas 16-kodning). Det skulle vara programmering i maskinkod .

För att underlätta processen för CPU-programmering för människor skapades ett Assembler- program som kunde läsa textfil som innehåller något som:

subroutineIncrementA:
    INC   a
    RET

dataValueDefinedInAssemblerSource:
    DB    60          ; define byte with value 60 right after the ret

mata ut byte hex-nummer sekvens 3C C9 3C , lindad med extra valfria nummer som är specifika för målplattform: markering vilken del av en sådan binär som är körbar kod, var är startpunkten för programmet (den första instruktionen i den), vilka delar är kodade data (inte körbara), etc.

Lägg märke till hur programmeraren specificerade den sista byten med värdet 60 som "data", men ur CPU-perspektiv skiljer det sig inte på något sätt från INC a byte. Det är upp till exekveringsprogrammet att korrekt navigera CPU över byte som är förberedda som instruktioner och bearbeta data bytes bara som data för instruktioner.

Sådan utgång lagras vanligtvis i en fil på lagringsenhet, laddas senare av OS ( operativsystem - en maskinkod som redan körs på datorn, hjälper till att manipulera med datorn ) i minnet innan den körs och slutligen pekar CPU på programmets ingångspunkt.

CPU kan endast bearbeta och köra maskinkod - men alla minnesinnehåll, till och med slumpmässig, kan behandlas som sådana, även om resultatet kan vara slumpmässigt, allt från " krasch " som upptäcks och hanteras av OS till oavsiktlig uttorkning av data från I / O-enheter eller skador på känslig utrustning ansluten till datorn (inte ett vanligt fall för hemmadatorer :)).

Den liknande processen följs av många andra programmeringsspråk på hög nivå, sammanställer källan (mänsklig läsbar textform av program) i siffror, antingen representerar maskinkoden (inbyggda instruktioner från CPU), eller i fall av tolkade / hybridspråk till något allmänt språkspecifik virtuell maskinkod, som vidare avkodas till inbyggd maskinkod under körning av tolk eller virtuell maskin.

Vissa kompilatorer använder Assembler som mellanstadium i sammanställningen, översätter källan först till Assembler-form, kör sedan monteringsverktyg för att få den slutliga maskinkoden ur den (GCC-exempel: kör gcc -S helloworld.c att få en assemblerversion av C-programmet helloworld.c ).

Hej värld för Linux x86_64 (Intel 64 bit)

section .data
    msg db "Hello world!",10      ; 10 is the ASCII code for a new line (LF)

section .text
    global _start

_start:
    mov rax, 1
    mov rdi, 1
    mov rsi, msg
    mov rdx, 13
    syscall
    
    mov rax, 60
    mov rdi, 0
    syscall

Om du vill köra detta program behöver du först Netwide Assembler , nasm , eftersom den här koden använder sin syntax. Använd sedan följande kommandon (förutsatt att koden finns i filen helloworld.asm ). De behövs för montering, länk respektive exekvering.

  • nasm -felf64 helloworld.asm
  • ld helloworld.o -o helloworld
  • ./helloworld

Koden använder sig av Linux: s sys_write syscall. Här kan du se en lista över alla syscalls för arkitekturen x86_64. När du också tar med man-sidorna för att skriva och avsluta , kan du översätta programmet ovan till ett C-program som gör detsamma och är mycket mer läsbart:

#include <unistd.h>

#define STDOUT 1

int main()
{
    write(STDOUT, "Hello world!\n", 13);
    _exit(0);
}

Här behövs bara två kommandon för sammanställning och länkning (första) och exekvering:

  • gcc helloworld_c.c -o helloworld_c .
  • ./helloworld_c

Hej värld för OS X (x86_64, Intel syntaxgas)

.intel_syntax noprefix

.data

.align 16
hello_msg:
    .asciz "Hello, World!"

.text

.global _main
_main:
    push rbp
    mov rbp, rsp

    lea rdi, [rip+hello_msg]
    call _puts

    xor rax, rax
    leave
    ret

Montera:

clang main.s -o hello
./hello

Anmärkningar:

Utför x86-montering i Visual Studio 2015

Steg 1 : Skapa ett tomt projekt via File -> New Project .

ange bildbeskrivning här

Steg 2 : Högerklicka på projektlösningen och välj Bygg beroenden-> Bygg anpassningar .

Steg 3 : Markera kryssrutan ".masm" .

ange bildbeskrivning här

Steg 4 : Tryck på knappen "ok" .

Steg 5 : Skapa din monteringsfil och skriv in den här:

.386
    .model small
        .code

            public main
                main proc

                    ; Ends program normally

                    ret
                main endp
            end main

Steg 6 : Sammanställ!

ange bildbeskrivning här



Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow