Pe această pagină
Citind cartea Professional Assembly Language, am ajuns la capitolul 13 și mi-a plăcut atât de mult încât am decis să scriu un articol despre el. Cartea este foarte bună dacă ești interesat de assembly pentru Linux.
Formatul Extended ASM îți permite să scrii cod assembly care interacționează cu orice tip de date C, cum ar fi variabile locale, șiruri de caractere, numere, etichete goto și altele. Formatul produce cod mai curat, mai sigur și mai eficient decât formatul Basic ASM.
Există două situații în care Extended ASM nu poate fi folosit și se preferă Basic ASM:
-
Extended ASM trebuie să se afle în interiorul unei funcții, nu poate fi folosit global.
-
Funcțiile declarate cu atributul naked trebuie să folosească și ele Extended ASM. Funcțiile declarate cu atributul naked trebuie, de asemenea, să își configureze singure prologul și epilogul.
Șablonul pentru Extended ASM arată astfel:
- [code langage=”asm”]
- asm [volatile]
- (
- “assembly code\n\t”
- “more assembly code\n\t”
- OutputOperands
- InputOperands
- ChangedRegisters
)
[/code]
Este destul de clar ce reprezintă OutputOperands și InputOperands.
ChangedRegisters reprezintă registrele pe care le-ai folosit în codul tău; trebuie să le scrii ca să îi spui compilatorului să nu le atingă.
Dacă trebuie să faci salturi către etichete goto declarate în C, atunci trebuie să specifici cuvântul cheie goto și : GotoLabels.
- [code langage=”asm”]
- asm [volatile] goto
- (
- “assembly code\n\t”
- “more assembly code\n\t”
- OutputOperands
- InputOperands
- ChangedRegisters
- GotoLabels
)
[/code]
Compilatorul GCC poate optimiza ASM-ul tău și îl poate elimina complet. Ca să îi spui compilatorului să nu îl atingă, trebuie să folosești cuvântul cheie volatile. Mai multe informații se găsesc aici: Extended-Asm.html#Volatile
Acum că ai avut o introducere rapidă în subiect, să explorăm aceste concepte cu câteva exemple de cod. Am inclus câteva comentarii în cod ca să fie mai ușor de urmărit.
O operație matematică simplă ar fi scrisă astfel:
[code language=”c”]
#include stdio.h // parantezele lipsesc din cauza parserului WordPress, prost implementat
int main()
{
int a = 0;
int b = 0;
int sum;
- asm
- (
- “movl $10, %%ecx\n\t” // Mută 10 în ECX (variabila a)
- “movl $15, %%edx\n\t” // Mută 15 în EDX (variabila b)
- “add %%edx, %%ecx\n\t” // ECX = ECX + EDX
- “movl %%ecx, %%eax\n\t” // EAX = ECX ; EAX (variabila sum)
- “=a”(sum) // OutputOperand: modificatorul ‘=’ (vezi documentația) ;
- “d”(a), “c”(b) // InputOperands: ‘d’ (variabila a) ; ‘c’ (variabila b) Vezi MachineConstraints pentru x86
- “%eax”, “%edx”, “%ecx”
);
// Ca să înțelegi că constrângerea ‘a’ înseamnă EAX, iar ‘d’ înseamnă EDX, vezi MachineConstraints pentru familia x86.
printf(“The sum of a + b is %d\n”, sum);
return 0;
}
[/code]
Ca să înțelegi ce înseamnă “=a”, consultă documentația pentru Simple Constraints și pentru Machine Constraints (pentru familia x86).
- ‘=’ este un modificator de constrângere și înseamnă că operandul este scris de instrucțiune.
- ‘a’ este o constrângere de mașină care îi spune compilatorului „Pune variabila sum în registrul EAX”
Același exemplu de mai sus poate fi scris folosind sintaxa asmSymbolicName, ceea ce face codul mai ușor de citit și de întreținut.
[code language=”c”]
#include stdio.h
int main()
{
int a = 0;
int b = 0;
int sum;
- asm
- (
- “movl $10, %[OpA]\n\t”
- “movl $15, %[OpB]\n\t”
- “add %[OpA], %[OpB]\n\t”
- “movl %[OpB], %[Sum]\n\t”
- [Sum] “=r”(sum)
- [OpA] “r”(a), [OpB] “r”(b)
);
printf(“The sum of a + b is %d\n”, sum);
return 0;
}
[/code]
Să trecem la următorul program. O copiere simplă de șir de caractere ar arăta astfel:
[code language=”c”]
#include
#include
int main()
{
unsigned length = 13;
char * src = “ASM is great!”;
char * dest = (char *) malloc(length * sizeof(char));
- asm volatile
- (
- “cld\n\t” // Șterge flag-ul de direcție.
- “repz movsb\n\t” // Repetă MOVSB până când ECX ajunge la zero.
- // OutputOperand
- “D”(dest), “S”(src), “c”(length) // InputOperands:
);
printf(“Input: %s\n”, src);
printf(“Output: %s\n”, dest);
return 0;
}
[/code]
După câteva încercări, am reușit să scriu un exemplu mai complicat, în care vrei să setezi un caracter dintr-un șir la poziția X, verificând limitele. Codul final arată astfel:
https://gist.github.com/dnutiu/282c063824936f40b1156c9a57233d67
Sper că ți-a plăcut acest articol 🙂
Mulțumesc că ai citit, spor la hacking!
Resurse:
- https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html
- https://gcc.gnu.org/onlinedocs/gcc/Basic-Asm.html
- https://gcc.gnu.org/onlinedocs/gcc/Modifiers.html#Modifiers
- https://gcc.gnu.org/onlinedocs/gcc/Simple-Constraints.html#Simple-Constraints
- https://gcc.gnu.org/onlinedocs/gcc-6.2.0/gcc/Machine-Constraints.html#Machine-Constraints (See x86 family)