2010-07-07 3 views
8

Я программист, встроенный программист DSP, который хочет улучшить навыки программирования на ассемблере. За 7 лет моей карьеры я программировал в C, Matlab, немного кодируя язык ассемблера. (Сборка ARM, процессор процессора DSP).Получение навыков программирования на языке ассемблера

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

  • Народного опыт кодирования в языке ассемблера (любой), которые они получили в течение многих лет кодирования в сборе язык.

  • Руководства иметь в виде при изучении нового языка Ассамблеи

  • конкретных советов и приемов, чтобы эффективно и правильно код на языке ассемблера

  • Как эффективно преобразовать данный код C в оптимальный код сборки

  • Как четко понимать данный код сборки

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

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

спасибо.

-AD

+3

Это может помочь, если вы объясните * почему * вы хотите это сделать? Какое преимущество (ы) вы воспринимаете в программировании сборки по сравнению с использованием HLL? И действительно ли эти воспринимаемые преимущества перевешивают значительно более высокую стоимость разработки и обслуживания программ сборки? –

+3

@Paul R: На работе я собираюсь работать над программированием процессора, который является SIMD и VLIW, а компилятор, выполненный для этой архитектуры, не делает хорошую работу. Его почти 4x-6x раз неэффективное генерирование кода для этой архитектуры, чем сборка с ручной кодировкой. Вот почему. – goldenmean

+1

в этом случае, вместо того, чтобы вкладывать много усилий в письменной форме ассемблера, вы должны получить гораздо более высокий ROI, если приложите столько же усилий к улучшению компилятора. –

ответ

6

Хорошее место для начала было бы книга Джеффа Duntemann, в Assembly Language Step-by-Step. Книга посвящена программированию x86 под Linux. Насколько я помню, предыдущая версия книги охватывала программирование под Windows. Это книга новичка, в которой она начинается с самого начала: биты, байты, двоичная арифметика и т. Д. Вы можете пропустить эту часть, если хотите, но, возможно, неплохо было бы по крайней мере обезвредить ее.

Я думаю, что лучший способ узнать ASM-кодирование - это 1) изучение основ аппаратного обеспечения, а затем 2) изучение кода других. Книга, о которой я говорил выше, стоит того. Вы также можете быть заинтересованы в The Art of Assembly Language Programming.

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

Это говорит о том, что я не буду препятствовать вам в ваших поисках, чтобы стать более эффективными с ASM. Познакомившись с тем, как процессор работает на этом уровне, можно только улучшить свои навыки программирования HLL.

18

Мой ответ в целом ... напишите дизассемблер. Вы коснулись ARM, возможно, вы знаете все инструкции ARM, возможно, нет, а как насчет большого пальца? ARM - это хороший способ научиться этому методу, как популярной, так и фиксированной длине инструкции, поэтому вы можете разбирать линейно от начала до конца.

Я не имею в виду написать полированный источник, достойный дизассемблер, возможно, написать 5 или 10 строк ассемблера за раз, макс, может быть, одну и ту же инструкцию с разными регистрами, достаточно, чтобы разобрать двоичный код с бит if-then-else дерева или переключателей.

 
add r0,r0,#1 
add r0,r1,#1 
add r0,r2,#2 

Ваша цель состоит в том, чтобы исследовать каждый бит опкодом, понять, почему вы можете иметь только 8 бит immediates, понять, почему некоторые процессоры только позволяют прыгать 127 или 128 байт для локального условного перехода. Вам не нужно писать дизассемблер, чтобы сделать это, но для меня это работает, чтобы внедрить эту информацию в мой мозг.

Чтобы создать все возможные коды операций/инструкции для тестирования дизассемблера, вы изучите все синтаксические нюансы для используемого ассемблера. Язык ассемблера в книге чип-компаний не обязательно является точным синтаксисом, используемым каждым ассемблером для этого семейства процессоров. Хорошим примером этого являются команды mrc/mcr (ARM). газ, в частности, известен ужасной работой, которая меняет синтаксис, делая его более болезненным, чем синтаксис чипов и инструменты. Это зависит от того, что вы пытаетесь сделать, если вы просто хотите закодировать несколько строк или что-то изменить, вам не нужно знать каждый элемент угла или ассемблер, но если вы действительно хотите изучить набор инструкций, я рекомендую этот подход ,

Я также встроенный инженер-программист, в основном используя C, но ежедневно разбирая, что C (используя objdump, а не мои инструменты), изучая вывод, гарантируя, что этот код находится в этой области памяти и этот код здесь, компоновщик. Но мне иногда приходится изучать симуляцию процессора/чипа, и вам нужно следить за выборками команд и связанными с ними вводами-выводами, чтобы следить за кодом через симуляцию. Или отлаживать плату с логическим анализатором на плунжере или какой-либо другой шине. Я узнал много разных процессоров: 8, 16, 32, 64 бит (и те, у которых длина регистра не входит в этот список) cisc, risc, dsp и несколько микрокодов. Написал дизассемблер для каждого из них (ну, кроме pdp11 и x86, мои первые два набора инструкций), возможно, может быть, после полудня, чтобы узнать новый ISA, как только вы увидите некоторые из них. Нет, мне требуется день или два, чтобы переключиться с одного, которое я использовал ежедневно в течение нескольких дней/недель/месяцев на один, который я не использовал в месяцах/годах. Я не думаю, что на всех языках сразу.

Разборка инструкций переменной длины (большинство процессоров там), действительно делает это правильно, является самой формой искусства и ПУТЕМ выше того, о чем я говорю, поэтому я рекомендую только несколько инструкций за раз , не вставляйте данные в эти инструкции. Идеально использовать этот метод, если у вас есть рабочий/хороший дизассемблер, поэтому вы можете сравнить свой результат с реальным, в основном, проверенным и отлаженным дизассемблером.

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

Независимо от того, какая учебная среда лучше всего подходит для вас, будь то разборки, эмуляторы, одиночный шаг через симулятор ISA на основе gui, книги, веб-страницы. Изучение ассемблера для одного или нескольких процессоров, безусловно, сделает ваше программирование на высоком уровне лучше. Даже если вы на самом деле никогда не пишете ассемблер, а только проверяете его. Напишите некоторый C-код, который использует массивы, указатели и структуры и без структур, циклов, развернутых циклов, скомпилирует каждый из них с различными параметрами компилятора, с включенным и без отладочного материала без оптимизации, до максимальной/агрессивной оптимизации. (скомпилируйте для разных процессоров и сравните различия в потоке программы, количестве инструкций и т. д. llvm отлично подходит для этого).

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

Я рекомендую проверить разные семьи, те, у кого нет/нет инбридинга, я упоминал ARM/thumb (и thumb2), которые определенно инбредны, но популярны и будут оплачивать счета, чтобы вы могли узнать других в свое свободное время , Вернитесь к 6802 или 68hc11, 8088 и/или z80. Старый pic pic12 или pic16 (pic32 - всего лишь mips). mips, power pc, avr. Я большой поклонник набора инструкций msp430, очень хороший, чтобы учиться, имел чувство pdp11, компилятор дружелюбный, печально ориентированный на нишу рынка. 8051, все еще не мертвый, удивительно. У старших, большинство из них, есть тренажеры с набором инструкций в различных формах (например, у мама есть много), поэтому вы можете взять эти симуляторы, а также память и регистры печати по мере того, как ваша программа выполняет наблюдение, обучение и улучшение. Затем сравните старые, более современные. Посмотрите, почему некоторые ISA с одинаковой тактовой частотой превосходят других по прыжкам и ограничениям, у некоторых есть один накопитель, один регистр, может быть, два или четыре, и делать что-нибудь полезное, которое вам нужно постоянно загружать и хранить, принимая несколько инструкций для одной реальной операции , Там, где что-то более современное делает эту реальную операцию в одной или двух или трех инструкциях/часах, просто имея больше регистров или общих регистров вместо специальных целевых регистров.

Продвинутая тема - это доступ к памяти. Thumb (не thumb2) не так эффективен, как ARM, есть заметные накладные расходы, на 5-10% больше инструкций, требуемых для одной и той же задачи, так почему же намного больший шаг на GameBoy Advance? Ответ: в основном 16-битные шины памяти с ненулевой памятью ожидания. GBA не имеет кэш-памяти, но имеет транзакцию предварительной выборки на интерфейсе rom, а синхронизация по времени - нелинейная, первое чтение - это N часов и чтение последовательных адресов, следующих за ними, - это M-часы (M меньше N) (что делает rom выполняться быстрее, чем ram). Не зная об этом, вы можете сделать разницу между успехом и неудачей для вашей встроенной программы для этой платформы и других. выходит за рамки понимания ассемблера, но вы не можете туда попасть, не имея возможности читать и понимать выходные данные компилятора.

Другая передовая тема - кэш. Если у вас есть доступ к чему-то с кешем и вы можете отключить его (скажите что-нибудь из игровой площадки gp32 или wiz, более старый ipod, на котором вы можете делать домородок) и т. Д. В идеале вы можете управлять кэшем инструкций и данных отдельно , Вы ощущаете совершенно другую оптимизацию, это больше не о наименьших инструкциях с наименьшим количеством прыжков/ветвей и наименьшим доступом к памяти. Теперь вам нужно иметь дело с длиной строки кэша, где инструкции располагаются внутри этой строки кэша. Добавление одного, двух, трех, а иногда и более nops в начале программы (на самом деле, буквально не добавление nop в start.S) может значительно улучшить или разрушить производительность программы, сгенерированной тем же (более высоким уровнем) источником, компилятором , и настройки оптимизации. Должен изучить инструкции и понять оборудование, чтобы понять, почему.

Ваши вопросы конкретно:

-Люди Опыт в кодировании в языке ассемблера (любой), которые они приобрели за годы кодирования на языке ассемблера.

см.выш

Руководящих указания, чтобы иметь в виде при изучении нового языка ассемблера

см.вышем. Полагайте, что процессоры более похожи друг на друга, они загружают и хранят регистры, ветви безоговорочно и условно. Такая же горстка условных ветвей хорошо известна и используется. Сначала найдите общие инструкции, немедленно загрузите, перейдите из одного регистра в другой, добавьте в регистр, и, или, xor.Не все процессоры имеют инструкцию деления, большинство из них не имеют, некоторые не имеют размножения, больше, чем вы думаете. И большинство из них вы не можете использовать в общем случае, если операнды и результат размножения имеют одинаковый регистр размера, тогда многие комбинации операндов будут переполнять результат.

Определённые советы и приемы, чтобы эффективно и правильно код на языке ассемблера

Drive вниз по середине дороги, не получают в прохладные трюки, специфичные для этого ассемблера/компилятора, или гы свист особенностей языка. Держите его простым, некоторые из моих 20-летних C-кода все еще компилируются сегодня во многих компиляторах. Я часто нахожу код в течение нескольких лет или менее старых в мире, который сегодня не компилируется, должен постоянно поддерживаться для выполнения той же функции с новыми компиляторами, просто из-за компилятора или языковых трюков.

-Как эффективно преобразовать данный код C в оптимального кода сборки

Пуск с C или другой, и компилировать и разбирать, может быть, несколько уровней оптимизации, может быть, несколько различных компиляторов. Тогда просто исправьте проблемы. Это забавная задача, но на самом деле вы попадаете в эту гигантскую ловушку. Зачастую сохранение 1 или 2 или 7 инструкций из 5 или 10 или 20 не стоит переносить ассемблер с помощью C и помещать вас в не переносимую ситуацию или в ситуации, когда компилятор может догнать следующую версию или две, и даже превышать ваши способности, потому что они знают больше инструкций и как их использовать, чем вы.

Где я использую ассемблер, большинство (кроме загрузки естественно) на самом деле предназначено для чтения и записи регистров или мест памяти. Каждый компилятор, который я использовал, в какой-то момент времени не смог получить правильную инструкцию, заменил 32-битный магазин на 8 бит, что-то вроде этого. Я на самом деле трачу инструкции и часы для выполнения подпрограмм и подстановок в ассемблере, чтобы гарантировать, что компилятор не похоронит меня. Копии памяти и тому подобное, как правило, очень хорошие (в библиотеках C), но это места, где вы можете воспользоваться набором инструкций. Используя конкретные инструкции, которые не являются частью языка, который вы используете, битовые тесты или бит устанавливаются (что компилятор не распознает/не оптимизирует). Byte swapping, если у вас есть команда байта или halfword swap. Определяет поворот или сдвиг или расширение знака.

Если вы можете найти его, то это бесплатно, как часть черной книги, Майкла Абраша, Дзэн языка Ассамблеи. Измерьте время выполнения и испытания, испытания, испытания. Независимо от того, насколько хорошо вы думаете, что вы секундомер, покажет настоящего победителя. Аппаратное обеспечение устранило половину его учения, но процесс мышления и глубину изучения кода на этом уровне детализации (у меня есть оригинальная книга в печати BTW), более поздние статьи в журналах попали в суперсканерные процессоры и просто перестроили некоторые инструкции, чтобы они могли быть распознаны и переданы отдельным исполнительным единицам, выполняющим одни и те же инструкции, выполняемые во много раз быстрее, было интересно читать и понимать. Здесь снова большая часть этого была похоронена в шуме трубопроводами, больше исполнительных блоков, параллельной обработки, более быстрыми часами. На самом деле все это результат ужасных языков программирования, которые настолько неэффективны, что аппаратные средства должны компенсировать. Но это еще более увлекательно для нас, когда мы можем выполнять ту же операцию в тысячах и десятках тысяч раз быстрее, чем наши сверстники.

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

-Как четко понимать данный код сборки

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

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

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

Еще один ответ, в зависимости от того, что вы действительно задавали здесь, - это знать соглашение об использовании компиляторов, являются операндами для функции, хранящейся в r0, r1, r2 ... и если да, то сколько из них находится в регистрах, прежде чем они перейдут на стек. Этот компилятор помещает все в стек? Флаги хранятся в стеке? Где хранится адрес возврата? Эти CAN могут отличаться от разных компиляторов для той же цели, что и в x86 в старые времена (Zortech/Watcom vs Microsoft/Borland), или для того же процессора для того же самого компилятора, что и в наше время (ABI и EABI). Современное время вы можете обнаружить, что интерфейс разработан и определен кем-то (сама чип-компания?), А различные компиляторы будут соответствовать этому стандарту по разным причинам, переносимости, маркетингу, лени и т. Д. Я считаю, что разбирать разборку и ездить по середине на дороге вы можете найти соглашения о вызовах, не имея необходимости идти и читать спецификацию.

Я изучил язык ассемблера на ранней стадии и часто до раздражения своих сверстников. Я склонен повторно использовать общие переменные в своем C, как если бы я писал ассемблер. Поэтому отслеживать, какие данные в какой переменной в какой момент времени в программе по привычке естественны для меня. YMMV. Анализируя какой-то сборщик или сборщик elses, я буду взломать этот вывод в текстовом редакторе, который я использую, чтобы его прочитать. Помещая визуальные пространства, пустые строки между функциональными блоками, делая комментарии после каждой инструкции относительно того, что сейчас находится в регистре, r0 содержит номер индекса в таблице, r1 теперь содержит смещение слова этого элемента в таблице, r0 теперь содержит физический адрес этого элемента в таблице, r2 теперь держит сам элемент из таблицы и т. д.

Удачи, получайте удовольствие, извините за очень длинный ответ.

0

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

1

Это довольно широкий вопрос, но у меня могут быть некоторые лакомые кусочки для вас. Я кодировал (по внешнему виду) BAL (сборка IBM 360), 8080A/8085, 8086/8088/80186, прикосновение 68000 (но не очень, действительно) и 80960 Assembly Languages, а также немного Sparc (хотя это было для класса в колледже, поэтому я не помню особенностей). Моя сильная сторона всегда была встроенной системой, хотя в мои более поздние годы я фактически занимаюсь веб-сайтами и борюсь со странностями JavaScript. Мне понравились мои годы обучения в Ассамблее, но сейчас у нас нет рабочих мест ...

У меня есть несколько советов для вас. Во-первых, вы должны изучить регистры чипов; для чего каждый используется, является ли это специальной целью общего назначения, математикой с плавающей запятой и т. д. Во-вторых, флаги; который проверяет триггеры, флаг (ы) и в этот момент находят инструкции, которые устанавливают И очищают эти флаги. Они обычно легки, как CLC («очистить перенос» - 8086/88/186). Узнайте, является ли чип большим или маленьким, то есть порядок бит слева направо - высокий или низкий или наоборот.

Команды бит-маневрирования также важны, например. ИЛИ, XOR, перемещение по флагом переноса и т. Д.

И затем есть запись в память и из нее; как язык ассемблера вашего чипа выполняет это? Можете ли вы написать прямо в память?Очень зависит от вашей аппаратной настройки. Команды для записи мгновенных значений в регистры? Потому что в основном вы делаете движение данных: между регистрами и памятью. Является ли адрес памяти плоской (надеюсь) или сегментированной (aiiiiigh!).

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

Чтобы начать, напишите короткие тестовые версии, прежде чем вы начнете писать большие. Выясните, как вы будете определять, будут ли достигнуты результаты (не все светодиоды загораются, хотя они облегчают жизнь). Я использовал анализатор; встроенные системы не всегда визуальны. Сначала сделайте небольшие шаги.

Если у вас есть компилятор, взгляните на код сборки, сгенерированный для вашего конкретного чипа. Попробуйте небольшую функцию C, чтобы добавить 2 числа, затем перейдите и посмотрите на сгенерированный код. Это вы узнаете много. Не позволяйте директивам ассемблера подавлять вас

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

В любом случае, удачи. Я узнал, потому что нам пришлось, и мне это очень понравилось. Я очень хорошо подходил к оптимизации (мне нравился Zen of Assembly Language от Michael Abrash), но компиляторы для чипов Intel получили очень высокую оптимизацию, поэтому программистам на языке ассемблера вообще не нужно. Наслаждайтесь!