Ik wou onlangs een map beperken in grote (bv max 500mb), aangezien het hier om een container ging kon ik niet in /etc/fstab quota’s gaan instellen, dus moest ik op zoek naar een andere manier. Toen vond ik na even zoeken het bash-script mklimdir. Dit script maakt een loopback-device die een beperkte grote heeft en gemount word in een bepaalde map. Dit is zeer handig als je een map wilt beperken in grote, zonder quota’s te moeten gaan opzetten.
Auteur archieven: Vincent Lammens
Gelukkig Nieuwjaar
Gelukkig nieuwjaar iedereen!
Ik heb een aantal wijzigingen doorgevoerd aan deze site zoals (eindelijk) alles omzetten naar jekyll, en ik ga natuurlijk dit jaar veel nieuwe dingen posten.
Ubuntu mate wifi disconection fix
Ik had problemen met mijn laptop zijn wifi na het instellen van ubuntu mate 18.04, ik vond echter al snel de oplossing die te maken had met de ahavi-daemon die ik met volgende fixes kon oplossen:
in /etc/avahi/avahi-deamon.conf, zoek je de regel domain-name = .local, verander deze naar domain-name = .alocal (of iets gelijkaardig, ik heb het gecomment, wat ook werkte)

Dan in /etc/default/avahi-deamon, verander AVAHI_DAEMON_DETECT_LOCAL=1 naar AVAHI_DAEMON_DETECT_LOCAL=0 (op line 4).

Dan moet je je systeem herstarten en daarna zou je verbonden moeten blijven. Ik moest ook nog een vast-ip instellen, aangezien ik mijn pc altijd laat aanstaan, 24/7, maar dat kan je doen in de instellingen van je router/modem.
Soms werkt het volgende ook:
nmcli c up <netwerknaam>
Edit 2020-01-18: Nadat ik ubuntu 18.04 heb geherinstalleerd, heb ik geen last meer van dat probleem, mogenlijks door kernel-updates.
SSH Server Beveiligen
SSH is de eenvoudigste methode om met een linux server te verbinden, maar een login mogenlijkheid openstellen maakt jouw systeem ook vatbaar voor verschillende aanvallen.
Verander de SSH poort
Het eenvoudigste is om de SSH poort aan te passen. Dit is geen waterdichte oplossing, maar is eerder “security by obscurity”. Deze kan je dan veranderen naar een vrije poort op jouw systeem (vb: 2022 or 4422). Hiervoor kan je het ssh-configuratie bestand aanpassen:
sudo nano /etc/ssh/sshd_config
Dan zoek je naar de volgende regel
#Port 22
Un⁻comment deze regel, en verander 22 naar de poort die je wenst te gebruiken, herstart dan SSH
sudo service ssh restart
SSH-keys gebruiken
Om de mogelijkheid van zwakke paswoorden te verwijderen, kan je SSH-sleutels verplichten.
Op een linux client, typ volgend commando:
ssh-keygen
Dit zal een paar vragen stellen, en daarna moet je jouw sleutel naar de server verplaatsen. vervang met het pad naar jouw sleutel (meestal ~/.ssh/id_rsa.pub)
ssh-copy-id -i <PATH_TO_YOUR_KEY> user@server.domain.tld
Nu moet je dit nog aanzetten in de SSH-server, dit kan je doen door in de configuratie van ssh (zie hiervoor hoe je deze kan aanpassen) volgende regels op te zoeken, en te un-commenten.
#PubkeyAuthentication yes
#AuthorizedKeysFile .ssh/authorized_keys .ssh/authorized_keys2
Je kan ook passwoord-logins uitzetten door het volgende op “no” te zetten maar test wel eerst of jouw keys werken!
# PasswordAuthentication yes
Nu kan je jouw ssh-server herstarten (zie hervoor).
Zo, nu kan je jouw ssh-server op het internet openzetten, zonder risico’s.
RPI Assembler tutorial 7
De ARM architectuur is vooral gericht op embedded systeemen. Deze zijn vaak gebruikt in massaproductie-producten. In deze context zijn de marges klein, dus zal de ontwerper zo min mogenlijk componenten willen gebruiken. Een relatief duur component is geheugen, hoewel het elke dag een stukje goedkoper word. In zulke situaties wordt geheugen als bespaard door de ARM instructieset. Deze is ontworpen met dat doel. Ik zal een paar delen nodig hebben om alles uit te leggen, maar we zullen beginnen met ‘Shifted operand’.
Indexeermodes
We hebben gezien dat voor alles behalve load store and branches, ARM instructies als operators ofwel registers ofwel de waarde zelf gebruiken. We hebben ook gezien dat de eerste operator vaak het doelregister is. De instructie mov heeft nog een andere operator: een register of een waarde. Instructies zoals ADD en AND hebben vaak nog meer bronregisters. De eerste is altijd een register en de 2e kan een register zijn, maar ook een andere waarde.
Dit maakt het mogenlijk voor operators in instructies om collectief te zijn. Dit worden indexing modes genoemd. Dit idee kan een beetje ‘off-topic’ lijken omdat we niets zullen indexeren. De naam Indexing heeft wel nut voor geheugen operators. ARM instructies buiten load en store hebben geen geheugen operators.
De syntax van de meeste ARM instructies is als volgt:
instruction Rdest, Rsource1, source2
Er zijn een paar uitzonderingen: mov, b en bxx, ldr en str.
In een volgend deel zal ik de indexeermodes van ldr en str overlopen. Voor Branches is het echter zeer simpel. Hier is het enkel een label in ons programma.
Shift operaties
Wat raar is aan source2 in de instructies hierboven is dat source2 zowel een register als een waarde kan zijn. Dit hebben we al gebruikt in vorige delen bv:
mov r0, #1 mov r1, r0 add r2, r1, r0 add r2, r3, #4
Source2 kan veel meer zijn dan een waarde of een register. We kunnen het zelf combineren met een shift operatie. In deel 6 zagen we er al een, maar nu is het tijd om ze allemaal te laten zien.
LSL #n
Logical Shift Left. Shifts bitsnkeer naar links. Dende linkse bits zijn weg en dende rechtse bits zijn 0.LSL Rsource3
Zoals de voorige maar met de waarde van een register.LSR #n
Logical Shift Right. Zelfde van de eerste, maar dan langs rechts,LSR Rsource3
Zelfde van de vorige, maar dan met een register.ASR #n
Arithmetic Shift Right. Zoals LSR Maar de meest linkse bit voor het shiften is gebruikt in plaats van 0 in denmeest linkse.ASR Rsource3
Zoals de vorige, maar met een register.ROR #n
Rotate Right. Zoals LSR maar denmeest rechtste bits zijn niet weg maar worden denmeest linkse bits.ROR Rsource3
Zoals ROR, maar dan met een register.
In bovenstaande lijst is n een nummer van 1 tot 31. Arm heeft geen shift right en shift left instructie, dus moet je de mov instructie gebruiken:
mov r1, r2, LSL #1
Als je je afvraagt waarom je een register naar links of naar rechts wilt sturen, maar als je in deel 6 hebt gezien dat LSL een waarde geeft die hetzelfde doet als x2, dan geeft ASR een waarde die gedeeld door 2 is. Aangezien een shift van n hetzelfde is als n shifts van 1. Shifts zijn eigenlijk maal of gedeeld door een waarde van 2^n.
mov r1, r2, LSL #1 /* r1 ← (r2*2) */ mov r1, r2, LSL #2 /* r1 ← (r2*4) */ mov r1, r3, ASR #3 /* r1 ← (r3/8) */ mov r3, #4 mov r1, r2, LSL r3 /* r1 ← (r2*16) */
We kunnen dit combineren voor zeer handige gevallen:
add r1, r2, r2, LSL #1 /* r1 ← r2 + (r2*2) equivalent to r1 ← r2*3 */ add r1, r2, r2, LSL #2 /* r1 ← r2 + (r2*4) equivalent to r1 ← r2*5 */
Je kan ook zoiets doen met sub
sub r1, r2, r2, LSL #3 /* r1 ← r2 - (r2*8) equivalent to r1 ← r2*(-7)
Arm komt met een handige rsb functie (reverse subtract) instructie, deze doet het omgekeerde van de sub instructie
rsb r1, r2, r2, LSL #3 /* r1 ← (r2*8) - r2 equivalent to r1 ← r2*7 */
Een voorbeeld:
* Complicated way to multiply the initial value of r1 by 42 = 7*3*2 */ rsb r1, r1, r1, LSL #3 /* r1 ← (r1*8) - r1 equivalent to r1 ← 7*r1 */ add r1, r1, r1, LSL #1 /* r1 ← r1 + (2*r1) equivalent to r1 ← 3*r1 */ add r1, r1, r1 /* r1 ← r1 + r1 equivalent to r1 ← 2*r1 */
Je zult je afvragen waarom we deze functies willen gebruiken, maar omdat de standaard vermenigvuldigingsinstructie veel meer werk is voor de cpu, dus langer duurt, is het voor bepaalde gevallen handig (zeker als het kleinere bewerkingen zijn) om het zo te doen.
Rotaties zijn minder handig dan shifts in het werkelijke gebruik. Deze zijn dan ook vooral gebruikt voor het versleutelen van bits. ARM heeft geen functie om naar links te roteren, maar we kunnen wel iets anders doen:
/* Assume r1 is 0x12345678 */ mov r1, r1, ROR #1 /* r1 ← r1 ror 1. This is r1 ← 0x91a2b3c */ mov r1, r1, ROR #31 /* r1 ← r1 ror 31. This is r1 ← 0x12345678 */
RPI Assembler tutorial 6
In het vorige deel heb ik de branch instructies vergeleken met control-flow tools, dit was niet helemaal juist. Er zijn in ARM assembler ingebouwde if-else structuren te vinden.
IF, THEN, ELSE
Dit is een gemakkelijke. We hebben deze structuur al gebruikt in het vorige deel. Beeld je de volgende structuur in, waar E een expressie is, en S1 en S2 statements zijn.
if (E) then S1 else S2
Een manier om dit in assembler voor te stellen is:
if_eval:
/* Assembler that evaluates E and updates the cpsr accordingly */
bXX else /* Here XX is the appropiate condition */
then_part:
/* assembler for S1, the "then" part */
b end_of_if
else:
/* assembler for S2, the "else" part */
end_of_if:
Als er geen else deel is, kunnen we de bXX else met Bxx end_of_if vervangen.
Loops
Dit is ook een belangrijke. Een loop kan je voorstellen als volgt:
while (E) S
Zo doet S iets waardoor E uiteindelijk een waarde = false krijgt, waardoor de loop stopt. Anders zou hij altijd in de loop blijven. Dit is soms handig maar niet voor onze voorbeelden. Zo kan je deze implementeren:
while_condition : /* assembler to evaluate E and update cpsr */ bXX end_of_loop /* If E is false, then leave the loop right now */ /* assembler of S */ b while_condition /* Unconditional branch to the beginning */ end_of_loop:
Een andere veelvoorkomende loop is de FOR loop, deze laat een integer altijd stijgen (of dalen) zoals:
for (i = L; i < N; i += K) S
Deze is niets meer dan:
i = L;
while (i < N)
{
S;
i += K;
}
Hierdoor kunnen we door een while-loop te gebruiken dezelfde functie krijgen als een for-loop
Een voorbeeld
Laat ons voor dit voorbeeld alle nummers van 1-22 optellen (1+2+3+… …+22)
/* -- loop01.s */
.text
.global main
main:
mov r1, #0 /* r1 ← 0 */
mov r2, #1 /* r2 ← 1 */
loop:
cmp r2, #22 /* compare r2 and 22 */
bgt end /* branch if r2 > 22 to end */
add r1, r1, r2 /* r1 ← r1 + r2 */
add r2, r2, #1 /* r2 ← r2 + 1 */
b loop
end:
mov r0, r1 /* r0 ← r1 */
bx lr
Hier tellen we van 1 naar 22, we zullen r2 als counter gebruiken. Op lijn 6 zetten we r2 naar 1. De som zal opgeslagen worden in r1. Op het eind verplaatsten we de inhoud van r1 naar r0, waardoor we het resultaat van de som als een error code kunnen zien. Deze laatste stap kan je echter overslaan door direct r0 te gebruiken.
Op lijn 8 vergelijken we r2 (de counter) met 22 Dit update de cpsr, dus op lijn 9 kunnen we het resultaat gaan controleren. Als dat het geval is kunnen we branchen naar het eind (de end: tag). Anders voegen we de waarde van r2 toe aan r1.
Lijn 11 is een belangerijke. Hier voegen we 1 toe aan de waarde van r2. Dit is omdat we van 1 naar 22 aan het tellen zijn we hebben de waarde van r2 al bij de som van r1 geteld. Op regel 12 branchen we weer naar het begin van de loop. Als regel 11 er niet was zou de loop nooit eindigen.
Als we dit uitvoeren zien we het resultaat.
$ ./loop01; echo $? 253
Nu, waarom heb ik 22 gekozen, en geen getal zoals bijvoorbeeld 100. Als we het zouden aanpassen naar 100 zouden we 5050 moeten krijgen, maar:
$ ./loop01; echo $? 186
Hier loopt iets mis. Dit gebeurt omdat de error-code van een programma in linux een getal is van 0 tot 255 (8 bits, 1 byte). Als het resultaat 5050 is, worden enkel de laagste 8 bits van het getal gebruikt. zo word 5050 in binair: 1001110111010, De laagste 8 bits zijn 10111010, wat 186 is. Laat ons GDB gebruiken om het te debuggen.
$ gdb loop ... (gdb) start Temporary breakpoint 1 at 0x8390 Starting program: /home/roger/asm/chapter06/loop01 Temporary breakpoint 1, 0x00008390 in main () (gdb) disas main,+(9*4) Dump of assembler code from 0x8390 to 0x83b4: 0x00008390 <main+0>: mov r1, #0 0x00008394 <main+4>: mov r2, #1 0x00008398 <loop+0>: cmp r2, #100 ; 0x64 0x0000839c <loop+4>: bgt 0x83ac <end> 0x000083a0 <loop+8>: add r1, r1, r2 0x000083a4 <loop+12>: add r2, r2, #1 0x000083a8 <loop+16>: b 0x8398 <loop> 0x000083ac <end+0>: mov r0, r1 0x000083b0 <end+4>: bx lr End of assembler dump.
Als we een breakpoint instellen op 0x00083ac, net voordat we r1 naar r0 verplaatsen:
(gdb) break *0x000083ac (gdb) cont Continuing. Breakpoint 2, 0x000083ac in end () (gdb) disas Dump of assembler code for function end: => 0x000083ac <+0>: mov r0, r1 0x000083b0 <+4>: bx lr End of assembler dump. (gdb) info register r1 r1 0x13ba 5050
Hier zien we wat we verwacht hadden, maar we konden het niet zien door de limieten van error codes.
Er is ook iets aan de gang met onze labels die functies worden. Dit zal ik verder uitleggen in een verder deel.
Dit was alles voor deel 6.
RPI assembler tutorial 5
Tot nu voerden onze kleine programmaatjes de instructies na elkaar uit. Het zou kunnen reageren op bestaande voorwaarden die verschillende instructiereeksen nodig hebben. Dit is het doel van de branch instructies
Een speciaal register
In deel 2 heb ik uitgelegd dat de Raspberrypi’s ARM cpu 16 general-purpose integer registers heeft en ook dat sommige speciale rollen hebben in het programma (zoals r0). Nu wordt dit belangrijk.
Zo is register r15 speciaal omdat het ook nog een andere naam heeft: pc. Register r15 wordt dan ook enkel gebruikt met de naam pc omdat het anders te verwarrend is. r15 is wel correct, maar het brengt gewoon verwarring.
pc staat voor program counter. Dit is de naam die stamt uit het begin van de computers. Dit register wordt ook wel de ip of instructie pointer genoemd in andere architecturen zoals i386. Deze bevat het adres van de volgende instructie die zal worden uitgevoerd.
Wanneer de arm processor een instructie uitvoert kunnen er 2 dingen gebeuren aan het eind. Als de instructie de pc niet aanpast (wat voor de meeste instructies het geval is), word het pc-register met 4 opgeteld. Dit is 4 omdat arm instructies 32bit zijn.
Zodra de processor de instructie heeft uitgevoerd, gaat het de waarde in de program counter gebruiken als het adres voor de volgende instructie. Op deze manier zal als een instructie de program counter niet aanpas, gewoon de volgende instructie worden uitgevoerd. Dit is impliciet sequensen: Eens een instructie is uitgevoerd, dan wordt gewoon de volgende uitgevoerd. Maar als een instructie de program counter aanpast, als bijvoorbeeld er een andere waarde dan 4 aan wordt toegevoegd, kunnen we een andere instructie in het programma uitvoeren (een beetje zoals de GOTO-commando in batch). Dit proces wordt ook branchering genoemd. In ARM gebeurt dit met de branch instructie.
Onvoorwaardelijke branches
Je kan de processor vertellen om onvoorwaardelijk te branchen met de instructie b (wat staat voor branch). Zoals in het volgende voorbeeld:
/* -- branch01.s */ .text .global main main: mov r0, #2 /* r0 ← 2 */ b end /* branch to 'end' */ mov r0, #3 /* r0 ← 3 */ end: bx lr
Als je dit uitvoert dan zal je een error code van 2 zien.
Wat hier gebeurd is dat de instructie ‘b end’ de program counter aanpas naar de instructie met het label ‘end’ en dat is ‘bx lr’, De instructie die wordt uitgevoerd op het einde van het programma. Hierdoor is de instructie ‘mov r0, #3’ nooit uitgevoerd.
op punt is is de b instructie onvoorwaardelijk gebranched. Dit lijkt nutteloos, maar dat is niet het geval. Deze instructie is essentieel in bepaalde gevallen, zeker in combinatie met voorwaardelijke branching.
Voorwaardelijke branches
Als een processor enkel kon branchen zonder voorwaarden dan zou het niet echt handig zijn. Het is veel handiger als er bepaalde voorwaarden voldaan zijn (denk maar aan control-flow tools). Dus een processor moet bepaalde voorwaarden kunnen vergelijken en evalueren.
Voordat we verdergaan moeten we nog een ander register leren kennen: cpsr (Current Program Status Register). Dit register is een beetje speciaal en het direct wijzigingen (met mov etc.) hoort niet bij het idee van branches. Het cpsr register kan bepaalde waarden houden dat kunnen gelezen en aangepast worden tijdens het uitvoeren van een instructie. De waarden van dit register bevatten 4 voorwaarden-codes genaamd: N (negatief), Z (Zero), C (Carry) en V (Overflow). Deze 4 voorwaarden-codes zijn vaak gelezen door branch instructies. Bewerkingsinstructies en speciale test en vergelijkingsinstructies kunnen deze ook aanpassen.
De voorwaarden van deze 4 codes die de cpsr registers aanpassen zijn als volgt:
- N: Deze zal worden ingeschakeld als het resultaat van de instructie negatief is, ander wordt hij uitgeschakeld.
- Z: Deze wordt ingeschakeld als het resultaat nul (zero) is. En uitgeschakeld als het niet zo is.
- C: Deze wordt ingeschakeld als het resultaat een 33ste bit nodig heeft om volledig te zijn. Bijvoorbeeld een optelling die de 32 bit range van integers ‘overflow’. Er is een speciaal geval voor C en aftrekkingen waar niet-lenende aftrekkingen het inschakelen, en anders uitschakelen. Een groot getal aftrekken van een kleiner getal zet C aan, maar het zal uitgeschakeld worden als het omgekeerd is.
- V: Deze zal worden ingeschakeld als het resultaat van de instructie niet kan worden weergegeven in 32bits
Dus we hebben alles wat nodig is om voorwaardelijk te branchen. Laat ons starten met het vergelijken van 2 waarden. Hiervoor gebruiken we de instructie cmp.
cmp r1, r2 /* updates cpsr wanneer "r1 - r2", maar als r1 en r2 niet worden aangepast */
Deze instructie verminderd de waarde van het eerste register met de waarde van het 2e register. Voorbeelden van wat er kan gebeuren:
- Als r2 een waarde had die groter was dan r1, dan zou N worden ingeschakeld.
- Als r1 en r2 dezelfde waarde hebben, dan zou Z worden ingeschakeld, omdat het resultaat dan 0 is.
- Als r1 1 was en r2 0, dan zou C worden ingeschakeld.
- Als r1 het grootste positieve 32bit getal was (2147483647) en r2 -1 was dan zou 2147483648 niet kunnen worden weergegeven in 32 bit, dus zal V worden ingeschakeld.
Hoe kunnen deze opties nuttig zijn:
- EQ (gelijk): Wanner Z is ingeschakeld
- NE (niet gelijk): Wanner Z is uitgeschakeld
- GE (Gelijk of groter dan): Met zowel V als N ingeschakeld of uitgeschakeld (V=N)
- LT (Kleiner dan): Dit is het tegenovergesteld van GE.
- GT (Groter dan): Dit is wanneer Z is uitgeschakeld, maar N en V beide zijn ingeschakeld.
- LE (Kleiner of gelijk aan): Als Z is ingeschakeld, of als N en V niet beide zijn in- of uitgeschakeld.
- MI (Minus, negatief): Als N is ingeschakeld.
- PL (Plus, positief): Als N is uitgeschakeld.
- VS (Overflow Set): Als V is ingeschakeld.
- VC (Overflow clear): Als V is uitgeschakeld.
- HI (Groter): Als C is ingeschakeld en Z is uitgeschakeld.
- LS (Kleiner of hetzelfde): Als C is uit of Z is ingeschakeld.
- CS/HS (Carry Set/Groter of gelijk): Als C is ingeschakeld.
- CC/LO (CarryClear of kleiner): Als C is uitgeschakeld.
Deze instructies kunnen gecombineerd worden met onze b instructie om nieuwe instructies te genereren. Op deze manier zal ‘beq’ enkel branchen als Z 1 is. Als deze voorwaarden niet zijn voldaan, dan wordt de branch genegeerd en zal de volgende instructie worden uitgevoerd. Het is de taak van de programmeur om deze goed te gebruiken en dat de voorwaarden goed zijn voordat er gebranched wordt.
/* -- compare01.s */ .text .global main main: mov r1, #2 /* r1 ← 2 */ mov r2, #2 /* r2 ← 2 */ cmp r1, r2 /* update cpsr condition codes with the value of r1-r2 */ beq case_equal /* branch to case_equal only if Z = 1 */ case_different : mov r0, #2 /* r0 ← 2 */ b end /* branch to end */ case_equal: mov r0, #1 /* r0 ← 1 */ end: bx lr
Als je dit uitvoert zal je een error code van 1 terugkrijgen omdat zowel r1 en r2 dezelfde waarde hebben. Als je r1 naar 3 zet op lijn 5 dan zal je een 2 moeten krijgen. Let op dat bij de case_diffirent: label wel op het einde een onvoorwaardelijke branch naar het end label gaat, omdat het resultaat anders altijd 1 is.
Dit was alles voor deel 5.
Google VS Privacy: Luisteren ze echt af?
<p style=”text-align: left;”>
Onlangs heb ik gemerkt dat elke keer ik in de buurt van een computer waar ik op ben ingelogd over een bepaald onderwerp praat, daarna reclames over dat onderwerp te zien krijgt. En dit is ondertussen meerdere malen gebeurt. Luistert googel werkelijk af, of is het puur toeval?
</p>
<!–more–>
<p style=”text-align: left;”>
</p>
<p style=”text-align: left;”>
</p>
<p style=”text-align: left;”>
Soms lijkt het te goed om waar te zijn, maar het is in het verleden al meerdere keren bewezen. Zo stuurt Google meer dan 500 keer per dag locatiepings die gebruikt worden voor het up to date houden van file gegevens op Google maps. Ze gebruiken deze data ook om advertenties beter op je af te stemmen. Zo krijg je in het buitenland reclame voor producten die verkocht worden in dat land. Dit gebeurt eigenlijk met alle data die Google van je verkrijgt.
</p> Zo hebben bepaalde mensen (waaronder ikzelf) al ontdekt dat als ze het over onderwerp x hebben, een paar dagen nadien krijg je reclame in het thema van onderwerp x. Dit gebeurde enkel op computers met Google Chrome erop geïnstalleerd. Chrome installeert stiekem ook een ‘afluister’ programma, en zet de microfoon standaard op aan. Hierdoor kan het dus afluisteren. Ook zorgt de ‘Ok Google’ functie van de Google assistent op je smartphone dat Google kan afluisteren. Deze data wordt ook niet door je eigen toestel verwerkt, maar doorgestuurd naar Google servers, waar het verwerkt wordt. Dit wilt dus zeggen dat Google eigenlijk als Chrome openstaat altijd de mogelijkheid heeft om audio te ‘livestreamen’. In de open-source versie van Chrome, Chromium, stond diezelfde ‘black box’ software, maar die is verwijderd na privacy problemen. In Google Chrome zit dit nog altijd, hier kan je eigenlijk niets aan doen omdat je daar toestemming voor geeft in de EULA, en Google’s diensten gebruiken zonder die te accepteren is onmogelijk. Op
[nomoregoogle.com](https://nomoregoogle.com/) kan je alternatieven vinden voor vrijwel elke dienst die Google bied.
Skyz update 8
Ik heb skyz verplaatst van skyz.vincentlammens.be naar projects.vincentlammens.be/p/skyz/, zodat alle projecten centraal staan. Dus als je bookmarks hebt, of het op je startscherm hebt gezet pas deze aan. Ik heb ook een redirect ingesteld, dus mocht je naar de oude url surfen word je voorlopig doorgestuurd.
RPI Assembler tutorial 4
Als we de fundering leren kennen van ARM assembler, zullen de voorbeelden langer worden. Omdat bij lange programma’s het eenvoudiger word om fouten te maken is het handig dat er gewerkt word met een debugger zoals de GNU Debugger (GDB) om de assembler code te debuggen. Hier zal ik in uitleggen hoe je assembler direct debugt.
GDB
We zullen het voorbeeld store01 van deel 3 gebruiken. Start de GDB met als argumenten het programma dat je gaat debuggen
gdb --args ./store01
Nu zijn we in de interactieve mode van de GDB. Hiermee kan je commando’s uitvoeren om acties binnen de debugger uit te voeren. Er is een help command ingebouwd (gewoon help). met de quit command sluit je de debugger. Als je start typt zal je de het proces starten.
(gdb) start
Temporary breakpoint 1 at 0x8390
Starting program: /home/pi/asm/Deel3/store01
Temporary breakpoint 1, 0x00008390 in main ()
De debugger is gestopt bij de functie main. Dit is handig omdat we de eerste initialisatie stappen hebben overgeslagen. Nu is de debugger aan het wachten aan de eerste instructie van de main functie.
(gdb) disassemble Dump of assembler code for function main: => 0x00008390 : ldr r1, [pc, #40] ; 0x83c0 0x00008394 : mov r3, #3 0x00008398 : str r3, [r1] 0x0000839c : ldr r2, [pc, #32] ; 0x83c4 0x000083a0 : mov r3, #4 0x000083a4 : str r3, [r2] 0x000083a8 : ldr r1, [pc, #16] ; 0x83c0 0x000083ac : ldr r1, [r1] 0x000083b0 : ldr r2, [pc, #12] ; 0x83c4 0x000083b4 : ldr r2, [r2] 0x000083b8 : add r0, r1, r2 0x000083bc : bx lr End of assembler dump.
De instructie die naar het geheugenadres van de variabele gaat zijn anders, dit is nu nog geen probleem. de pijl => wijst naar de instructie die zal worden uitgevoerd. Voordat we deze uitvoeren laat ons de registers controleren.
(gdb) info registers r0 r1 r2 r3 r0 0x1 1 r1 0xbefff744 3204446020 r2 0xbefff74c 3204446028 r3 0x8390 33680
We kunnen de registers aanpassen met de functie p (staat voor print), maar ook de effecten zien:
(gdb) p $r0 = 2 $1 = 2 (gdb) info registers r0 r1 r2 r3 r0 0x2 2 r1 0xbefff744 3204446020 r2 0xbefff74c 3204446028 r3 0x8390 33680
De debugger heeft $1 weergegeven. Dit is het resultaat en we kunnen het gebruiken als we het nodig hebben. Nu is dit nog niet zo handig, maar bij grote programma’s zal dit nuttiger worden. Met deze command zal je de eerste instructie kunnen uitvoeren
(gdb) stepi 0x00008394 in main ()
Hier is niet veel gebeurd. Gebruik dissasemble opnieuw
(gdb) disassemble Dump of assembler code for function main: 0x00008390 : ldr r1, [pc, #40] ; 0x83c0 => 0x00008394 : mov r3, #3 0x00008398 : str r3, [r1] 0x0000839c : ldr r2, [pc, #32] ; 0x83c4 0x000083a0 : mov r3, #4 0x000083a4 : str r3, [r2] 0x000083a8 : ldr r1, [pc, #16] ; 0x83c0 0x000083ac : ldr r1, [r1] 0x000083b0 : ldr r2, [pc, #12] ; 0x83c4 0x000083b4 : ldr r2, [r2] 0x000083b8 : add r0, r1, r2 0x000083bc : bx lr End of assembler dump.
Als we kijken wat er in R1 is veranderd zullen we zien dat het het adres is voor myvar1
(gdb) info register r1 r1 0x10564 66916
Als we naar de inhoud zouden kijken van deze variabele zullen we zien dat het 0 is (wat we hadden ingesteld). Volgende stap:
(gdb) stepi 0x00008398 in main () (gdb) disas Dump of assembler code for function main: 0x00008390 : ldr r1, [pc, #40] ; 0x83c0 0x00008394 : mov r3, #3 => 0x00008398 : str r3, [r1] 0x0000839c : ldr r2, [pc, #32] ; 0x83c4 0x000083a0 : mov r3, #4 0x000083a4 : str r3, [r2] 0x000083a8 : ldr r1, [pc, #16] ; 0x83c0 0x000083ac : ldr r1, [r1] 0x000083b0 : ldr r2, [pc, #12] ; 0x83c4 0x000083b4 : ldr r2, [r2] 0x000083b8 : add r0, r1, r2 0x000083bc : bx lr End of assembler dump.
Als we kijken wat er gebeurd is met r3:
(gdb) info registers r3 r3 0x3 3
Dit is wat we verwacht hebben dus volgende stap:
(gdb) stepi 0x0000839c in main () (gdb) disas Dump of assembler code for function main: 0x00008390 : ldr r1, [pc, #40] ; 0x83c0 0x00008394 : mov r3, #3 0x00008398 : str r3, [r1] => 0x0000839c : ldr r2, [pc, #32] ; 0x83c4 0x000083a0 : mov r3, #4 0x000083a4 : str r3, [r2] 0x000083a8 : ldr r1, [pc, #16] ; 0x83c0 0x000083ac : ldr r1, [r1] 0x000083b0 : ldr r2, [pc, #12] ; 0x83c4 0x000083b4 : ldr r2, [r2] 0x000083b8 : add r0, r1, r2 0x000083bc : bx lr End of assembler dump.
Als we nu naar het einde gaan:
(gdb) continue Continuing. [Inferior 1 (process 3080) exited with code 07]
Nu zien we dat het heeft gestopt met code 07, wat het resultaat is!
Dit was alles voor deel 4