Что мне знать при переключении с MIPS на сборку x86?

В школе мы программировали на языке ассемблера MIPS в течение некоторого времени. Мне интересно вникать в сборку x86, и я слышал, что это несколько сложнее (даже мой учебник MIPS говорит об этом).

Какую основную информацию я должен знать как программист MIPS, прежде чем совершать погружение в мир x86?

Ответ 1

Самые большие вещи, о которых следует помнить:

  • Несколько регистров общего назначения, а те, которые у вас есть, не являются чистым GP - многие инструкции требуют, чтобы вы использовали определенные регистры для определенной цели.
  • Инструкции x86 представляют собой двухкоординатную форму, а не трехкоординатный код, который может сделать некоторые операции более сложными. То есть вместо добавления r0, r1, r2 (r0 = r1 + r2), вы добавляете eax, ebx (eax + = ebx).
  • Сегменты в защищенном режиме (все 32-разрядные коды вне DOS, эффективно) делают вашу схему адресации памяти чрезвычайно неочевидной, что может укусить вас в задницу, когда вы начинаете.
  • Вы будете искать флаги, установленные/очищенные инструкциями все время. Научитесь любить руководства Intel.
  • Изменить, я забыл одно: использование субрегистров (например, ах для доступа к высоким 8 бит младших 16 бит регистра eax) может затруднить отслеживание манипуляций в ваших регистрах. Будьте осторожны и комментируйте либерально, пока вы не опуститесь.

Кроме этого, x86 довольно прямолинейный. Когда вы научитесь злоупотреблять инструкциями типа "lea" и "test", вы научитесь любить его. Кроме того, protip: Intel пошлет вам копии руководств по набору инструкций бесплатно, даже не придется платить за доставку. Посмотрите вокруг своего сайта на письмо о выполнении и запросите книги по SKU.

Ответ 2

x86 имеет очень ограниченный набор доступных регистров по сравнению с большинством других архитектур. Это на самом деле не затрудняет изучение ассемблера, но иногда затрудняет реализацию кода на практике.

Кроме того, из-за истории сильной обратной совместимости x86 набор команд не является ужасно симметричным (определенно, до RISC), и может быть много исключений из правил и угловых случаев, на которые следует обратить внимание.

Ответ 3

x86 имеют более сложные инструкции, чем MIPS. Таким образом, существует, вероятно, одна команда для общих последовательностей в MIPS (в первую очередь, адреса памяти). Недостаток многочисленных регистров, безусловно, является недостатком, но в обеих архитектурах существуют соглашения, которые в значительной степени ограничивают количество того, что вы можете свободно использовать до 4-5. Еще более ярко выражено в x86. x86 имеют больше исключений для использования регистров, чем MIPS, которые вы должны иметь в виду, но ничего не стоит скулить о постоянно.

Говоря по опыту, любой язык имеет одинаковую трудность в обучении, включая условные обозначения. Возможно, x86 немного проще, учитывая обильные онлайн-ресурсы и его популярность.

Сложная часть о x86 генерирует двоичный код из-за его инструкций переменной длины и нескольких режимов адресации. Чаще всего вам никогда не придется это делать.

Я могу посоветовать вам изучить более сложную архитектуру команд, чем MIPS.

И это важно, не входите в религиозную войну между RISC vs. CISC...

Ответ 4

Я изучил x86 и x86_64, чтобы написать сам ассемблер. Если вы не собираетесь писать ассемблер самостоятельно, то некоторые из того, что я расскажу, в значительной степени бесполезны. Я даже не знаю о MIPS.

x86 косвенная адресация - сложная вещь. В одной инструкции вы можете сделать следующее:

mov reg, [reg+offset]
mov reg, [reg*scale+base register+offset] # in where scale can be 1, 2, 4 or 8.

Их кодировка команд сложна из-за этого, но она согласована для каждой инструкции, которая кодирует этот путь. Возможно, вам захочется прочитать это из sandpile.org. Если вы хотите узнать больше о кодировке, вы всегда можете узнать об этом от меня. Еще одна кодировка команды, связанная с досадной детализацией, является префиксом. Они сильно меняют смысл инструкции. Например, 0x66 (если я правильно помню) спереди, а некоторые команды становятся для 16-битных GPR вместо 32-битных.

32-битные GPR (по порядку): eax, ecx, edx, ebx, esp, ebp, esi, edi

64-битные GPR: rax, rcx, rdx, rbx, rsp, rbp, rsi, rdi, r8, r9, r10, r11, r12, r13, r14, r15

Обратите внимание на то, что существует несколько регистров общего назначения, это заставит большинство программного обеспечения использовать его более или менее в макете с помощью стека. Болезненная деталь. rsp используется для стека (pop, push -instructions), а rbp также сохраняется. x86_64 имеет больше регистров, но потребуется время, когда люди его усыновят, даже если у каждого из потребителей есть процессор, способный к этому.

Существует два разных набора инструкций для арифметики с плавающей запятой. XMM является более новым. В x86_64 доступно 16 128-битных регистров, а в x86 всего 8 из них. Более старый набор команд обрабатывает регистры как стек. У вас просто нет swap, nip или rot, поэтому работа с ним - изгиб ума.

В использовании x86 имеет тенденцию сводиться к машине RISC. Некоторые из этих сложных инструкций не дают преимуществ или еще медленнее на новых машинах. Вы будете разбираться в 30-150 инструкциях в зависимости от того, что вы читаете или пишете. Вы также можете полностью игнорировать некоторые старые инструкции и AL/HL-материалы. Имейте в виду это все беспорядочное происхождение за 1978 год, что совершенно неожиданно, это не хуже, 31 год от этого и 24 года с момента первого внедрения IA-32. В то время многие вещи меняют свою актуальность.

Прямые переходы и вызовы кажутся относительными относительно следующей команды в x86. Поэтому:

    jmp nowhere  # or call, jz, jg whatever...
nowhere:
    nop

Заканчивается кодировка на "JMP imm: 0, NOP". Регистро-косвенный jmp, который делает абсолютные прыжки. Также хорошо заметить, что не существует никаких косвенных условных скачков, связанных с регистром, и это беспокоило меня тоже.

Здесь не все возможно, вы должны знать, но первый материал, который приходит мне на ум из вашего вопроса. Но, возможно, вы можете ладить с ними на данный момент.