Комментарии 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
Эм... И оно компилируется?
вроде да. пошёл перепроверил. и компилируется и работает
лучше пишите подробнее что именно смущает, м.б. тогда мы сможем разобраться есть ли тут загвоздка
Ааа, красноглазые и тут отличились, синтаксис AT&T: https://en.wikipedia.org/wiki/X86_assembly_language#Syntax
Вопрос снимаю.
не знаю что за красноглазые, но по моим ощущениям порядок операндов приблизительно в половине ассемблеров (ну может 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).
Это все из-за тяжелого наследия под названием "виртуальная память" (пэйджинг). Если отказаться от пэйджинга то можно хорошо увеличить производительность системы. Но тогда потребуется либо тэггированная память, либо системы на базе виртуальной байт-код машины. Не понятно что из них меньшее зло. Ну и переход на такие системы это слишком радикальное решение для подавляющего числа пользователей.
Итак, мы соорудили две подпрограммы
В линуксовом ассемблере до сих пор нет адекватных средств оформления подпрограмм, или Вы решили не рассматривать их с целью упрощения?
Поревьюим и порефакторим — Ассемблер для любопытных #2