+ Odpowiedz na ten temat
Pokaż wyniki od 1 do 3 z 3

Temat: O tym, jak napisać prosty kompilator asemblera po linuksem

  1. #1

    Domyślnie O tym, jak napisać prosty kompilator asemblera po linuksem

    Wstęp

    Swego czau obmyśliłem prosty asembler, do którego był kompilowany inny język. Ten aembler był wykonywany przez maszynę wirtualną. Teraz piszę kompilator tego asemblera do pliku wykonywalnego, napisany jest w C, pod Linuksem.


    Przedstawię tu pokrótce, jak to działa, gdyż temat te wydaje mi się dość ciekawy, a też mało popularny. Kod jest w początkowej fazie i mało jest tam do analizowania, a jednocześnie IMHO jest na tyle dobry, że dalsze rzeczy będzie w miarę łatwo dodać.


    Potrzebne będą nam następujące oprogramowanie oraz wiedza z zakresu:
    • podstawy asemblera, C, Makefile
    • Linux z pakietami libelfg0 oraz libelfg0-dev
    • git (by ściągnąć kod z repozytorium)
    • objdump


    Projekt można ściągnąć pomocy git'a klonując repozytorium:


    Kod:
    git clone git@github.com:RobertGawron/l33tlang.git
    Możliwości kompilatora


    No na razie nie ma tego dużo:
    • obsługa przerwania, które kończy działanie programu
    • dodawanie
    • odkładanie na stos
    • procedury (których póki co nie można wywoływać)


    Teoria


    Pliki wykonywalne w Linuksie oparte są o pliki ELF, jest to dość stary standard, powszechny w środowiskach Uniksowych. Każdy taki plik jest plikiem binarnym, tzn. Nie otworzymy go zwykłym edytorem tekstu (vim, emacs), lecz musimy skorzystać z wyspecjalizowanego programu, który potrafi go odczytać I przedstawić nam o nim (tzn. o pliku) informacje. Takie narzędzia to m.in. readelf oraz objdump, ja wykorzystałem ten drugi. O tym, jak go wykorzystać powiem później.


    Plik ELF składa się z sekcji, informacje w nich zawarte są ze sobą powiązane, najważniejsze z nich to:
    • symtab – tablica symboli, służy m.in. Do tego, by wskazac, w którym miejcu zaczynają się procedury, nazwy tych funkcji zawarte są w strtab
    • strtab – powiązana z symtab, nazwy procedur
    • text – instrukcje do wykonania dla procesora
    Toolchain



    W skrócie to pisanie takiego kodu u mie działa tak: kompiluję kompilator, odpalam makefile, który tym kompilowanym kmpilatorem kompiluje plik asemblera. Ta kompilacja przebiega pod okiem valgrinda, bym wiedział, czy są wycieki pamięci. Skompilowany plik wynikowy sprawdzam objdumpem (sekcje z rozkazami dla procesor), linkuję (ld – standardowy linker) sprawdzając czy nie ma błędów linkwania, a na końcu wykonuję (sprawdzając czy program się nie rozsypie.


    By przeprpwadzić te czynności trzeba ucruchomić makefile, w katalogu /dist/Debug/GNU-Linux-x86 Ma on postać:
    Kod:
    all:
            valgrind ./nativecompiler ./hello-*
            objdump -D foo.o 
            ld -s -o foo ./foo.o  -lelf -I/lib/ld-linux.so.2 
            ./foo
    Plik asemblera ma postać:
    Kod:
    main:
        push 5
        push 3
        add
        call foo
        int 0
        int 2
        ret
    foo:
        ret
    bar:
        ret
    A wynik jest taki:
    Kod:
    rgawron@foo:/opt/l33tlang/NativeCompiler/dist/Debug/GNU-Linux-x86$ make
    valgrind ./nativecompiler ./hello-*
    ==13616== Memcheck, a memory error detector.
    ==13616== Copyright (C) 2002-2007, and GNU GPL'd, by Julian Seward et al.
    ==13616== Using LibVEX rev 1804, a library for dynamic binary translation.
    ==13616== Copyright (C) 2004-2007, and GNU GPL'd, by OpenWorks LLP.
    ==13616== Using valgrind-3.3.0-Debian, a dynamic binary instrumentation framework.
    ==13616== Copyright (C) 2000-2007, and GNU GPL'd, by Julian Seward et al.
    ==13616== For more details, rerun with: -v
    ==13616==
    call foo
     ; call is not implmented
    ==13616==
    ==13616== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 13 from 1)
    ==13616== malloc/free: in use at exit: 352 bytes in 1 blocks.
    ==13616== malloc/free: 14 allocs, 13 frees, 2,164 bytes allocated.
    ==13616== For counts of detected errors, rerun with: -v
    ==13616== searching for pointers to 1 not-freed blocks.
    ==13616== checked 69,732 bytes.
    ==13616==
    ==13616== LEAK SUMMARY:
    ==13616==    definitely lost: 0 bytes in 0 blocks.
    ==13616==      possibly lost: 0 bytes in 0 blocks.
    ==13616==    still reachable: 352 bytes in 1 blocks.
    ==13616==         suppressed: 0 bytes in 0 blocks.
    ==13616== Rerun with --leak-check=full to see details of leaked memory.
    objdump -D foo.o
    
    foo.o:     file format elf32-i386
    
    Disassembly of section .text:
    
    00000000 <_start>:
       0:   55                      push   %ebp
       1:   89 e5                   mov    %esp,%ebp
       3:   68 05 00 00 00          push   $0x5
       8:   68 03 00 00 00          push   $0x3
       d:   59                      pop    %ecx
       e:   5b                      pop    %ebx
       f:   01 cb                   add    %ecx,%ebx
      11:   90                      nop
      12:   b8 01 00 00 00          mov    $0x1,%eax
      17:   cd 80                   int    $0x80
      19:   c9                      leave
      1a:   c3                      ret
    
    0000001b <foo>:
      1b:   55                      push   %ebp
      1c:   89 e5                   mov    %esp,%ebp
      1e:   c9                      leave
      1f:   c3                      ret
    
    00000020 <bar>:
      20:   55                      push   %ebp
      21:   89 e5                   mov    %esp,%ebp
      23:   c9                      leave
      24:   c3                      ret
    ld -s -o foo ./foo.o  -lelf -I/lib/ld-linux.so.2
    ./foo
    make: *** [all] Error 8
    Pytanie na znajomość asma+linuka, czy Error, który pojawia się na końcu to błąd czy nie? :)


    Kod


    Całośc napisana jest w sposób obiektowy, w C, jeśli się z tym nie spotkaliście, to może to wyglądać trochę dziwnie :) Jakbyście chcieli o tym więcej poczytać, to tutaj jest dłuższa notka o programowaniu zorientowanym obiektowo w C.


    Obiekt world tworzy środowisko dla naszego parsera (nom, on też powinien być bardziej obiektowo napisany, to swoją drogą).


    Parser, po koleii pobiera linijki z pliku z asemblerem, a każdą z nich parsuje (tzn mając string “push 33”, probuje zrozumieć, że ma odłożyć na stos 33, że ma takie coś ma właście skompilować). Moje założenie było takie, by kompilacja każdej linijki pliku asemblera wymagała wczytania, posiadania informacji tylko tej linijce, by nie trzeba było sprawdzać, co jest linijkę wcześniej, lub później.


    Obsługa przerwań asemblera, generowanie odpowiadającego im kodu znajdje się wpliku interrupts.c.


    Do obsługi plików ELF wykorzystałem gotową bibliotekę (napisaną w C) o nazwie libelf. AFAIK mało jest o niej dokumentacji, lecz dośc ciekawym linkiem jest ten tutorial.

    Biblioteka ta jest ona dość toporna w obłudze, masę rzeczy trzeba ustawić ręcznie, dlatego obudowałem ją w swój zestaw funkcji (wzorują się na powyższym linku), dzięki czemu pisząć inne fragmęty kompilatora nie musiałem sie przejmować niskopoziomowymi detalami. Ta częśc jest też napisana nieobiektowo.


    W całym kodzie często przekazuję funkcję jako argument inne funkcje, tworze tablice funkcji etc, jest to rozwiązanie znacznie czytelniejsze, niż siermiężne drabinki if-else. W przyszłości poprawię to I zamiast zwykłych tablic zastosuję struktury.
    Ostatnio edytowane przez RobertG ; 24-02-2010 o 01:45

  2. #2

    Domyślnie

    Notka była zbyt długa na jeden post, więc tu jest ciąg dalszy:

    Dokumentacja


    Ogólna znajduje się na stonie projektu.
    Dokumentacja techniczną można wygenerować doxygenem (o ile macie zainstalowanego), jest do tego dopisana osobna regułka w Makefile, więc wystarczy odpalić:
    Kod:
    make docs
    dokumentacja znajduje się w katalogu html.



    Rzeczy do zrobienia

    Jest cała masa błędów, niedoróbek, np pusta linia w pliku asemblera wywala kompilator Niedługo skończę wreszcie pisać wywoływanie funkcji bo już mam to wstępnie przeanalizowane. Użycie w asemblerze liczb dziesiętnych zamiast szesnastkowych to był epic fail..


    Plany na przyszłość

    wielowątkowość


    W razie pytań, uwag i sugestii piszcie.

  3. #3
    Dawni Moderatorzy Avatar grzonu
    Dołączył
    26-12-2006
    Skąd
    Gdansk, Poland, Poland
    Posty
    1 382

    Domyślnie

    Bardzo dobrze ze cos takiego powstaje
    Pisz dalej bo warto zobaczyc efekty koncowe
    Filmy online---Grzonu Blog

    1) Moje gg to nie pomoc techniczna w obsludze keyloggerow!!! Na gg i pw pomagam tylko w kwestiach organizacyjnych forum. Masz problem to pisz na forum.
    2) Nie zajmuje sie malware a uprzedzajac pytanie "czemu?" - bo taki mam kaprys!

+ Odpowiedz na ten temat

Uprawnienia

  • Nie możesz zakładać nowych tematów
  • Nie możesz pisać wiadomości
  • Nie możesz dodawać załączników
  • Nie możesz edytować swoich postów