unix-asm-mini-A1

AT&T синтаксис разрабатывался компанией AT&T в те далекие времена, когда никакого Intel'а вообще не существовало, процессоры менялись как перчатки и знание нескольких ассемблеров было вполне нормальным явлением. По сравнению с синтаксисом Intel, AT&T-синтаксис намного более избыточен, но это сделано умышленно с целью сокращения ошибок (хинт: на одном процессоре команда MOV может перемещать 32-бита, на другом 16, а на третьем вообще 64).

Отличия синтаксиса AT&T от Intel следующие:

  1. имена регистров предваряются префиксом: «%«:
    1. Intel:eax,ebx,dl;
    2. AT&T:%eax,%ebx,%dl;
  2. обратный порядок операндов: вначале источник, затем приёмник:
    1. Intel:moveax, ebx;
    2. AT&T:movl%ebx, %eax;
  3. размер операнда задается суффиксом, замыкающим инструкцию, всего есть три типа суффиксов: «b» — байт (8-бит), «w« – слово (16-бит) и «l« – двойное слово (32-бита):
    1. Intel:movah, al;
    2. AT&T:movb%al,%ah;
    3. Intel: movbx, ax;
    4. AT&T:movw%ax,%bx;
    5. Intel:moveax,ebx;
    6. AT&T:movl%ebx,%eax;
  4. числовые константы записываются в Си-соглашении:
    1. Intel:69h;
    2. AT&T:0x69;
  5. для получения смещения метки используется префикс «$», отсутствие которого приводит к чтению содержимого ячейки:
    1. Intel:moveax, offset label;
    2. AT&T:movl$label, %eax;
    3. Intel:moveax, [label];
    4. AT&T:movllabel, %eax;
  6. в тех случаях, когда метка является адресом перехода, префикс «$» опускается:
    1. Intel:jmplabel;
    2. AT&T:jmplabel;
    3. Intel:jmp–;
    4. AT&Tjmp0x69;
  7. для косвенного перехода по адресу используется префикс «*»:
    1. Intel:jmpdword ptr ds:[69h];
    2. AT&T:jmp*0x69;
    3. Intel:jmpdword ptr ds:[label];
    4. AT&T:jmp*label;
    5. Intel:jmpeax;
    6. AT&T:jmp*%eax;
    7. Intel:jmpdword ptr ds: [eax];
    8. AT&T:jmp*(%eax);
  8. использование префикса «$» перед константой используется для получения ее значения. знак (если он есть) ставится после префикса. константа без указателя трактуется как указатель:
    1. Intel:moveax, 69h;
    2. AT&Tmovl$0x69, %eax;
    3. Intel:moveax, -69h;
    4. AT&Tmovl$-0x69, %eax;
    5. Intel:moveax, [69h];
    6. AT&Tmovl0x69, %eax
  9. для реализации косвенной адресации базовый регистр заключается в круглые скобки, перед которыми может присутствовать индекс, записанный в виде числовой константы или метки _без_ префикса «$»:
    1. Intel:moveax, [ebx];
    2. AT&T:movl(%ebx), %eax;
    3. Intel:moveax, [ebx+69h];
    4. AT&T:movl0x69(%ebx), %eax;
    5. Intel:moveax, [ebx+label];
    6. AT&T:movllabel(%ebx), %eax;
  10. если регистров несколько, то они разделаются через запятую:
    1. Intel:moveax, [ebx+ecx];
    2. AT&T:movl(%ebx, %ecx), %eax;
  11. для задания коэффициента масштабирования (scale) перед первым регистром ставится ведущая запятая (при использовании базово индексной адресации запятая опускается), а сам коэффициент отделяется другой запятой, без префикса «$»:
    1. Intel:moveax, [ebx*8];
    2. AT&Tmovl(,%ebx, 8), %eax
    3. Intel:moveax, [ebx*8+label];
    4. AT&Tmovllabel(,%ebx, 8), %eax
    5. Intel:moveax, [ecx+ebx*8+label];
    6. AT&T:movllabel(%ecx, %ebx, 8);
    7. Intel:moveax, [ebx+ecx*8+label];
    8. AT&T:movllabel(%ebx, %ecx, 8);
  12. сегментная адресация с использованием сегментных регистров отличается от Intel'а использованием круглых скобок вместо квадратных:
    1. Intel:moveax, es:[ebx];
    2. AT&T:mov%es:(%bx), %eax;
  13. в командах переходов и вызовов функций непосредственные сегмент и смещение разделяется не двоеточием, а запятой:
    1. Intel:jmp far 10h:100000h (псевдоконструкция!)
    2. jmp$0x10, $0x100000;