Что лучший способ состоит в том, чтобы пойти о записи простого x86 ассемблера?

Расширение Chrome Google Analytics очень полезно при тестировании кода Google Analytics. Расширение выводит данные, отправленные в Google Analytics, в окно консоли JavaScript. Дни, когда вы ... ждали ... надеялись / молились, чтобы увидеть ваши тестовые просмотры страниц в Google Analytics, прошли.

Ниже приведен пример некоторых выходных данных, которые расширение печатает в окне консоли JavaScript:

Track Pageview
Tracking beacon sent!

Account ID               : UA-2345678-90
Page Title               : About
Host Name                : www.yourdomain.org
Page                     : /about
Referring URL            : -
Language                 : en-us
Encoding                 : UTF-8
Flash Version            : 11.1 r102
Java Enabled             : true
Screen Resolution        : 1680x1050
Color Depth              : 16-bit
Ga.js Version            : 5.2.4d
Cachebuster              : 476867651

16
задан starblue 1 November 2009 в 12:18
поделиться

9 ответов

Вы можете найти книгу драконов как полезную.

Фактическое название - Компиляторы: принципы, методы и инструменты ( amazon.com ).

Ознакомьтесь с Руководством разработчика программного обеспечения Intel Architectures для полной документации по наборам инструкций IA-32 и IA-64.

Технические документы по архитектуре AMD также доступны на ее веб-сайте.

Линкеры и загрузчики ( amazon.com ) - хорошее введение в форматы объектов и вопросы связывания. (Неотредактированная оригинальная рукопись также доступна в Интернете.)

6
ответ дан 30 November 2019 в 21:54
поделиться

Чтобы ответить на один из ваших вопросов, однократный проход нецелесообразен, если вы не выдадите код после прохода.

Представьте себе:

  JMP some_label
  .. code here
some_label:

что вы испускаете как значение расстояния для инструкции JMP? Какую инструкцию JMP вы испускаете, ту, которая требует близкого значения, или метка находится далеко?

Таким образом, двухпроходной должна быть минимум.

2
ответ дан 30 November 2019 в 21:54
поделиться

Учитывая, что это хобби-проект, многие ваши вопросы действительно сводятся к тому, «какие аспекты проблемы вам больше всего интересно изучать и изучать?» Если вам интересно посмотреть, как инструменты синтаксического анализа соотносятся с проблемой ассемблеров (особенно в том, что касается обработки макросов и т.п.), вам следует их использовать. С другой стороны, если вас не слишком интересуют эти вопросы и вы просто хотите вникнуть в вопросы упаковки и компоновки инструкций и довольны минимальным ассемблером без макросов, то быстрый и грязный синтаксический анализ, вероятно, будет путь к успеху.

Для однопроходного и многопроходного - вам интересно поиграться с созданием очень быстрого ассемблера с минимальным объемом памяти? Если так, этот вопрос становится актуальным. Если не, просто поместите всю программу в память, обработайте ее там, создав образ объекта в памяти, а затем запишите его. Не нужно беспокоиться о пропусках как таковых. В этой модели вам будет легче поэкспериментировать с выполнением действий в разном порядке, чтобы увидеть, каковы компромиссы, что в значительной степени является сутью хобби-проекта.

1
ответ дан 30 November 2019 в 21:54
поделиться

Я написал пару парсеров. Я написал пару парсеров, сделанных вручную, а также попробовал парсеры типа yacc ....

Ручные парсеры обеспечивают большую гибкость. Yacc предоставляет фреймворк, к которому нужно адаптироваться или потерпеть неудачу. Парсер Yacc по умолчанию предоставляет быстрый парсер, но для перехода после сдвига / уменьшения и уменьшения / уменьшения может потребоваться довольно много усилий, если вы не знакомы с одним из этих средств, а среда вашего парсера не Лучший. О преимуществах Yacc. Это дает вам систему, если она вам нужна. Сделанный вручную парсер дает вам свободу, но можете ли вы его использовать? Язык ассемблера кажется достаточно простым, чтобы его можно было обрабатывать с помощью yacc или аналогичных парсеров.

Мой ручной парсер будет содержать токенизатор / лексер, и я бы просмотрел массив токенов с помощью цикла for и выполнил некоторую обработку событий, поместив ifs или оператор case в цикле и проверка текущего токена или следующего / предыдущего. Возможно, я бы использовал отдельный парсер для выражений ... Я бы поместил код перевода в массив строк и "записал" невычисленные части переведенного кода, чтобы программа могла прийти к ним позже и заполнить пробелы. Могут быть пробелы, и не все известно заранее, когда кто-то анализирует код. Например, расположение переходов.

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

Существуют и другие парсеры, помимо Yacc, и они обещают большую гибкость и меньше «ошибок», но это не означает, что вы не получаете ошибок, они не будут так заметны и могут не будь таким быстрым. Если это важно.

Между прочим, если бы токены были сохранены, можно было бы даже подумать о смешанном yacc и ручном синтаксическом анализаторе.

0
ответ дан 30 November 2019 в 21:54
поделиться

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

Он будет компилироваться в байтовый код, который будет распространяться, а затем в машинный код при установке или при изменении среды процессора. Таким образом, при загрузке исполняемой части будет часть загрузчика, которая будет проверять процессор и несколько байтов управляющих данных в объекте, и если они совпадают, то исполняемая часть объекта может быть загружена сразу, но если нет , то необходимо перекомпилировать байт-код этого объекта и обновить исполняемую часть. (Так что это не компиляция Just In Time - это компиляция при установке программы или при изменении процессора.) Часть загрузчика будет очень короткой и приятной, она будет в коде 386, поэтому ее не нужно компилировать. Он будет загружать компилятор байт-кода только в том случае, если это необходимо, и если да, он загрузил бы объект компилятора, который был маленьким и плотным и оптимизирован для обнаруженной архитектуры. В идеале загрузчик и компилятор оставались бы резидентными после загрузки, и был бы только один экземпляр обоих.

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

Что вы делаете, это когда вы сталкиваетесь с символом, проверяете свою хеш-таблицу символов, и, если там нет записи, создаете ее и сохраняете маркер «прямой ссылки» в вашем скомпилированном коде с указателем на запись в таблице. . По мере того, как вы сталкиваетесь с определениями меток и символов, обновляйте (или помещайте новые данные в) вашу таблицу символов.

Отдельные скомпилированные объекты никогда не должны быть настолько большими, чтобы занимать очень много памяти, поэтому определенно весь скомпилированный код должен храниться в памяти до тех пор, пока все не будет готово для записи. Чтобы уменьшить объем памяти, нужно просто иметь дело только с одним объектом за раз и никогда не хранить в памяти более одного небольшого буфера, полного исходного кода, за раз. Может быть, 64к или 128к или что-то в этом роде. (Что-то достаточно большое, чтобы накладные расходы, связанные с вызовом загрузки буфера с диска, были небольшими по сравнению со временем, необходимым для чтения данных с диска, так что потоковая передача оптимизируется.)

Итак, один проход через исходный поток для объекта, затем вы соединяете свои части вместе, собирая необходимую информацию о прямой ссылке из хэш-таблицы по ходу дела, и если данных нет - это ' sa ошибка компиляции. Я хотел бы попробовать именно этот процесс.

1
ответ дан 30 November 2019 в 21:54
поделиться

Вам нужно будет написать лексер и синтаксический анализатор для чтения исходного кода и вывода абстрактного синтаксического дерева (AST). Затем можно пройти через AST для генерации выходного байтового кода.

Я рекомендую изучить книги по написанию компилятора. Обычно это курс уровня колледжа, поэтому книг должно быть много. Извините, я не могу порекомендовать один конкретно.

Вы также можете прочитать об инструменте ANTLR . Он может принимать грамматические правила и выводить код на разных языках, чтобы лексер / парсер работал за вас.

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

1
ответ дан 30 November 2019 в 21:54
поделиться

Хотя многие люди предлагают специальные парсеры, я думаю, что в наши дни следует использовать генератор парсеров, потому что он действительно упрощает задачу построения всего сложного синтаксиса, необходимого для интересного современного ассемблера. См. Мой пример BNF / ответ на StackOverflow: Z80 ASM BNF .

«Один проход» или «Два прохода» относится к тому, читаете ли вы исходный код дважды. Вы всегда можете сделать однопроходный ассемблер. Вот два способа:

1) Генерировать двоичные результаты на лету (представьте их в абстрактной форме парами, имеющими тенденцию к монотонно увеличивающимся адресам) и выпускать обратные исправления в качестве исправлений, когда вы находите информацию, которая позволяет вам разрешать прямые ссылки ( считайте их просто парами, в которых адреса используются для перезаписи ранее выданных местоположений). Для JMP, зафиксируйте тип / размер кода операции JMP, когда вы его встретите. По умолчанию может быть коротким или длинным в зависимости от вкуса или даже варианта ассемблера. Небольшой фрагмент синтаксиса, введенный кодировщиком со словами «используйте другой тип» или «я настаиваю на этом», достаточно (например, « JMP long target») для обработки тех случаев, когда выбор ассемблера по умолчанию неправильно. (Это ассемблер, его нормально иметь забавные правила.)

2) На (первом) проходе сгенерируйте данные для буферов в памяти. JMP по умолчанию (и другие зависящие от диапазона инструкции) на короткие смещения. Запишите расположение всех JMP (инструкции, зависящие от диапазона и т. Д.). В конце этого прохода вернитесь к JMP и исправьте те, которые «слишком короткие», чтобы быть длиннее; перемешайте код и настройте другие JMP. Умная схема для этого и достижения почти оптимальных наборов коротких JMP представлена ​​в этой статье 1978 года: Сборка кода для машин с инструкциями, зависящими от диапазона / Шимански

4
ответ дан 30 November 2019 в 21:54
поделиться

Возьмите таблицы NASM и попробуйте реализовать более простые инструкции, используя таблицы для декодирования

1
ответ дан 30 November 2019 в 21:54
поделиться

There is an excellent free e-book (pdf) on how to build assemblers and loaders by David Salomon. You can find it at:

http://www.e-booksdirectory.com/details.php?ebook=1311

7
ответ дан 30 November 2019 в 21:54
поделиться
Другие вопросы по тегам:

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