În acest proiect veţi implementa un alocator simplu de memorie, similar sistemului malloc/free.
Responsabili:
Autor inițial: Ștefan Bucur
Deadline hard: 18.12.2017
În prima săptămână de după vacanța de iarnă, proiectul se va susține în fața celor doi responsabili. Această dată va fi specificată ulterior în enunț și pe forum.
Punctajul final este cel acordat în urma prezentării și poate să difere de cel de pe vmchecker.
Un proiect neprezentat este notat cu punctaj NUL!
Sugerăm să citiți cu atenție TOATĂ secțiunea Testare, înainte de a folosi checkerul local.
În urma realizării acestui proiect, studentul va fi capabil:
Așa cum ați aflat deja, locuitorii din satul lui Gigel sunt in război deschis cu barbarii. Aceștia din urmă sunt însă cei care, cu mulți ani înainte de trecerea la un stil de viață beligerant, erau recunoscuți pentru înclinația lor către știință. Aceea a fost perioada în care au scris biblioteca stdlib.
Odată cu începerea războiului, locuitorii din satul lui Gigel s-au văzut nevoiți să renunțe la folosirea acestei biblioteci. Totuși, pentru a putea efectua calculele necesare pentru viața de zi cu zi, ei sunt obligați de împrejurări să își scrie ei înșiși funcțiile de care au nevoie. Momentan, prioritatea o reprezintă funcțiile pentru alocarea dinamică a memoriei. Ajutați-i pe locuitorii din satul lui Gigel să implementeze funcțiile de care au nevoie.
Programul vostru va trebui să realizeze o simulare a unui sistem de alocare de memorie. Programul va primi la intrare comenzi de alocare, alterare, afişare şi eliberare de memorie, şi va trebui să furnizaţi la ieşire rezultatele fiecărei comenzi. Nu veţi înlocui sistemul standard malloc()
şi free()
, ci vă veţi baza pe el, alocând la început un bloc mare de memorie şi apoi presupunând că acela reprezintă toată “memoria” voastră, pe care trebuie s-o gestionaţi.
Un alocator de memorie poate fi descris, în termenii cei mai simpli, în felul următor:
arenă
. De exemplu, sistemul de alocare cu malloc()
are în gestiune heap
-ul programului vostru, care este un segment special de memorie special rezervat pentru alocările dinamice.disjuncte
), pentru că altfel datele modificate într-un bloc vor altera şi datele din celălalt bloc.
O problemă pe care o are orice alocator de memorie este cum este ţinută evidenţa blocurilor alocate, a porţiunilor libere şi a dimensiunilor acestora
. Pentru această problemă există în general două soluţii:
pe care voi o veţi implementa în această temă
, foloseşte arena pentru a stoca informaţii despre blocurile alocate. Preţul plătit este faptul că arena nu va fi disponibilă în totalitate utilizatorilor, pentru că va conţine, pe lângă date, şi informaţiile de gestiune, însă avantajul este că nu are nevoie de memorie suplimentară şi este în general mai rapidă decât prima variantă.Există mai multe metode prin care se poate ţine evidenţa blocurilor alocate în arenă, în funcţie de performanţele dorite. Voi va trebui să implementaţi un mecanim destul de simplu, care va fi prezentat în secţiunea următoare. Deşi nu este extrem de performant, se va descurca destul de bine pe dimensiuni moderate ale arenei (de ordinul MB).
În continuare vom considera arena ca pe o succesiune (vector) de N
octeţi (tipul de date unsigned char
). Fiecare octet poate fi accesat prin indexul său (de la 0
la N-1
). Vom considera că un index este un întreg cu semn pe 32 de biţi (tipul de date int
pe un sistem de operare pe 32 de biţi). De asemenea, va fi nevoie câteodată să considerăm 4 octeţi succesivi din arenă ca reprezentând valoarea unui index. În această situaţie, vom considera că acel index este reprezentat în format 'little-endian
' (revedeţi exerciţiile de la laboratorul de pointeri pentru mai multe detalii şi citiţi acest articol mult mai descriptiv), şi astfel vom putea face cast de la un pointer de tip unsigned char *
la unul de tip int*
, pentru a accesa valoarea indexului, stocată în arenă.
Figura de mai jos ilustrează structura detaliată a arenei, în decursul execuţiei programului:
Se poate observa că fiecare bloc alocat de memorie (marcat cu un chenar îngroşat) constă din două secţiuni:
de gestiune
, este reprezentată de 12 octeţi (3 * sizeof(int)
) împărţiţi în 3 întregi (a câte 4 octeţi fiecare). Cei trei întregi reprezintă următoarele:0
.0
.datele efective
ale utilizatorului. Secţiunea are lungimea în octeţi egală cu dimensiunea datelor cerută de utilizator la apelul funcţiei de alocare. Indicele returnat de alocator la o nouă alocare reprezintă începutul acestei secţiuni din noul bloc, şi 'nu
' începutul primei secţiuni, întrucât partea de gestiune a memoriei trebuie să fie complet transparentă pentru utilizator.
După cum se poate observa din figura de mai sus, la începutul arenei sunt rezervaţi 4 octeţi care reprezintă indicele de start
- indicele primului bloc (cel mai “din stânga”) din arenă. Dacă arena nu conţine nici un bloc (de exemplu, imediat după iniţializare), acest indice este 0
.
Indicele de start
marchează începutul lanţului de blocuri
din arenă: din acest indice putem ajunge la începutul primului bloc, apoi folosind secţiunea de gestiune a primului bloc putem găsi începutul celui de-al doilea bloc, şi asa mai departe, până când ajungem la blocul care are indexul blocului următor 0 (este ultimul bloc din arenă). În acest mod putem traversa toate blocurile din arenă, şi de asemenea să identificăm spaţiile libere din arenă, care reprezintă spaţiile dintre două blocuri succesive.
Este de remarcat faptul că lanţul poate fi parcurs în ambele sensuri: dintr-un bloc putem ajunge atât la vecinul din dreapta, cât şi la cel din stânga.
De asemenea, atunci când este alocat un bloc nou sau este eliberat unui vechi, 'lanţul de blocuri trebuie modificat
'. Astfel, la alocarea unui nou bloc de memorie, trebuie să ţineţi cont de următoarele:
0
în locul vecinului care lipseşte.La eliberarea unui bloc, trebuie modificate secţiunile de gestiune a vecinilor într-o manieră similară ca la adăugare.
Programul vostru va trebui să implementeze o serie de operaţii de lucru cu arena, care vor fi lansate în urma comenzilor pe care le primeşte la intrare. Fiecare comandă va fi dată pe câte o linie, şi rezultatele vor trebui afişate pe loc. Secţiunea următoare prezintă sintaxa comenzilor posibile şi formatul de afişare al rezultatelor.
“Introduceţi comanda: ”
).
NU aveti voie cu variabile globale, instructiunea goto si alte lucruri interzise (in general) la laborator / curs!!!
Aveti voie sa folositi toate functiile din C, care nu au fost interzise! (ex. NU folositi gets, in locul ei folositi fgets)
(Optional) Daca doriti sa reduceti numarul de parametri ale functiilor, va recomandam realizarea unei structuri `arena_t` si gruparea datelor relevante in aceasta structura.
Daca nu sunteti siguri de ceva care ar putea fi interzis / nu ar respecta regulile din enunt, intrebati pe forum!
Programul vostru va trebui să accepte următoarele comenzi la intrare:
INITIALIZE <N>
N
octeţi. Prin iniţializare se înţelege alocarea dinamică a memoriei necesare stocării arenei, setarea fiecărui octet pe 0, şi iniţializarea lanţului de blocuri (setarea indicelui de start pe 0
).FINALIZE
DUMP
'\t
') , urmat de 16 octeţi, afişati separaţi printr-un spaţiu şi în format hexazecimal, cu 2 cifre hexa majuscule fiecare. Între cel de-al 8-lea şi cel de-al 9-lea octet se va afişa un spaţiu suplimentar.ALLOC <SIZE>
SIZE
octeţi de memorie din arenă. Ea va trebui să găsească o zonă liberă suficient de mare (care să încapă SIZE
octeţi + secţiunea de gestiune), şi să rezerve un bloc 'la începutul
' zonei (nu în mijloc, nu la sfârşit). Va trebui folosită prima zonă liberă validă, într-o căutare de la stânga la dreapta.0
dacă nu a fost găsită nici o zonă liberă suficient de mare în arenă. 'Atenţie:
' Va trebui să afişaţi indexul secţiunii de date din noul bloc, şi nu al secţiunii de gestiune.FREE <INDEX>
INDEX
în arenă. Practic, INDEX
va fi o valoare care a fost întoarsă în prealabil de o comandă
'ALLOC
'. În urma execuţiei acestei comenzi, spaţiul de arenă ocupat de vechiul bloc va redeveni disponibil pentru alocări ulterioare.FILL <INDEX> <SIZE> <VALUE>
SIZE
octeţi consecutivi din arenă, începând cu indexul INDEX
, la valoarea VALUE
, cuprinsă între 0 şi 255 inclusiv. Atenție, această comandă poate modifica și octeți de gestiune, nu numai octeți de date. În acest caz, se garantează ca arena nu va deveni coruptă după o serie de comenzi FILL
consecutive.SHOW <INFO>
INFO
poate fi una din următoarele:FREE
<nblocks> blocks (<nbytes> bytes) free
USAGE
<nblocks> blocks (<nbytes> bytes) used <eff>% efficiency <fragm>% fragmentation
ALLOCATIONS
{FREE|OCCUPIED} <N>
{ .. | .. }
reprezintă faptul că doar una dintre valori va fi afişată. N
reprezintă dimensiunea (nenulă), în octeţi, a zonei respective.
În această secţiune sunt ilustrate câteva exemple de rulare a programului, pentru a înţelege mai bine modul în care programul vostru trebuie să se comporte. Fiecare exemplu este urmat apoi de câteva explicaţii.
INITIALIZE 100 ALLOC 13 16 FILL 16 13 255 DUMP 00000000 04 00 00 00 00 00 00 00 00 00 00 00 19 00 00 00 00000010 FF FF FF FF FF FF FF FF FF FF FF FF FF 00 00 00 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00000060 00 00 00 00 00000064 FREE 16 ALLOC 50 16 ALLOC 40 0 ALLOC 30 0 ALLOC 20 78 FILL 78 20 127 DUMP 00000000 04 00 00 00 42 00 00 00 00 00 00 00 3E 00 00 00 00000010 FF FF FF FF FF FF FF FF FF FF FF FF FF 00 00 00 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00000040 00 00 00 00 00 00 04 00 00 00 20 00 00 00 7F 7F 00000050 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 00000060 7F 7F 00 00 00000064 FREE 16 FREE 78 FINALIZE
Observaţii:
DUMP
, au fost marcate cu verde zonele de gestiune. În primul dump, în primul chenar se poate recunoaşte indexul de start, în al doilea chenar secţiunea de gestiune a blocului alocat. Cu roşu au fost figurate datele utilizatorilor.INITIALIZE 100 ALLOC 10 16 ALLOC 10 38 ALLOC 10 60 ALLOC 10 82 ALLOC 10 0 FREE 16 FREE 60 FILL 38 10 255 FILL 82 10 255 DUMP 00000000 1A 00 00 00 1A 00 00 00 00 00 00 00 16 00 00 00 00000010 00 00 00 00 00 00 00 00 00 00 46 00 00 00 00 00 00000020 00 00 16 00 00 00 FF FF FF FF FF FF FF FF FF FF 00000030 46 00 00 00 1A 00 00 00 16 00 00 00 00 00 00 00 00000040 00 00 00 00 00 00 00 00 00 00 1A 00 00 00 16 00 00000050 00 00 FF FF FF FF FF FF FF FF FF FF 00 00 00 00 00000060 00 00 00 00 00000064 FINALIZE
În acest exemplu se poate observa modul în care sunt actualizate secţiunile de gestiune ale vecinilor blocurilor eliberate, pentru a le înlătura din lanţul de blocuri. De asemenea, se poate observa în dump faptul că un bloc eliberat nu este modificat (resetat pe 0, de exemplu).
INITIALIZE 100 ALLOC 20 16 ALLOC 20 48 SHOW FREE 1 blocks (32 bytes) free SHOW USAGE 2 blocks (40 bytes) used 58% efficiency 0% fragmentation SHOW ALLOCATIONS OCCUPIED 4 bytes OCCUPIED 32 bytes OCCUPIED 32 bytes FREE 32 bytes FREE 16 SHOW FREE 2 blocks (64 bytes) free SHOW USAGE 1 blocks (20 bytes) used 55% efficiency 100% fragmentation SHOW ALLOCATIONS OCCUPIED 4 bytes FREE 32 bytes OCCUPIED 32 bytes FREE 32 bytes FINALIZE
În acest exemplu se poate observa cum se modifică statisticile arenei pe măsură ce blocurile sunt alocate şi eliberate.
Se va acorda un bonus de 20 de puncte
(pe lângă faimă şi respect :) ), dacă se vor implementa, pe lângă comenzile standard prezentate mai devreme, şi următoarele comenzi:
ALLOCALIGNED <SIZE> <ALIGN>
ALLOC
, cu excepţia faptului că indexul returnat va trebui să fie aliniat la ALIGN
octeţi, unde ALIGN
este o putere a lui 2 (poate fi 1, 2, 4, 8, etc.). Un index INDEX
este aliniat la ALIGN
octeţi dacă INDEX % ALIGN == 0
.REALLOC <INDEX> <SIZE>
INDEX
într-un nou spaţiu de memorie de dimensiune SIZE
şi va afişa indexul secţiunii de date a noului bloc alocat. De asemenea, va copia datele aflate în vechiul bloc în noul bloc. Daca SIZE
este mai mic decât dimensiunea originală, vor fi copiaţi numai SIZE
octeţi (va avea loc o trunchiere
).Atenţie:
Pentru găsirea unei zone de memorie libere va trebui să reluaţi procedura de căutare de la stânga la dreapta. Nu este valid să verificaţi că în locul curent există deja spaţiu pentru expansiune / micşorare.SHOW MAP <LENGTH>
LENGTH
caractere, fiecare caracter fiind fie “*”
sau ”.”
, care va descrie zonele libere sau ocupate din arenă. Un caracter este “*”
dacă în zona descrisă de el se află cel puţin un octet rezervat, altfel el va fi ”.”
. Fiecare linie va afişa maxim 80
de astfel de caractere. Dacă dimensiunea arenei este N
, atunci un caracter va reprezena x = N / LENGTH
octeți. Dacă cel puțin unul din cei x octeți este ocupat, se va afișa “*”
, altfel ”.”
. Atenție, x
poate fi și subunitar.INITIALIZE 100 ALLOCALIGNED 10 32 32 SHOW ALLOCATIONS OCCUPIED 4 bytes FREE 16 bytes OCCUPIED 22 bytes FREE 58 bytes FILL 32 10 255 SHOW MAP 50 **........***********............................. SHOW MAP 31 **....********................. SHOW MAP 2 *. SHOW MAP 200 ********................................**************************************** ****............................................................................ ........................................ DUMP 00000000 14 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00000010 00 00 00 00 00 00 00 00 00 00 00 00 16 00 00 00 00000020 FF FF FF FF FF FF FF FF FF FF 00 00 00 00 00 00 00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00000060 00 00 00 00 00000064 REALLOC 32 50 16 DUMP 00000000 04 00 00 00 00 00 00 00 00 00 00 00 3E 00 00 00 00000010 FF FF FF FF FF FF FF FF FF FF 00 00 16 00 00 00 00000020 FF FF FF FF FF FF FF FF FF FF 00 00 00 00 00 00 00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00000060 00 00 00 00 00000064 SHOW MAP 100 ******************************************************************.............. .................... FINALIZE
Puteti folosi scheletul de cod care se gaseste aici.
Folosirea scheletului NU este obligatorie, puteti alege daca vreti sau nu sa il folositi! Recomandam sa va faceti propriul cod care sa parseze comenzile (in vederea unei mai bune pregatiri pentru examen).
Pentru mai multe detalii despre functiile fgets, strtok puteti consulta documentatia din laboratoarele de pe ocw.
Testarea temei se va face folosind un script de evaluare automată, ce poate fi descărcat de aici.
./allocator
).check.sh
, din care se porneşte operaţia de testare (./check.sh
).
reference
). În caz că sistemul vostru de operare de pe mașina fizică este pe 64 de biți, sugerăm să faceți testarea finală și pe o mașină (virtuală sau nu) de 32 de biți.
ATENTIE! Înainte de a folosi checker-ul trebuie să vă asigurați că îl puteți rula. Deoarece sunt mai multe teste random (variază de la rulare la rulare), executabilul reference (programul de referință) este rulat în paralel cu executabilul allocator (programul vostru). Fiecare oferă câte un rezultat pentru fiecare test, apoi rezultatele sunt comparate. De aceea este important sa verificati ca executabilul reference se poate rula.
Exemplu de utilizare:
Dacă ați reușit să rulați ca în exemplu, atunci aveți instalat tot ce este nevoie pentru checker. Dacă întâmpinați erori (ex. “No such file” - pare absurd, dar așa apare), atunci consulați secțiunea Q&A de la finalul acestei pagini, unde aveti o posibilă soluție.
basic
, advanced
și bonus
. Testele random
vor fi generate de fiecare dată când se va rula check.sh
._tests
pentru testele din arhiva, iar pentru cele random aceste limite de gasesc in functia generate_random
din check.sh. _tests
şi să comparaţi rezultatele voastre (fişierele .out
), cu cele ale implementării de referinţă (fişierele .ref
)../reference
), care este folosit intern de tester. Puteţi de asemenea să-l rulaţi separat şi să experimentaţi cu el şi alte situaţii.cs.py
, care este varianta adaptată pentru C a checkerului de C++ de aici aici . Checkerul va rula intern acest script. Puteți să îl rulați manual astfel python cs.py sursa.c
sau python cs.py antet.h
.90 puncte
- testele automate din arhiva de testare.4 puncte
- explicaţiile din README6 puncte
- aspectul codului sursă20 puncte
- implementarea bonusuluiSe pot aplica depunctări suplimentare:
Punctajul pe teste este cel acordat pe vmchecker. Echipa de corectare își rezervă dreptul de a depuncta pentru orice încercare de a trece testele fraudulos (de exemplu prin hardcodare).
Punctajul pe README va fi stabilit în urma corectării manuale. Checker-ul doar vă reamintește dacă nu aveți README sau aveți un README gol în arhivă, pentru a submite unul în arhiva finală.
Checker-ul va încerca să detecteze în mod automat cele mai frecvente greșeli de coding style. Dacă checkerul acordă punctaj 0 pe coding style, acesta este final . În caz contrar, va acorda punctaj maxim, iar punctajul final pe coding style va fi acordat după corectarea manuală.
Se pot aplica depunctări care nu apar în lista de mai sus!
În total se pot obține până la 200p pe proiect, pentru anumite soluții deosebite.
Soluțiile eligibile sunt cele care obțin cele 120 de puncte menționate anterior.
Numim soluție deosebită o soluție care în plus poate avea următoarele atribute (nu neapărat pe toate): * prezintă un mod eficient de organizare al proiectului, de lucru cu pointeri și cu memoria * prezintă funcționalități în plus (nemenționate în enunț) și care sunt relevante pentru alocator de memorie; aceste funcționalități noi trebuie să fie însoțite și de o metodă de testare (de exemplu prin crearea unor fișiere de test noi care să cuprindă noile comenzi) * prezintă o interfață ușor de folosit (de exemplu sub forma unei biblioteci dinamice partajate)
Studentul poate propune orice alt extra bonus pe care îl consideră relevant pentru acest subiect (alocator de memorie).
Pentru a explica de ce credeți ca soluția voastră trebuie luată în considerare pentru extra bonus, creați o secțiune Extra bonus în README și explicați pe larg ce ați facut.
Pentru funcționalitățile noi create se pot aplica depunctări (cele menționate mai sus), dar care nu se aplică pentru cele 120 de puncte.
Notarea este subiectivă și va fi facută în urma prezentării proiectului.
În prima săptămână de după vacanța de iarnă, proiectul se va susține în fața celor doi responsabili. Această dată va fi specificată ulterior în enunț și pe forum.
Un proiect neprezentat este notat cu punctaj NUL!
Punctajul final pe proiect este cel acordat în urma prezentării și poate să difere de cel de pe vmchecker.
Makefile
care să conțină regulile build
și clean
. Regula build
va compila programul într-un executabil cu numele allocator
. Regula clean
va șterge executabilul și eventual toate binarele intermediare (fișiere obiect) generate de voi.README
care să conțină prezentarea implementării alese de voi. Dacă ați implementat și bonusul, menționați acest lucru în README. NU copiați bucăți din enunț în README.bonus
dacă ați implementat și bonus-ul (folosit intern de vmchecker pentru a determina dacă trebuie să ruleze sau nu și aceste teste).A: Dupa tema 2 ar trebui sa stiti deja care sunt problemele (undefined behaviour):p. Aveti grija sa NU cititi din zone de memorie neinitializate / invalide / dealocate in prealabil cu free etc.
A: Iau o pauza, beau o bere … apoi incerc sa depistez linia de cod care ar putea sa produca aceasta eroare.
A: Am grija ca numarul de alocari sa fie egal cu numarul de eliberari de memorie (vorbim doar de alocare dinamica). Folosesc valgrind ca sa confirm acest lucru:
darius@pc ~/project/skel $ sudo apt-get install valgrind ... darius@pc ~/project/skel $ valgrind --version valgrind-3.11.0 darius@pc ~/project/skel $ valgrind ./allocator < _tests/basic_1.in ==19233== Memcheck, a memory error detector ==19233== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al. ==19233== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info ==19233== Command: ./allocator ==19233== // DE AICI INCEPE EXECUTIA NORMALA A PROGRAMULUI MEU (Ex. citeste date de la tastatura) cmd = (INITIALIZE) arg[0] = (INITIALIZE) arg[1] = (100) cmd = (ALLOC) arg[0] = (ALLOC) arg[1] = (13) ... cmd = (FINALIZE) arg[0] = (FINALIZE) // AICI S-A INCHEIAT PROGRAMUL MEU, urmeaza un sumar de la valgrind ==19233== ==19233== HEAP SUMMARY: ==19233== in use at exit: 0 bytes in 0 blocks ==19233== total heap usage: 31 allocs, 31 frees, 5,253 bytes allocated ==19233== ==19233== All heap blocks were freed -- no leaks are possible ==19233== ==19233== For counts of detected and suppressed errors, rerun with: -v ==19233== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Pentru verificarea memory leaks relevante sunt liniile urmatoare:
P.S. Valgrind poate fi util si pentru alte situatii. Un exemplu foarte util este detectarea acceselor invalide la memorie (daca as fi avut as fi vazut multe mesaje de tip eroare inainte de HEAP SUMMARY). Rezolvarea acestor probleme m-ar putea scuti de situatia neplacuta in care obtin X puncte local si Y puncte pe vmchecker (Y « X).
A:
Ce este reference? La ce e util? Unul dinstre autori a implementat tema, a compilat-o pe OS 32bit (conditiile de pe vmchecker). Dacă lucrați pe 64 de biți, este posibil să nu aveți instalate toate bibliotecile necesare pentru a rula executabile compilate pe 32 de biți.
Încercați să reproduceți exemplul următor (după ce ați dezarhivat arhiva cu checkerul):
Dacă ați reușit să rulați ca în exemplu, atunci aveți instalat tot ce trebuie pentru checker.
Dacă întâmpinați erori (ex. “No such file” - pare absurd, dar așa apare), atunci încercați una din soluțiile menționate pe acest link: How to run 32-bit app in Ubuntu 64-bit? .
sudo apt-get update sudo apt-get install multiarch-support
sudo dpkg --add-architecture i386 sudo apt-get update sudo apt-get install libc6:i386 libncurses5:i386 libstdc++6:i386
Încercați pe rând câte o soluție. După fiecare soluție încercați să rulați reference ca în exemplul anterior.
Dacă nu ați reușit cu soluțiile menționate mai sus (sau pe acel link), postați pe forum un mesaj în care includeți și un printscreen cu terminal când rulați (pentru a ne da seama mai repede ce problemă aveți).
Otherwise… Google it's your best friend ! (after Gigel )