V předchozím článku jsme si ukázali, jakým způsobem je možné zkombinovat zdrojový kód napsaný v programovacím jazyku C s kódem psaným v assembleru. Přitom jsme se zaměřili na 32bitovou architekturu x86 (i386 až i686) a 64bitovou architekturu x86-64. Dnes si ukážeme kombinaci jazyka C a assembleru na mikroprocesorech s architekturou ARM.

Obsah

1. Kombinace assembleru a programovacího jazyka C na procesorech ARM

2. Seznam obecných jmen registrů použitých pro specifikaci vstupních a výstupních operandů

3. Zápis komentářů, zpracování bloku asm překladačem céčka

4. Pořadí zápisu operandů, specifikace konstant a jmen registrů

5. Vrácení hodnoty z bloku napsaného v assembleru

6. Větší množství výstupních operandů

7. Vstupní a výstupní operandy

8. Použití symbolických jmen v assemblerovském bloku: cesta k čitelnému zdrojovému kódu

9. Makefile určený pro překlad dnešních demonstračních příkladů

10. Repositář s demonstračními příklady

11. Odkazy na Internetu

1. Kombinace assembleru a programovacího jazyka C na procesorech ARM

Již z předchozího článku víme, že překladač GNU C (ale nejenom on) podporuje zápis bloků s instrukcemi assembleru přímo do zdrojových kódů psaných v céčku či C++. To může být velmi výhodné, protože nám to umožňuje nejenom psaní celých subrutin (podprogramů) v assembleru, ale i kombinaci C a assembleru v rámci jedné funkce, tj. bez nutnosti explicitního volání subrutiny, předání parametrů a návratu ze subrutiny apod. Minule jsme si taktéž ukázali způsob specifikace vstupních a výstupních operandů uvnitř bloku asm či __asm__. Dnes budeme v popisu této problematiky pokračovat, ovšem zaměříme se především na 32bitovou architekturu ARM, která se od architektury x86/x86-64 v mnoha ohledech odlišuje. Týká se to samozřejmě i způsobu zápisu assemblerovských bloků, specifikací operandů atd.

Všechny demonstrační příklady, s nimiž se dnes seznámíme, byly odzkoušeny na dnes již postarším GCC překladači verze 4.6.3, kterou naleznete v původních instalacích Raspbianu (testování probíhalo na Raspberry Pi):

gcc --version
gcc (Debian 4.6.3-14+rpi1) 4.6.3
Copyright (C) 2011 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Verze GNU assembleru použitá pro otestování demonstračních příkladů:

as -version
GNU assembler (GNU Binutils for Debian) 2.24.51.20140425
Copyright (C) 2014 Free Software Foundation, Inc.
This program is free software; you may redistribute it under the terms of
the GNU General Public License version 3 or later.
This program has absolutely no warranty.
This assembler was configured for a target of `arm-linux-gnueabihf'.

Poznámka: demonstrační příklady budou samozřejmě funkční i na novějším překladači a/nebo novější verzi GNU Assembleru. Budou taktéž funkční na novějších procesorech ARM s výjimkou řady Cortex-M, která neobsahuje podporu pro původní ARMovskou instrukční sadu.

2. Seznam obecných jmen registrů použitých pro specifikaci vstupních a výstupních operandů

Minule jsme si řekli, že při specifikaci vstupních a výstupních operandů celého assemblerovského bloku je nutné specifikovat, do jakých registrů se tyto operandy budou ukládat. Všechny příklady používaly obecné označení „r“ značící libovolný pracovní registr. Na platformě x86/x86-64 je možné registr zvolit explicitně, a to náhradou znaku „r“ v řetězci „=r“ za jiný znak podle následující tabulky. Povšimněte si, že (alespoň prozatím) není možné explicitně použít vyšších osm pracovních registrů, tj. registry pojmenované R8R15. V samotném assemblerovském kódu však tyto registry samozřejmě lze využít:

Náhrada „r“ Význam
a %rax, %eax, %ax, %al
b %rbx, %ebx, %bx, %bl
c %rcx, %ecx, %cx, %cl
d %rdx, %edx, %dx, %dl
S %rsi, %esi, %si
D %rdi, %edi, %di

U 32bitových mikroprocesorů a mikrořadičů ARM se kromě běžných pracovních registrů spadajících do kategorie „r“ mohou používat i následující skupiny registrů. Povšimněte si, že některé skupiny jsou platné pouze v režimu ARM (původní RISCová instrukční sada), jiné naopak pouze v režimu Thumb. Některé skupiny dále vyžadují matematický koprocesor (VFP…) či rozšíření NEON:

Skupina registrů Omezení Význam
r × libovolný pracovní registr
l × pracovní registr r0-r7 v režimu Thumb
h × pracovní registr r8-r15 v režimu Thumb
b Thumb pracovní registr r0-r7 popř. ukazatel na vrchol zásobníku
f FPA registr f0-f7
t VFP registr s0-s31 (single)
x VFP registr d0-d7 (double)
w VFP registr d0-d15 (double)
w VFPv3 registr d0-d31 (double)

Poznámka: přesnou specifikaci registru (například „r0“) prozatím nelze provést.

3. Zápis komentářů, zpracování bloku asm překladačem céčka

Praktickou část začneme velmi jednoduchým příkladem, na němž si ukážeme jeden z rozdílů mezi assemblerovským blokem psaným pro architektury x86 a x86-64 na jedné straně a tímtéž blokem psaným pro ARMovskou 32bitovou architekturu na straně druhé. Nejprve se podívejme, jak se zapisují komentáře při použití procesorů Intel či AMD. Každý komentář v assemblerovském bloku začíná znakem # a platí až do konce aktuálního řádku:

#include <stdio.h>

int main()
{
    __asm__ __volatile__(
        "nop   \n\t"
        " nop   \n\t"
        "  nop   \n\t"
        "    nop   \n\t"
        "    nop  # komentar \n\t"
        : /* zadne vystupni registry */
        : /* zadne vstupni operandy */
        : /* zadne registry pouzivane uvnitr kodu */
    );

    return 0;
}

Naprosto stejný příklad, ovšem psaný pro 32bitovou architekturu ARM, používá odlišné komentáře. Ty začínají znakem @ a taktéž platí až do konce aktuálního řádku:

#include <stdio.h>

int main()
{
    __asm__ __volatile__(
        "nop   \n\t"
        " nop   \n\t"
        "  nop   \n\t"
        "    nop   \n\t"
        "    nop  @ komentar \n\t"
        : /* zadne vystupni registry */
        : /* zadne vstupni operandy */
        : /* zadne registry pouzivane uvnitr kodu */
    );

    return 0;
}

Pokud se chcete podívat na způsob zpracování takového bloku překladačem céčka, lze použít příkaz:

gcc -S -c test.c -o test.s

4. Pořadí zápisu operandů, specifikace konstant a jmen registrů

Jména běžných pracovních registrů odpovídají konvencím používaným společností ARM, tj. registry mají přiřazena jména r0r15. U některých registrů, konkrétně u posledních třech registrů, je možné použít i jmenný alias, což se týká především pc (programový čítač), lr (link register) a sp (ukazatel na vrchol zásobníku).

Vstupní operandy se zapisují způsobem „r“ (proměnná_či_konstanta). Operandy se od sebe oddělují čárkou a od výstupních operandů jsou odděleny dvojtečkou:

: "r"  (ix),  "r" (iy)  /* vstupni operandy */

Výstupní operandy se zapisují způsobem „=r“ (proměnná) a pokud je jich větší množství, opět se pro jejich oddělení používá čárka:

: "=r" (ox), "=r" (oy)  /* vystupni operandy */

Na konci celého bloku se uvádí nepovinný seznam registrů, které jsou modifikovány („zničeny“) uvnitř assemblerovského bloku. Překladač programovacího jazyka C tuto informaci potřebuje, aby do těchto registrů před zavoláním assemblerovského bloku neuložil důležité údaje (připomeňme si, že samotný překladač se nijak nesnaží o hlubší analýzu assemblerovského bloku):

: "r0", "r1"            /* registry pouzivane uvnitr kodu */

Následující assemblerovský blok má:

  1. Dva vstupní operandy, které jsou naplněny z proměnných ix a iy.
  2. Dva výstupní operandy, které jsou naplněny z proměnných ox a oy.
  3. Specifikaci pracovních registrů r0 a r1 „zničených“ uvnitř bloku.
    __asm__ __volatile__(
        ""                      /* řetězec, který se po expanzi předá do assembleru */
        : "=r" (ox), "=r" (oy)  /* vystupni operandy */
        : "r"  (ix),  "r" (iy)  /* vstupni operandy */
        : "r0", "r1"            /* registry pouzivane uvnitr kodu */
    );

5. Vrácení hodnoty z bloku napsaného v assembleru

Zkusme si nyní vytvořit assemblerovský blok, který nemá žádné vstupní operandy, ovšem má jeden operand výstupní. V tomto bloku se nejdříve do pracovního registru r0 vloží konstanta 42 a ta se ve druhé instrukci přenese do výstupního operandu, který je v bloku reprezentován svým pořadovým číslem %0. Výsledek je uložen do globální proměnné result, která je následně vypsána na standardní výstup běžnou céčkovskou funkcí printf():

#include <stdio.h>

unsigned long result;

int main()
{
    __asm__ __volatile__(
        "mov    r0, #42    \n\t"
        "mov    %0, r0     \n\t"
        : "=r" (result)  /* vystupni operand */
        :                /* zadne vstupni operandy */
        : "r0"           /* registry pouzivane uvnitr kodu */
    );

    printf("%ld\n", result);

    return 0;
}

Pokud výše uvedený zdrojový kód přeložíme s volbou -s, můžeme ve vygenerovaném souboru najít i náš blok, v němž je jasně patrné, jak došlo k náhradě operandu specifikovaného svým pořadovým číslem %0 za registr r2:

#APP
@ 7 "asm_in_c_4.c" 1
        mov    r0, #42    
        mov    r2, r0     

6. Větší množství výstupních operandů

Na rozdíl od běžných funkcí mohou assemblerovské bloky vytvořit větší množství výstupních hodnot, které jsou reprezentovány výstupními operandy. V předchozím příkladu jsme použili jen jeden výstupní operand, nyní si ukážeme použití dvou operandů, jejichž hodnoty mají být na konci assemblerovského bloku uloženy do globálních proměnných nazvaných x a y. Pro zajímavost je v assemblerovském bloku použita instrukce mov, která hodnotu vstupního operandu (registr r0) posune doleva o jeden bit (jedná se o logický posun), což je v instrukční sadě 32bitových mikroprocesorů ARM plně podporováno:

#include <stdio.h>

unsigned long x = 10;
unsigned long y = 20;

int main()
{
    printf("%ld\t%ld\n", x, y);

    __asm__ __volatile__(
        "mov    r0, #42          \n\t"
        "mov    r1, r0, lsl #1   \n\t"
        "mov    %0, r0           \n\t"
        "mov    %1, r1           \n\t"
        : "=r" (x), "=r" (y)  /* vystupni operandy */
        :                     /* zadne vstupni operandy */
        : "r0", "r1"          /* registry pouzivane uvnitr kodu */
    );

    printf("%ld\t%ld\n", x, y);

    return 0;
}

Po překladu a spuštění tohoto příkladu by se na standardní výstup měly vypsat původní hodnoty proměnných x a y (ty budou následně přepsány) a na druhém řádku jejich nové hodnoty (42 a 42×2):

10      20
42      84

Pro zajímavost se podívejme, jak se náš assemblerovský blok přeložil do výsledného souboru. Vidíme, že překladač vybral pracovní registry r12 a r2 (pro registr r12 je použil alias ip):

#APP
@ 10 "asm_in_c_4.c" 1
        mov    r0, #42          
        mov    r1, r0, lsl #1   
        mov    ip, r0           
        mov    r2, r1           

7. Vstupní a výstupní operandy

V dalším příkladu je ukázána kombinace vstupních a výstupních operandů. Povšimněte si především toho, že výstupní operandy jsou uvedeny na prvním místě a proto jsou jim přiřazena pořadová čísla %0 a %1. Až potom následují vstupní operandy s pořadovými čísly %2 a %3 (toto číslování může být zpočátku matoucí). I v tomto příkladu používáme instrukci mov kombinovanou s operací logického posunu doprava o dva bity (jen pro ukázku možností ARMovských procesorů):

#include <stdio.h>

unsigned long ix = 100;
unsigned long iy = 200;
unsigned long ox;
unsigned long oy;

int main()
{
    printf("%ld\t%ld\n", ix, iy);

    __asm__ __volatile__(
        "mov    r0, %2          \n\t"
        "mov    r1, %3          \n\t"
        "mov    %0, r0, lsr #2  \n\t"
        "mov    %1, r1, lsr #2  \n\t"
        : "=r" (ox), "=r" (oy)  /* vystupni operandy */
        : "r" (ix),  "r" (iy)   /* vstupni operandy */
        : "r0", "r1"            /* registry pouzivane uvnitr kodu */
    );

    printf("%ld\t%ld\n", ox, oy);

    return 0;
}

Po překladu a spuštění tohoto příkladu by se na standardní výstup měly vypsat hodnoty vstupních proměnných ix a iy a na druhém řádku hodnoty proměnných výstupních ox a oy:

100      200
25       50

Opět se podívejme na způsob překladu. První čtyři instrukce naplní obsahy pracovních registrů vstupními proměnnými, následuje vlastní assemblerovský blok a následně uložení výsledků do výstupních proměnných:

        ldr     r3, .L2+4
        ldr     r3, [r3, #0]
        ldr     r2, .L2+8
        ldr     r2, [r2, #0]
#APP
@ 12 "asm_in_c_5.c" 1
        mov    r0, r3          
        mov    r1, r2          
        mov    ip, r0, lsr #2  
        mov    r2, r1, lsr #2  
        
@ 0 "" 2
        ldr     r3, .L2+12
        str     ip, [r3, #0]
        ldr     r3, .L2+16
        str     r2, [r3, #0]

Pro pochopení způsobu adresování (.L2+12 atd.) je nutné se podívat na datovou sekci vygenerovaného souboru. Každé slovo má šířku čtyři bajty:

.L2:
        .word   .LC0
        .word   ix
        .word   iy
        .word   ox
        .word   oy

8. Použití symbolických jmen v assemblerovském bloku: cesta k čitelnému zdrojovému kódu

Již minule jsme se zmínili o možnosti použití symbolických jmen vstupních a výstupních operandů v assemblerovském bloku. Tyto operandy je nejdříve zapotřebí pojmenovat, přičemž jména se uvádí v hranatých závorkách:

: [output1] "=r" (ox),  /* vystupni operandy */
  [output2] "=r" (oy)
: [input1]  "r" (ix),   /* vstupni operandy */
  [input2]  "r" (iy)

Následně lze tato jména použít v assemblerovském bloku, nesmíme však zapomenout na uvedení znaku procenta před symbolické jméno:

"mov    r0, %[input1]           \n\t"
"mov    r1, %[input2]           \n\t"
"mov    %[output1], r0, lsr #2  \n\t"
"mov    %[output2], r1, lsr #2  \n\t"

Demonstrační příklad popsaný v předchozí kapitole můžeme velmi snadno přepsat do čitelnější podoby:

#include <stdio.h>

unsigned long ix = 100;
unsigned long iy = 200;
unsigned long ox;
unsigned long oy;

int main()
{
    printf("%ld\t%ld\n", ix, iy);

    __asm__ __volatile__(
        "mov    r0, %[input1]           \n\t"
        "mov    r1, %[input2]           \n\t"
        "mov    %[output1], r0, lsr #2  \n\t"
        "mov    %[output2], r1, lsr #2  \n\t"
        : [output1] "=r" (ox),  /* vystupni operandy */
          [output2] "=r" (oy)
        : [input1]  "r" (ix),   /* vstupni operandy */
          [input2]  "r" (iy)
        : "r0", "r1"            /* registry pouzivane uvnitr kodu */
    );

    printf("%ld\t%ld\n", ox, oy);

    return 0;
}

Překlad proběhne prakticky totožným způsobem:

        ldr     r3, .L2+4
        ldr     r3, [r3, #0]
        ldr     r2, .L2+8
        ldr     r2, [r2, #0]
#APP
@ 12 "asm_in_c_6.c" 1
        mov    r0, r3           
        mov    r1, r2           
        mov    ip, r0, lsr #2  
        mov    r2, r1, lsr #2  
        
@ 0 "" 2
        ldr     r3, .L2+12
        str     ip, [r3, #0]
        ldr     r3, .L2+16
        str     r2, [r3, #0]

9. Makefile určený pro překlad dnešních demonstračních příkladů

Všechny demonstrační příklady, které jsme si v dnešním článku ukázali, lze přeložit příkazem make s využitím následujícího souboru Makefile. Tento soubor si raději stáhněte přímo z repositáře, neboť jen tak budete mít jistotu, že se nenahradí znaky pro Tab za mezery:

# Parametry prekladace.
CFLAGS=-Wall -O9

# Vychozi pravidlo pro vytvoreni vysledne spustitelne aplikace.
all:    asm_in_c_0.s asm_in_c_0 \
        asm_in_c_1.s asm_in_c_1 \
        asm_in_c_2.s asm_in_c_2 \
        asm_in_c_3.s asm_in_c_3 \
        asm_in_c_4.s asm_in_c_4 \
        asm_in_c_5.s asm_in_c_5 \
        asm_in_c_6.s asm_in_c_6 \
        asm_in_c_7.s asm_in_c_7 \
        asm_in_c_8.s asm_in_c_8 \
        asm_in_c_9.s asm_in_c_9 \
        asm_in_c_10.s asm_in_c_10 \
        asm_in_c_11.s asm_in_c_11

clean:
        rm -f *.o
        rm -f *.s
        rm -f asm_in_c_[0-9]+

# Pravidlo pro slinkovani vsech objektovych souboru a vytvoreni
# vysledne spustitelne aplikace.
$(PROGNAME):    $(PROGNAME).o
        $(CC) -o $@ $(LDFLAGS) $<

# Pravidlo pro preklad kazdeho zdrojoveho souboru do prislusneho
# objektoveho souboru.
%.o:    %.c
        $(CC) $(CFLAGS) -c $< -o $@

# Pravidlo pro preklad kazdeho zdrojoveho souboru do prislusneho
# assemblerovskeho vysledku.
%.s:    %.c
        $(CC) $(CFLAGS) -S -c $< -o $@

10. Repositář s demonstračními příklady

Všechny demonstrační příklady byly, podobně jako v prakticky všech předchozích částech tohoto seriálu, společně s podpůrným skriptem připraveným pro jejich překlad, uloženy do GIT repositáře dostupného na adrese https://github.com/tisnik/presentations/. Všechny zmíněné příklady jsou určeny pro překladač GNU C (podrobnosti o konkrétních verzích jsou uvedeny v úvodní kapitole):

# Soubor Odkaz do repositáře
1 asm_in_c_0.c https://github.com/tisnik/presentations/blob/master/assembler/asm_in_c_arm/asm_in_c_0.c
2 asm_in_c_1.c https://github.com/tisnik/presentations/blob/master/assembler/asm_in_c_arm/asm_in_c_1.c
3 asm_in_c_2.c https://github.com/tisnik/presentations/blob/master/assembler/asm_in_c_arm/asm_in_c_2.c
4 asm_in_c_3.c https://github.com/tisnik/presentations/blob/master/assembler/asm_in_c_arm/asm_in_c_3.c
5 asm_in_c_4.c https://github.com/tisnik/presentations/blob/master/assembler/asm_in_c_arm/asm_in_c_4.c
6 asm_in_c_5.c https://github.com/tisnik/presentations/blob/master/assembler/asm_in_c_arm/asm_in_c_5.c
7 asm_in_c_6.c https://github.com/tisnik/presentations/blob/master/assembler/asm_in_c_arm/asm_in_c_6.c
8 asm_in_c_7.c https://github.com/tisnik/presentations/blob/master/assembler/asm_in_c_arm/asm_in_c_7.c
9 asm_in_c_8.c https://github.com/tisnik/presentations/blob/master/assembler/asm_in_c_arm/asm_in_c_8.c
10 asm_in_c_9.c https://github.com/tisnik/presentations/blob/master/assembler/asm_in_c_arm/asm_in_c_9.c
11 asm_in_c_10.c https://github.com/tisnik/presentations/blob/master/assembler/asm_in_c_arm/asm_in_c_10.c
12 asm_in_c_11.c https://github.com/tisnik/presentations/blob/master/assembler/asm_in_c_arm/asm_in_c_11.c

Poznámka: poslední příklady budou podrobněji popsány příště.

11. Odkazy na Internetu

  1. ARM GCC Inline Assembler Cookbook
    http://www.ethernut.de/en/documents/arm-inline-asm.html
  2. Extended Asm – Assembler Instructions with C Expression Operands
    https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html
  3. ARM inline asm secrets
    http://hardwarebug.org/2010/07/06/arm-inline-asm-secrets/
  4. How to Use Inline Assembly Language in C Code
    https://gcc.gnu.org/onlinedocs/gcc/Using-Assembly-Language-with-C.html#Using-Assembly-Language-with-C
  5. GCC-Inline-Assembly-HOWTO
    http://ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html
  6. A Brief Tutorial on GCC inline asm (x86 biased)
    http://www.osdever.net/tutorials/view/a-brief-tutorial-on-gcc-inline-asm
  7. GCC Inline ASM
    http://locklessinc.com/articles/gcc_asm/
  8. Cortex-A35
    https://www.arm.com/products/processors/cortex-a/cortex-a35-processor.php
  9. Cortex-A53
    https://www.arm.com/products/processors/cortex-a/cortex-a53-processor.php
  10. Cortex-A57
    https://www.arm.com/products/processors/cortex-a/cortex-a57-processor.php
  11. Cortex-A72
    https://www.arm.com/products/processors/cortex-a/cortex-a72-processor.php
  12. Cortex-A73
    https://www.arm.com/products/processors/cortex-a/cortex-a73-processor.php
  13. System cally pro AArch64 na Linuxu
    https://github.com/torvalds/linux/blob/master/include/uapi/asm-generic/unistd.h
  14. Architectures/AArch64 (FedoraProject.org)
    https://fedoraproject.org/wiki/Architectures/AArch64
  15. SIG pro AArch64 (CentOS)
    https://wiki.centos.org/SpecialInterestGroup/AltArch/AArch64
  16. The ARMv8 instruction sets
    http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.den0024a/ch05s01.html
  17. A64 Instruction Set
    https://developer.arm.com/products/architecture/instruction-sets/a64-instruction-set
  18. Switching between the instruction sets
    http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.den0024a/ch05s01.html
  19. The A64 instruction set
    http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.den0024a/ch05s01.html
  20. Introduction to ARMv8 64-bit Architecture
    https://quequero.org/2014/04/introduction-to-arm-architecture/
  21. MCU market turns to 32-bits and ARM
    http://www.eetimes.com/document.asp?doc_id=1280803
  22. Cortex-M0 Processor (ARM Holdings)
    http://www.arm.com/products/processors/cortex-m/cortex-m0.php
  23. Cortex-M0+ Processor (ARM Holdings)
    http://www.arm.com/products/processors/cortex-m/cortex-m0plus.php
  24. ARM Processors in a Mixed Signal World
    http://www.eeweb.com/blog/arm/arm-processors-in-a-mixed-signal-world
  25. ARM Architecture (Wikipedia)
    https://en.wikipedia.org/wiki/ARM_architecture
  26. ARM Documentation: B, BL, BX, BLX, and BXJ
    http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0204j/Cihfddaf.html
  27. Branch and Call Sequences Explained
    https://community.arm.com/groups/processors/blog/2013/09/25/branch-and-call-sequences-explained
  28. Improving ARM Code Density and Performance
    New Thumb Extensions to the ARM Architecture Richard Phelan
  29. Aarch64 Register and Instruction Quick Start
    https://wiki.cdot.senecacollege.ca/wiki/Aarch64_Register_and_Instruction_Quick_Start
  30. Exploring AArch64 assembler – Chapter 1
    http://thinkingeek.com/2016/10/08/exploring-aarch64-assembler-chapter1/
  31. Exploring AArch64 assembler – Chapter 2
    http://thinkingeek.com/2016/10/08/exploring-aarch64-assembler-chapter-2/
  32. The ARM Processor Architecture
    http://www.arm.com/products/processors/technologies/instruction-set-architectures.php
  33. Thumb-2 instruction set
    http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0344c/Beiiegaf.html
  34. Introduction to ARM thumb
    http://www.eetimes.com/discussion/other/4024632/Introduction-to-ARM-thumb
  35. ARM, Thumb, and ThumbEE instruction sets
    http://www.keil.com/support/man/docs/armasm/armasm_CEGBEIJB.htm
  36. An Introduction to ARM Assembly Language
    http://dev.emcelettronica.com/introduction-to-arm-assembly-language
  37. Processors – ARM
    http://www.arm.com/products/processors/index.php
  38. The ARM Instruction Set
    http://simplemachines.it/doc/arm_inst.pdf
  39. ARM Architecture (Wikipedia)
    http://en.wikipedia.org/wiki/ARM_architecture
  40. C Functions Without Arguments
    https://eklitzke.org/c-functions-without-arguments
  41. GNU Assembler Examples
    http://cs.lmu.edu/~ray/notes/gasexamples/
  42. Simply FPU
    http://www.website.masmforum.com/tutorials/fptute/
  43. Art of Assembly language programming: The 80×87 Floating Point Coprocessors
    https://courses.engr.illinois.edu/ece390/books/artofasm/CH14/CH14-3.html
  44. Art of Assembly language programming: The FPU Instruction Set
    https://courses.engr.illinois.edu/ece390/books/artofasm/CH14/CH14-4.html
  45. INTEL 80387 PROGRAMMER’S REFERENCE MANUAL
    http://www.ragestorm.net/downloads/387intel.txt
  46. x86 Instruction Set Reference: FLD
    http://x86.renejeschke.de/html/file_module_x86_id_100.html
  47. x86 Instruction Set Reference: FLD1/FLDL2T/FLDL2E/FLDPI/FLDLG2/FLDLN2/FLDZ
    http://x86.renejeschke.de/html/file_module_x86_id_101.html
  48. x86 Instruction Set Reference: FLD
    http://x86.renejeschke.de/html/file_module_x86_id_100.html
  49. x86 Instruction Set Reference: FST/FSTP
    http://x86.renejeschke.de/html/file_module_x86_id_117.html
  50. x86 Instruction Set Reference: BTC
    http://x86.renejeschke.de/html/file_module_x86_id_23.html
  51. x86 Instruction Set Reference: BTR
    http://x86.renejeschke.de/html/file_module_x86_id_24.html
  52. x86 Instruction Set Reference: BTS
    http://x86.renejeschke.de/html/file_module_x86_id_25.html
  53. x86 Instruction Set Reference: BSF
    http://x86.renejeschke.de/html/file_module_x86_id_19.html
  54. x86 Instruction Set Reference: BSR
    http://x86.renejeschke.de/html/file_module_x86_id_20.html
  55. x86 Instruction Set Reference: BSWAP
    http://x86.renejeschke.de/html/file_module_x86_id_21.html
  56. x86 Instruction Set Reference: XCHG
    http://x86.renejeschke.de/html/file_module_x86_id_328.html
  57. x86 Instruction Set Reference: SETcc
    http://x86.renejeschke.de/html/file_module_x86_id_288.html
  58. X86 Assembly/Arithmetic
    https://en.wikibooks.org/wiki/X86_Assembly/Arithmetic
  59. Art of Assembly – Arithmetic Instructions
    http://oopweb.com/Assembly/Documents/ArtOfAssembly/Volume/Chapter_6/CH06-2.html
  60. The GNU Assembler Tutorial
    http://tigcc.ticalc.org/doc/gnuasm.html
  61. The GNU Assembler – macros
    http://tigcc.ticalc.org/doc/gnuasm.html#SEC109
  62. ARM subroutines & program stack
    http://www.toves.org/books/armsub/
  63. Generating Mixed Source and Assembly List using GCC
    http://www.systutorials.com/240/generate-a-mixed-source-and-assembly-listing-using-gcc/
  64. Calling subroutines
    http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.kui0100a/armasm_cihcfigg.htm
  65. ARM Assembly Language Programming
    http://peter-cockerell.net/aalp/html/frames.html
  66. ASM Flags
    http://www.cavestory.org/guides/csasm/guide/asm_flags.html
  67. Status Register
    https://en.wikipedia.org/wiki/Status_register
  68. Intel x86 JUMP quick reference
    http://unixwiz.net/techtips/x86-jumps.html
  69. Linux assemblers: A comparison of GAS and NASM
    http://www.ibm.com/developerworks/library/l-gas-nasm/index.html
  70. Programovani v assembleru na OS Linux
    http://www.cs.vsb.cz/grygarek/asm/asmlinux.html
  71. Is it worthwhile to learn x86 assembly language today?
    https://www.quora.com/Is-it-worthwhile-to-learn-x86-assembly-language-today?share=1
  72. Why Learn Assembly Language?
    http://www.codeproject.com/Articles/89460/Why-Learn-Assembly-Language
  73. Is Assembly still relevant?
    http://programmers.stackexchange.com/questions/95836/is-assembly-still-relevant
  74. Why Learning Assembly Language Is Still a Good Idea
    http://www.onlamp.com/pub/a/onlamp/2004/05/06/writegreatcode.html
  75. Assembly language today
    http://beust.com/weblog/2004/06/23/assembly-language-today/
  76. Assembler: Význam assembleru dnes
    http://www.builder.cz/rubriky/assembler/vyznam-assembleru-dnes-155960cz
  77. Assembler pod Linuxem
    http://phoenix.inf.upol.cz/linux/prog/asm.html
  78. AT&T Syntax versus Intel Syntax
    https://www.sourceware.org/binutils/docs-2.12/as.info/i386-Syntax.html
  79. Linux Assembly website
    http://asm.sourceforge.net/
  80. Using Assembly Language in Linux
    http://asm.sourceforge.net/articles/linasm.html
  81. vasm
    http://sun.hasenbraten.de/vasm/
  82. vasm – dokumentace
    http://sun.hasenbraten.de/vasm/release/vasm.html
  83. The Yasm Modular Assembler Project
    http://yasm.tortall.net/
  84. 680×0:AsmOne
    http://www.amigacoding.com/index.php/680×0:AsmOne
  85. ASM-One Macro Assembler
    http://en.wikipedia.org/wiki/ASM-One_Macro_Assembler
  86. ASM-One pages
    http://www.theflamearrows.info/documents/asmone.html
  87. Základní informace o ASM-One
    http://www.theflamearrows.info/documents/asminfo.html
  88. Linux Syscall Reference
    http://syscalls.kernelgrok.com/
  89. Programming from the Ground Up Book – Summary
    http://savannah.nongnu.org/projects/pgubook/
  90. IBM System 360/370 Compiler and Historical Documentation
    http://www.edelweb.fr/Simula/
  91. IBM 700/7000 series
    http://en.wikipedia.org/wiki/IBM_700/7000_series
  92. IBM System/360
    http://en.wikipedia.org/wiki/IBM_System/360
  93. IBM System/370
    http://en.wikipedia.org/wiki/IBM_System/370
  94. Mainframe family tree and chronology
    http://www-03.ibm.com/ibm/history/exhibits/mainframe/mainframe_FT1.html
  95. 704 Data Processing System
    http://www-03.ibm.com/ibm/history/exhibits/mainframe/mainframe_PP704.html
  96. 705 Data Processing System
    http://www-03.ibm.com/ibm/history/exhibits/mainframe/mainframe_PP705.html
  97. The IBM 704
    http://www.columbia.edu/acis/history/704.html
  98. IBM Mainframe album
    http://www-03.ibm.com/ibm/history/exhibits/mainframe/mainframe_album.html
  99. Osmibitové muzeum
    http://osmi.tarbik.com/
  100. Tesla PMI-80
    http://osmi.tarbik.com/cssr/pmi80.html
  101. PMI-80
    http://en.wikipedia.org/wiki/PMI-80
  102. PMI-80
    http://www.old-computers.com/museum/computer.asp?st=1&c=1016
  103. The 6502 overflow flag explained mathematically
    http://www.righto.com/2012/12/the-6502-overflow-flag-explained.html
  104. X86 Opcode and Instruction Reference
    http://ref.x86asm.net/coder32.html