Как записать X86_64 _assembler _?

Цель: Я хочу записать ассемблер X86_64.Примечание: отмеченный как общественная Wiki

Фон: я знаком с C. Я записал блок MIPS прежде. Я записал некоторый x86 блок. Однако я хочу записать x86_64 ассемблер - он должен произвести машинный код, что я могу перейти к и начать выполняться (как в JIT).

Вопрос: что лучший способ состоит в том, чтобы приблизиться к этому? Я понимаю, что эта проблема выглядит доброй большой для занятия. Я хочу начать с основным минимальным набором:

  • Загрузка в регистр
  • Операция в секунду Arithmetric на регистрах (просто целые числа прекрасен, никакая потребность смешать с FPU все же),
  • Условные выражения
  • Переходы

Просто основной набор для создания этого полным по Тьюрингу. Кто-либо сделанный это? Предложения / ресурсы?

5
задан unwind 19 June 2010 в 13:25
поделиться

2 ответа

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

Язык ассемблера обычно проще, чем обычные компилируемые языки, поскольку вам не нужно беспокоиться о конструкциях, пересекающих границы строк, а формат обычно фиксирован.

Я написал ассемблер для (вымышленного) процессора около двух лет назад в образовательных целях, и он в основном рассматривал каждую строку как:

  • необязательную метку (например, : loop ).
  • операция (например, mov ).
  • операнды (например, ax, $ 1 ).

Самый простой способ сделать это - убедиться, что токены легко различимы.

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

  • удаление комментариев (сначала ; вне строки до конца строки).
  • извлеките этикетку, если она есть.
  • первое слово - это операция.
  • остальные - операнды.

Вы можете легко настоять на том, чтобы у разных операндов были специальные маркеры, чтобы облегчить вашу жизнь. Все это предполагает, что у вас есть контроль над входным форматом. Если вам требуется использовать формат Intel или AT&T, это немного сложнее.

Я подошел к этому так: была вызвана простая функция для каждой операции (например, doJmp , doCall , doRet ) и что функция решила, что было разрешено в операндах.

Например, doCall допускает только числовые значения или метки, doRet ничего не допускает.

Например, вот сегмент кода из функции encInstr :

private static MultiRet encInstr(
    boolean ignoreVars,
    String opcode,
    String operands)
{
    if (opcode.length() == 0) return hlprNone(ignoreVars);
    if (opcode.equals("defb"))  return hlprByte(ignoreVars,operands);
    if (opcode.equals("defbr")) return hlprByteR(ignoreVars,operands);
    if (opcode.equals("defs"))  return hlprString(ignoreVars,operands);
    if (opcode.equals("defw"))  return hlprWord(ignoreVars,operands);
    if (opcode.equals("defwr")) return hlprWordR(ignoreVars,operands);
    if (opcode.equals("equ"))   return hlprNone(ignoreVars);
    if (opcode.equals("org"))   return hlprNone(ignoreVars);

    if (opcode.equals("adc"))   return hlprTwoReg(ignoreVars,0x0a,operands);
    if (opcode.equals("add"))   return hlprTwoReg(ignoreVars,0x09,operands);
    if (opcode.equals("and"))   return hlprTwoReg(ignoreVars,0x0d,operands);

Функции hlpr ... просто взяли операнды и вернули массив байтов, содержащий инструкции. Они полезны, когда многие операции имеют одинаковые требования к операндам, например, adc , add и и все требуют двух регистровых операндов в приведенном выше случае (второй параметр контролировал, какой код операции был возвращен. для инструкции).

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

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

Чтобы правильно создать код в ЦП, который допускает инструкции переменной длины, лучше всего сделать это за два прохода.

На первом проходе не генерируйте код, просто генерируйте длину инструкций. Это позволяет вам присваивать значения всем меткам по мере их появления. Второй проход сгенерирует код и может заполнить ссылки на эти метки, поскольку их значения известны. Для этой цели использовались ignoreVars в указанном выше сегменте кода (были возвращены байтовые последовательности кода, поэтому мы могли знать длину, но любые ссылки на только что используемые символы 0).

8
ответ дан 18 December 2019 в 13:11
поделиться

Чтобы не обескураживать, но уже существует много ассемблеров с различными наворотами. Пожалуйста, рассмотрите возможность внесения своего вклада в существующий проект с открытым исходным кодом, такой как elftoolchain .

6
ответ дан 18 December 2019 в 13:11
поделиться
Другие вопросы по тегам:

Похожие вопросы: