Как стать автором
Обновить

Комментарии 39

Что используете для разработки и дебага asm?

Для дебага компилируемых в натив-код языков точно полезно.

простой редактор (vim / nano / gedit) - ну и принтлны, коды возврата, пайпы, светодиоды для отладки

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

Кстати, в начале 90-х я изучал C++ после ассемблера. Книг не было, интернета тоже. Пользовался встроенной справкой F1. Метод изучения был такой - я знал, что мне нужно на ассемблере и подбирал такой код на C++, который компилировался в нужный мне :)) Ну, сурово, конечно... но в начале 90-х и C++ был попроще...

Кстати, поиск нулевого символа в строке обычно делается по другому, цепочечными командами. Как бы цикл внутри команды, x86 и такое умеет (REP, REPE, REPNE, REPNZ, REPZ). Автор их не использует, видимо, из педагогических соображений...

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

да нет конечно, просто подзабыл уже - для x86 всё-таки я уже ассемблер давно не использую, кроме конечно разборок в чужих проектах :)

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

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

Метод изучения был такой - я знал, что мне нужно на ассемблере и подбирал такой код на C++, который компилировался в нужный мне :)) Ну, сурово, конечно... но в начале 90-х и C++ был попроще...

Забавно, но это до сих пор актуально для меня но в области FPGA и xHDL. Я знаю, что мне надо получить схематически, я пишу на xHDL, собираю, открываю RTL и смотрю, насколько точно понял меня синтезатор. После нескольких итераций получается прям отлично.

В 64-разрядном режиме, если память не изменяет, строковые операции выпилены.

Значит, с чем-то ещё спутал. Всё ж под ПК на асме уже четверть века не быдлокодил, особо поэтому не слежу :)

Но, вроде б, для реализации функций вроде memcpy стандартные либы используют пересылки через SIMD-регистры. Или тоже с чем-то путаю?

Оптимальный вариант зависит от микроархитектуры, размера и выравнивания данных, где то лучше SIMD, где то rep movs. Вот тут можно глянуть, как работает glibc на невыровненных данных, в частности

6. On machines with ERMS feature, if size greater than equal or to __x86_rep_movsb_threshold and less than __x86_rep_movsb_stop_threshold, then REP MOVSB will be used.

mov \fn, %rax

Эм... И оно компилируется?

вроде да. пошёл перепроверил. и компилируется и работает

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

не знаю что за красноглазые, но по моим ощущениям порядок операндов приблизительно в половине ассемблеров (ну может 40 на 60 процентов) обратный. в целом большой проблемы это не вызывает кроме команд сравнения (вот после cmp 0, eax как будет действовать jge)

Просто я привык на интелях (MCS48, MCS51, i8080, x86/x64) кодить в синтаксисе самого интеля.

В ГНУсном ассемблере изначально заимствовали порядок, принятый в родном ассемблере PDP-11, но почти во всём остальном всё исказили; потом зачем-то применили его к интеловскому, но изрядная часть других архитектур использует синтаксис, "родной" для архитектуры, а не для ГНУсных извращенцев.

Вообще, практически единственная задача AS -- глотать выхлоп GCC и преобразовывать его в объектный файл. Для написания сколько-нибудь серьёзных ассемблерных программ он непригоден (нет очень многих возможностей, и, в частности, макросредств).

нет очень многих возможностей, и, в частности, макросредств

Каких именно макросредств Вам нехватает в GAS ? Не то, чтобы мне он сильно нравится, но мне всегда казалось что в GAS переизбыток всякого разного мета-синтаксиса из-за чего программы на нём нечитаемы.

Что такое традиционные макрокоманды, знаете? Какие, скажем, были в ассемблере OS/360? Вот ничего подобного в нём нет. Локальных меток (определённых только внутри блока, ограниченного нормальными метками) тоже нет -- лишний гемор при написании команд переходов. А переизбыток в нём директив для вывода всякой разной информации в объектный файл -- как раз для того, чтобы переваривать выхлоп компилятора и помещать в объектный файл сгенерированную компилятором отладочную информацию.

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

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

Сишный препроцессор исключительно убог. В той же ОС/360 процесс генерации (сборки) ОС построен как раз на использовании ассемблера с его макросредствами: параметры будущей системы описываются кучей макрокоманд, и ассемблер на выходе даёт не объектный файл, а текст заданий, выполнение которых, собственно, и сгенерирует систему. Ну а для этого макросредства должны иметь возможность вычислений во время трансляции, обработки строк, ветвлений, циклов и т.д. (Конкретно в асме ОС/360 это всё синтаксически довольно коряво -- всё ж первая половина 1960-х -- но функционально полноценно.)

Что такое традиционные макрокоманды, знаете? Какие, скажем, были в ассемблере OS/360? Вот ничего подобного в нём нет.

Вспомнила бабка Юрьев день. :) Нет, с макроассемблером в OS/360 я знаком не был, наверное многое потерял.

В GAS используется синтаксис обычного Сишног препроцессора, а он достаточно фичкав чтобы управлять сборкой ядер таких ОС как Linux и *BSD. Но мне видится весь этот синтаксис очень убогим и избыточно сложным.

Ну, если и потеряли, то лишь в плане знакомства с возможностями довольно навороченных макросредств. Синтаксически, повторюсь, он довольно страшненький, и многие вещи можно было бы решить лучше (в частности, лучше решено в макроассемблере PDP-11 -- но функционально он несколько слабее).

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

Боюсь представить каких делов можно наворотить с циклами в макросах. :-)

Хотя, программисты на LISP как-то справляются с такой сложностью.

Ну, скажем, если макрокоманда описывает 8 дисководов на одном контроллере, то она развернётся в восемь блоков управления устройством -- по одному на каждый из дисководов. Часть информации в них идентичная, часть (вроде адреса устройства) отличается.

Какая расточительность, по тем-то временам. :-) Почему не один кусок кода с параметром - адрес привода ?

Наоборот, это очень компактное представление. Код общий для всех типов дисков, все необходимые параметры (далеко не только адреса) -- как раз в блоках управления.

Но есть и отличие - номера системных вызовов поменялись. Они их все перепутали, Карл!!!

Они и на Линуксе на разных платформах сильно отличаются.

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

Да, для x86-64 табличку действительно оптимизировали, но та же оптимизация актуальна и для других платформ, а по факту везде по историческим причинам делали по своему. На более менее новых архитектурах есть тенденция использовать общие номера из linux/include/uapi/asm-generic/unistd.h

Но есть и отличие - номера системных вызовов поменялись. Они их все перепутали, Карл!!!

Да, забавно получилось - в 64bit фрюхе пришли к линуховому формату системного вызова, но линухоиды усмотрели в этом опасность и всё напрочь поменяли. :-)

Кстати, int 0x80 во FreeBSD 64bit всё еще легальный способ вызова системы. Только что проверил:

код
.section .data
msg: .ascii "Hi, Peoplez!\n"
len = . - msg

.section .text
.global _start

_start:
mov $4, %rax
mov $1, %rdi
mov $msg, %rsi
mov $len, %rdx
int $0x80
//syscall

mov $1, %rax
mov $0, %rdx
int $0x80
//syscall

rz@butterfly:~ % as -o a.o a.s
rz@butterfly:~ % ld a.o -o a
rz@butterfly:~ % ./a
Hi, Peoplez!

Любопытно, спасибо - это протестировать я не догадался :) загрузка аргументов через стек в 64-битном ядре не работает.

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

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

Сисколлов с большим числом параметров нет, обычно там передаются указатели на большие структуры. Но прикол в другом. К моменту появления 64-битных ОС проведенные бенчмарки уже не показывали какого-то выигрыша в линуксовой схеме сисколлов, видимо за счет кэшей и прочих микроархитектурных решений. Гораздо более серьезное влияние на производительность оказывал сам процесс переключения контекста и копирование данных между ядрёной и пользовательской памятью. Что в линухе, что во фре это является очень тяжелым процессом. Поэтому переход на линуховую схему был больше PR-ный ход, чтобы ублажить часть сомнивающихся. :)

Ну, я подозреваю. Переключение контекста -- это всегда дорого, а если при этом сыплются кэши и/или TLB, то вообще жуть... В частности, поэтому настоящих микроядерных осей и нет (та же QNX ни разу не микроядерная, если брать сей термин, как он изначально понимался: в ней абсолютно все функции традиционного ядра вроде управления процессами, потоками и памятью, находятся в общем адресном пространстве, и лишь драйверы устройств вынесены в отдельные пространства -- но такое было возможно ещё в той же RSX-11 и VAX/VMS).

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

А что подразумевается под тэгированной памятью?

Тэггированный указатель как в E2K в защищенном режиме. Указатель который не является адресом, а некий уникальный идентификатор блока памяти. В нём закодирован размер блока, права доступа и т.д.

Итак, мы соорудили две подпрограммы

В линуксовом ассемблере до сих пор нет адекватных средств оформления подпрограмм, или Вы решили не рассматривать их с целью упрощения?

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории