LINUX.ORG.RU

Изучение ассемблера: суть и с чего начать?

 ,


4

3

Доброго времени суток всем ЛОРовцам!

Начну немного с предистории. Живу под «гордым» названием веб-разработчик. Для клиентов маг и бездарь одновременно (хотя, второе чаще). Для понимающих просто очередной фронтендщик, который пишет велосипеды на ванильке. Помимо JS знаю, наверное, ниже среднего PHP, BASH и Lua. Когда-то учил Basic, Pascal, C и Python. И тут понятно, что не могу я назвать себя программистом - левел не тот. Вот по этой причине и для души хочу начать изучать ассемблер.

А теперь к сути. Почитал немного информации, понял, что есть команды процессора, используя которые мы создаем программу. Эти команды у разных процессоров/архитектур разные. Но как с этим всем работать пока не понял. Исходя из этого у меня есть ряд вопросов:

  1. Я так понимаю, что текст программы на ассемблере необходимо компилировать, да? Есть какой-нить предустановленный компилятор в GNU/Linux?
  2. Есть какие-то общие правила написания программ? Что-то вроде var arr; function(){};. Как-то же необходимо связывать меж собой команды процессора. Что это за WASM или TASM?
  3. Сборка программы на ассемблере возможна не на устройстве, для которого пишется программа? Если сравнивать с компиляцией ядра Linux.
  4. Я так понимаю, что для «переменных» необходимо жестко указывать ячейку памяти процессора и ОЗУ, да? Что на счет этого стоит учить? Необходимо для старта читать кучу материала о страницах памяти и т.д.?

Планирую начать с чего-то простого, например, Z80 или MC6800. Думаю, завтра у меня еще вопросы будут :) .

В общем, кто что посоветует, с чего начать, где эти основы брать? А то я как по среди моря не вижу куда плыть.

P.S. За ранее всем спасибо!

★★★★

Последнее исправление: Klymedy (всего исправлений: 2)

программистом

байтодроч

anonymous
()
  • Скачай интеловские мануалы (Intel® 64 and IA-32 Architectures Software Developer’s Manuals) одним файлом и в любой непонятной ситуации читай их.
  • Пиши под своё железо и свою ОС, не городи лишних виртуалок и слоёв абстракции.
  • Выбери инструменты, которые развиваются и поддерживаются (например, fasm).
  • Начни с чтения хэлловорда с документацией к ассемблеру и интеловскими мануалами наперевес.
  • Измени код хэлловорда до, например, калькулятора.
  • Выложи код и попроси опытных людей сделать ревью.
  • Читай чужой код.

Компилировать (ассемблировать) нужно, ассемблером. Masm, nasm, fasm, tasm и прочие — это ассемблеры. Отличаются, в основном, синтаксисом, т.к. язык ассемблера по сути только представляет кишки процессора в человекочитаемом виде. А раз архитектура одна, то и яйца те же, только в профиль.

Правила написания есть, довольно примитивные. Типа «одна строчка — одна команда». Научишься по примерам и документации.

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

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

Общий совет — бери и делай. Вместо вопросов «как делать» лучше спрашивать «почему не работает» или «как оно работает» с конкретным кодом.

d ★★★★
()

возьми книгу «Структуры данных и алгоритмы» Рацеев, там много хелоувордов. Почитай книгу Программирование на языке ассемблера Nasm для ОС UNIX. там очень хорошо все разжеванно. Но самое главное, как писали выше это просто писать код

SmilePlz
()
Ответ на: комментарий от d

Пиши под своё железо и свою ОС, не городи лишних виртуалок и слоёв абстракции

Все бы хорошо, но асм под чужой протмодой это самое унылое, что только можно придумать. Ничто не сравнится с прямой записью в видеобуфер и ловлей девятого инта для тср. Уже не говоря об ощущении той мощи, которую тебе дают univbe и dos4gw/pharlap. Колить write и brk можно и под сишкой, ничего особо интересного в этом нет.

fasm лорчую.

arturpub ★★
()
Последнее исправление: arturpub (всего исправлений: 1)

как с этим всем работать пока не понял

Кроме самой программы есть еще вопрос, как обьяснить загрузчику, куда какие части класть в рантайме (потому что перед запуском процесс конструируется из секций исполняемого файла). В досе самые примитивные — .com программы, это тупо образ рантайма <64Кб, кладется как есть (или +100h, забыл). Все остальные — exe/dll (mz,pe,le), +x (elf,aout) имеют структуру, с которой и приходится воевать. ld в этом плане кстати не очень адекватный.

Ты пишешь программу в секции code, размещаешь статические данные в data и bss, иногда указываешь размер стека, а ассемблер (tasm, masm, gas) это все собирает либо в объектные файлы, которые можно линковать линкером (tlink, link, ld), либо сразу в исполняемые (фасм на винде, например). Динамическая память выделяется как обычно malloc (или int21/48), к секциям и асму в целом отношения не имеет.

arturpub ★★
()
Ответ на: комментарий от targitaj

Конечно, с этого начинать надо, чтобы потом не плакать в бложиках pointers considered harmful. Если не осилил такую примитивную вещь, как асм, то в низкий уровень вход заказан.

arturpub ★★
()
Ответ на: комментарий от arturpub

А какой синтаксис в конкретном ассемблере — дело десятое, а секции и в африке секции

anonymous
()

Следовало бы начать с языка Си.

Deleted
()
Ответ на: комментарий от arturpub

Дурак что ли? Твои bss с data — это не elf по-твоему. К тому же elf везде почти

anonymous
()
Ответ на: комментарий от arturpub

Угу, «начинать». Только двое из трёх программеров нашего подрядчика имеют представление о работе машины на уровне двоичного когда. Они пишут на жабе. Из приходивших на собеседования на позицию программера молодых мальчиков - никто вообще. Я не могу этого понять. Как можно писать код, если ты не понимаешь что именно делает машина? Может быть я ошибаюсь и, наоборот, лучше не знать? Может быть знание низкого уровня отвлекает? Сам я не зарабатываю программированием.

Задавали соискателям задачку. Есть 4 млрд + 1 число, из которых 4 млрд - парные и 1 непарное. Надо найти это самое единственное непарное число. Решается на низком уровне просто элементарно, если знаешь как работает машина. Было интересно послушать какие конструкции лепили соискатели. Ппц, чего они лепили... Сортировки, хеши, таблицы. Мрак.

targitaj ★★★★★
()
Ответ на: комментарий от targitaj

Решается на низком уровне просто элементарно, если знаешь как работает машина.

Решение, пжалста

anonymous
()
Ответ на: комментарий от arturpub

В досе самые примитивные — .com программы, это тупо образ рантайма

Это да, при загрузке твой файлик помещается в один сегмент по адресу 100h, перед ним какой-то мусор, не помню уже, что, видимо параметры запуска и окружение. Все сегментные регистры ставятся на твой сегмент.

Динамическая память выделяется как обычно malloc (или int21/48), к секциям и асму в целом отношения не имеет.

Как сделать в асме под GNU/Linux это я не очень понял...

Xenius ★★★★★
()

Я вообще начинал с Программирование однокристальных микропроцессоров. В бумаге. (Аппаратную часть тех времен, можно не зацикливаться). Потом на TurboC-ях хелловорды писались, и компилировались с дебагинфо, потом дебажились TASM-овоским дебагером. Помаленьку хелловорды начали линковаться с модулями написанные на асме(реализовывались примитивные функции). Потом внезапно открыл для себя Flat Assembler, который упростил прототипирование.
В любом случае, нужно писать и писать и писать. Я бы посоветовал по такой схеме вкуривать:
1. Знакомимся с базовыми понятиями: регистры, память, стек и данные в нем, и что с ними можно делать(основные команды как для вхождения нужно знать я бы сказал не более 30%);
2. Знакомимся с потоком выполнения: последовательность исполнения команд, как работают (без)условные переходы, вызовы процедур, возврат из них, аналоги высокоровневых операторов управления(if,while);
3. Берем(ставим себе) задачку, и решаем её на бумаге. Как в школе учили/учат: блоксхема, разбиваем на процедуры, подбираем тестовые данные. Знаете другой язык - отлаживаете алгоритмы на нем абы потом не гадать: алгоритм не корректный или реализация кривая.
4. Реализуем процедуры, обязательно наступая не все грабли(ну очень советую тот же Flat).
5. Пункт 3 и 4 повторяем до опупения.
На самом деле, кодинг на ассемблере принципиально ничем не отличается от чего либо другого. Количество деталей, уровень абстракции. Вывих мозга начинается там где нужна глубокая оптимизация всего и вся. В 95% случаев таковая не нужна, хватает того что может предоставить оптимизатор С/С++.

Да кстати, у вас есть возможность войти в это ещё плавнее. Говорите есть опыт с Lua. Как ни странно, но понятие ассемблера тоже входит и мнемокод для виртуальных процессоров, виртуальных машин. Lua, Java, .NET, Python, PHP. За 3 первых точно скажу, что написав хелловорлд на высокоуровневом языке можно посмотреть комманды виртуальной машины соотвествующие этому коду. И даже тот же С/С++ можно просить родить ассемблер код. Не советую смотреть что-либо программок больше 3-5 процедур. А крутя ручки оптимизации...

FeyFre ★★★★
()

Я думаю, можешь доками Intel не заморачиваться.

Просто берёшь fasm, качаешь, там будет и сам ассемблер и примеры и дока по командам процессора.

В принципе особой разницей между nasm и fasm нету, но fasm позволяет глубже погрузиться в низкоуровневую фигню, а nasm (и GAS, gnu assembler) зато удобнее когда нужно включить ассемблерный код в большой проект.

Кроме того, fasm написан сам на себе, а nasm на C, что опять же делает nasm удобнее для real world-задач, когда ты можешь собирать код для x86 на высокопроизводительной машине с каким-нибудь ультраспарком или PowerPC, а fasm работает только на x86-компьютерах, хотя может ассемблировать для любой ОС с любой другой (например можно собирать виндовые exe под линуксом и наоборот).

Xenius ★★★★★
()
Последнее исправление: Xenius (всего исправлений: 1)
Ответ на: комментарий от Xenius

Это да, при загрузке твой файлик помещается в один сегмент по адресу 100h, перед ним какой-то мусор, не помню уже, что, видимо параметры запуска и окружение. Все сегментные регистры ставятся на твой сегмент.


PSP - Program segment prefix. Как же меня коробит сокращение PlaySatiton Portable к PSP.

FeyFre ★★★★
()
Ответ на: комментарий от Xenius

Как сделать в асме под GNU/Linux это я не очень понял...

Что именно, память выделить? Если libc в процессе и через main() работаем, то malloc, иначе сисколить, выяснив номер brk (это лишь теория, афаик не иметь libc в юникслайках это дебильная затея).

перед ним какой-то мусор

Там помойму дос FCB размещал, пока не стало deprecated.

arturpub ★★
()
Последнее исправление: arturpub (всего исправлений: 1)

В общем, не с того конца ты подходишь. Не с языка начинать надо. Нужно понять что делает ЦП. Суть. А суть простая - копирование чисел и преобразование чисел. До меня дошло всё это в тот самый момент, когда я понял что точки на экране - это попросту единицы в ОЗУ. 1 - есть точка. 0 - нет точки. Или, точнее, 1 - точка горит, 0 - погашена. А изменение картинки на экране достигается тупо мат. преобразованиями и копированием. Это было потрясающе. Тогда у меня был Вектор 06Ц, я писал на бейсике и изучал синенькую брошюрку «От бейсика к ассемблеру». Я долго не мог понять, какого хрена считай что все команды ЦП сводились к копированию.

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

targitaj ★★★★★
()
Ответ на: комментарий от targitaj

синенькую брошюрку «От бейсика к ассемблеру»

Омфг я не один такой!!!

arturpub ★★
()

Я так понимаю, что текст программы на ассемблере необходимо компилировать, да? Есть какой-нить предустановленный компилятор в GNU/Linux?

Вообще да, но это не та компиляция, которую делают языки, вроде Си. Это скорее трансляция

Есть какие-то общие правила написания программ? Что-то вроде var arr; function(){};. Как-то же необходимо связывать меж собой команды процессора.

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

Что это за WASM или TASM?

WASM это или Watcom Assembler или Web Assembly. Последний к нормальным ассемблерам отношения не имеет. А вот TASM это Turbo Assembler - нормальный транслятор ассемблера, который можно сравнивать с Watcom Assembler.

Сборка программы на ассемблере возможна не на устройстве, для которого пишется программа? Если сравнивать с компиляцией ядра Linux.

Конечно возможна. Особенно легко это получается сделать, если сам транслятор ассемблера умеет работать на любой архитектуре, и к нему предоставляются исходники. А если он сам на ассемблере написан(например как FASM) то его на чужой архитектуре только через эмулятор запускать. Или например эти TASM MASM к которым нет исходников и которые только под винды и дос в скомпилированном виде есть. Запускать в GNU/Linux их просто так не выйдет, надо wine или какой-нибудь dosbox ставить.

Я так понимаю, что для «переменных» необходимо жестко указывать ячейку памяти процессора и ОЗУ, да?

Можно локальные переменные в стеке хранить.

Что на счет этого стоит учить? Необходимо для старта читать кучу материала о страницах памяти и т.д.?
В общем, кто что посоветует, с чего начать, где эти основы брать?

Советую начать с http://stolyarov.info/books/asm_unix

Планирую начать с чего-то простого, например, Z80 или MC6800.

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

А собственно, зачем тебе ассемблер?

SZT ★★★★★
()
Последнее исправление: SZT (всего исправлений: 1)
Ответ на: комментарий от targitaj

Че то не понятно, глянул, что такое парное/непарное:

Парные числа - это числа, которые делятся на 2 : 2,4,6,8 и т.д.
Непарные числа - это числа, которые делятся на 2 с остатком 1,3,5,7 и т.д.

Тут же тупо нужно в цикле пробежаться с оператором «%»:

if number % 2 != 0
   println(непарное)
   break

Нахрена тут «исключающее или»? Чтобы твой код выглядел загадочнее?

foror ★★★★★
()
Ответ на: комментарий от arturpub

Ну, когда пишешь на асме md5 и он работает быстрее md5sum в твоём дистрибутиве, то первое время писаешься от радости.

На wiki.osdev.org тоже можно сходить, но там теоретическая база нужна для некопипаста. Имхо, пусть сначала языком овладеет, а потом уже в архитектуру зарывается.

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

d ★★★★
()

А почему ты считаешь, что квалификация программиста как то зависит от низко/высоко - уровневости? Разве хирург должен быть микробиологом, для того чтобы стать хорошим профи? Невозможно охватить всего, и не нужно, достаточно общих представлений о физической работе компьютера. И даже наоборот, иногда полезней абстрагироваться от этого, чтобы в голове постоянно не маячила мысль о перформансе.

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

callbackhell
()
Ответ на: комментарий от foror

Полагаю, под парностью тут имеется ввиду, что число встречается два раза. А непарное число в этом массиве есть в единственном экземпляре

SZT ★★★★★
()
Ответ на: комментарий от SZT

Вообще да, но это не та компиляция, которую делают языки, вроде Си. Это скорее трансляция

Ух ты, а компиляция, которую делают языки вроде си не является трансляцией?

callbackhell
()
Ответ на: комментарий от callbackhell

А я где-то сказал, что компиляция это не трансляция?
Из википедии:

A compiler is a computer program (or a set of programs) that transforms source code written in a programming language (the source language) into another computer language (the target language), with the latter often having a binary form known as object code.[1] The most common reason for converting source code is to create an executable program.
The name «compiler» is primarily used for programs that translate source code from a high-level programming language to a lower level language (e.g., assembly language or machine code). If the compiled program can run on a computer whose CPU or operating system is different from the one on which the compiler runs, the compiler is known as a cross-compiler. More generally, compilers are a specific type of translator.

Ассемблер сам является низкоуровневым ЯП и «компилятор» ассемблера правильнее называть транслятором. Ассемблер, в отличии от высокоуровневых компилируемых ЯП, типа C, C++, Pascal, FORTRAN и проч. не строят абстртактное синтаксическое дерево, не занимается constant folding-ом, не выкидывает «мертвый» код и не делает кучу других вещей ввиду самой специфики того, что это ассемблер. Что сказали - то и будет. Есть конечно всякие там макросы в ассемблере, но все равно это транслятор. Если в ассемблер запилят некий тьюринг-полный макроязык, на нем (этом макроязыке) в принципе можно сделать какой-никакой компилятор, но таким бредом ни один здравомыслящий человек заниматься не будет

SZT ★★★★★
()
Ответ на: комментарий от SZT

Ассемблер сам является низкоуровневым ЯП

Он является низкоуровневм в отношении си, но высокоуновневым в тношении нейтива. Принцииальной разницы тут нет.

Ассемблер, в отличии от высокоуровневых компилируемых ЯП, типа C, C++, Pascal, FORTRAN и проч. не строят абстртактное синтаксическое дерево

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

но таким бредом ни один здравомыслящий человек заниматься не будет

Да? Значит авторы сишечки и других макроассемблеров не здравомыслящие люди?

callbackhell
()
Ответ на: комментарий от SZT

А я где-то сказал, что компиляция это не трансляция?

И да, ты сказал это

Вообще да, но это не та компиляция, которую делают языки, вроде Си. Это скорее трансляция

callbackhell
()

суть и с чего начать?

Древняя, замшелая, но предельно простая классика: Абель.

Планирую начать с чего-то простого, например, Z80 или MC6800.

«Микроконтроллеры AVR. Практикум для начинающих.» ©.

quickquest ★★★★★
()

А вообще, если уж говорить о «мастерстве» программиста в вакууме, то я бы разделил языки по другому. Есть языки, коорые компилируются за один проход, это называется, условено, нажми на кнопку, получи результат. Рантайм таких языков не позволяет модифицировать код исходника в рантайме. Если выражаться языком лисперов, на нем невозможны программы, которые пишут программы. Эти языки являются наиболее примитивными языками, независимо от из уровня, будь то асм или хаскель. Обратное так же справедливо. Вот, как раз умение владеть перезаписью кода в рантайме, в том или ином виде, и определяют мастерство и искусство программирования. Когда ты не просто реализуешь программу, а реализуешь программы, которые реализуют программы. На практике, это означает владение ООП- и рефлексивными языками.

callbackhell
()

с чего начать?

С чтения Таненбаума. На изучение ассемблера забей.

grimwaken
()

Вот же тебе делать нефиг! Ты собрался свое ведро/компилятор писать что ли? Если нет, то на кой тебе ассемблер?

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от callbackhell

Он является низкоуровневм в отношении си, но высокоуновневым в тношении нейтива. Принцииальной разницы тут нет.

Какие такие отношения? Есть понятие «низкоуровневый язык программирования» и понятие «высокоуровневый язык программирования». Читай определения, а не выдумывай какие-то там отношения. Иди википедию читай

In computer science, a low-level programming language is a programming language that provides little or no abstraction from a computer's instruction set architecture—commands or functions in the language map closely to processor instructions. Generally this refers to either machine code or assembly language. The word «low» refers to the small or nonexistent amount of abstraction between the language and machine language; because of this, low-level languages are sometimes described as being «close to the hardware.» Because of the close relationship between the language and the hardware architecture programs written in low-level languages tend to be relatively non-portable.

Это почему же? ты видел реализацию компилятора своими глазами, чтобы утверждать это?

Да. Я читал своими глазами абстрактные синтаксические деревья(промежуточные представления) порождаемые компилятором GCC. Изучал архитектуру это самого GCC. Читал про устройство GIMPLE, GENERIC. Читал документацию на LLVM байткод. Даже заглядывал в исходники GCC. Даже отправлял багрепорты
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66123
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66178
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68027
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66152

Это относится к оптимизациям, и к вопросу отношения не имеет. скорей всего, компилятор асма тоже оптимизирует код.

Это почему еще не имеет? Какие оптимизации можно по-твоему сделать на уровне ассемблера? Заменить длинный JMP на короткий? Что там оптимизировать?

Да? Значит авторы сишечки и других макроассемблеров не здравомыслящие люди?

Сишке до макроассемблера очень далеко.

SZT ★★★★★
()
Ответ на: комментарий от callbackhell

Эмм, и где оттуда следует что компиляция - не трансляция?

SZT ★★★★★
()
Последнее исправление: SZT (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.