Причиной создания этого топика есть: 1) мне в руки попал кусок кода написанный на си. И это был не просто кусок сорса. Это был эллегантный до мозга костей код. Этот код можно было читать даже тогда, когда знаешь си на уровне школьника. Я просто влюбился в стиль офомления 2) постоянное желание менять что-то к лучшему. Незнаю как Вы отреагируете на этот пост, но возможно он кому-то поможет не наступать на грабли, связанные с написанием программ на flat assembler. Можно было бы не полениться и написать небольшую статью на эту тему, но наблюдается глобальная нехватка времени. Итак начнем: Я сравнительно недавно программирую на фасме и ввиду того, что код написанный на ассемблере достаточно емкий(обьем скомпилированного бинарника маленький, а сорс - ёмкий) всегда пытался вывести некоторую формулу написания кода, который бы отличался нормальной читабельностью, но в то же время время, потраченное на оформление стремилось к минимуму. пробовал и так и эдак лепить комментарии, смотрел как пишут другие. Скажу честно: большая часть сорсов, которые написаны на фасме по своему оформлению просто ужас в чистом виде. Возьмем к примеру сорс, морфан 1,0 (вроде 1,0): Код (Text): ;---------------------- ; SUB REG32,1 ; INC REG32,1 INS3: ; 4 BYTE mov byte [esi],83h inc esi mov eax,8 call brandom32 push eax add eax,0E8h mov byte [esi],al inc esi mov byte [esi],01h inc esi pop eax add eax,40h mov byte [esi],al inc esi add edi,4 jmp nextp ;--------------------------------- ; PUSHAD ; 3nuyf ; POPAD INS4: ; 2 BYTE, To ALL mov byte [esi],60h inc esi ; THIS GARBAGE REG32 mov byte [esi],61h inc esi add edi,2 jmp nextp ;---------------------------------- недостатки: 1)так нельзя. Во-первых нет отступа, во вторых всякие ;--------- или ;xxxxxxxxx или ;=============== только вначале кажутся милыми и очаровательными, но когда начинаешь смотреть на код, которого к примеру на 500 строк, то восприятие его несколько ухудшается. Единственное что, там в принципе нормально разбито на процедуры, хотя они там вперемешку с кодом(т.к нет отступа) и поэтому без спецIDE которые умеют сворачивать процедуры читать данный код(к примеру в fasmw) - это просто пипец. 2) Все разбито на небольшие блоки. Гуд, но только тогда, когда пишешь сам проект. Любой, кто будет читать такой код никогда не разберется в нем. Нужно ставить много мелких бряков и собирать с бряками. Далее - в отладчик и смотреть что там происходит. Иначе - никак. Разбор такого кодеса не очень сложен, но достаточно трудоёмен. При этом можно бродить по коду эдак дня три. Да и сам автор, если он откроет свой сорец через три-четыре месяца будет плеваться на самого себя, что не прокоментил участки кода и так вот писал(привет-привет автору кода). недостатков в коде крайне много, кто читал много сорсов - тот в принципе поймет. Дальше от себя: 1)Никогда не используйте много локальных и глобальных меток, как средство отделения блоков кода. Используйте метки только тогда, когда вы будет в них прыгать в каком-то цикле. Вот что получается из всего этого: Причиной этого кстати является топик созданный мной немного ранее: https://www.wasm.ru/forum/viewtopic.php?id=38490 такой стиль - головная боль и причина многих суидидов(наверное). 2) Программируйте процедурами. Все сабфункции не ленитесь и выносите в отдельные инклюды - так будет понятней, что делает основной код 3) используйте локальные переменные, пытайтесь избегать глобальных переменных, по крайней мере там, где это возможно. 4) не комментируйте блоки кода перед самим кодом типа: Код (Text): ;dfgvsdfgsdvsdvsd ;sdfvsvsdvsdvsdvsdvsdvsdv ;vsvsdvsdvsdvsdvsdvsdvvvvvvvvv xor eax,eax xor eax,eax xor eax,eax это нереально читать вообще. Код сбивается в кучу и вообще ничего не понятно в нем. 5)в процедурах пересохраняйте параметры самой процедуры в локальные переменные 6) никогда не пишите смещениями типа: Код (Text): mov eax,[eax+0x3c] лучше написать инклюд и сделать так: Код (Text): mov eax,[eax+IMAGE_DOS_HEADER.e_lfanew] согласитесь, по-приятней будет 7)хватит короче Вот к какой концепции оформления я пришел: 1)весь код - тройной таб 2)разделение блоков кода следующим образом: Код (Text): ;; ;;краткое описание блока ;; отступ кода три таба содержимое блока 3)комментарии -> двойная точка с запятой 4)ненавижу циклы код типа такого: Код (Text): .if .if .if .if .if .if .............. ................ .endif .............. ............ .............. ........... .endif ............ .............. ........... .endif .endif .endif .endif .endif .endif делайте типа(будет скриншот) такого: в общем дальше описывать не буду - просто приложу скрин В общем-то не ставлю из себя крутого перца\гуру и тд. Просто может то, что я написал - поможет тем, кто знает чуть меньше, ну и вызовет улыбку у тех - кто знает много больше, чем я
common_up Изучать этот сурс. Пример того, как следует оформлять код: http://files.virustech.org/indy/wrk/trap.asm http://files.virustech.org/indy/wrk/kimacro.inc
оформлять код следует не хуже чем это делает IDA если вы можете нормально читать листинг IDA, вы прочитаете и исходник.
common_up Мда... А скрины очень информативные. Пересоздайте скрины, иначе обсуждать практически нечего. Не согласен. Если это функция, или начало определенного алгоритма, имеет смысл как раз описать его подробно, а не расписывать по каждой строчке. Это более грамотно. Хорошие специалисты так делают. Это нормальная практика. И это читаемо. А дальше вы пишете: Противоречите собственному 4ому пункту. Да и вообще - подробнее. Кратное оно хорошо, но чем подробнее тем лучше. Хех, вы это ненавидите. А что вы любите? cmp\je\jne... etc А вообще гляньте код клерка. Вполне читабельно. Вы к тому же ничего не сказали про именование переменных\процедур, конвенций вызовов. Пока хватит.
common_up ну чай дядь Томаш задает ритм и стиль... видели сорцы фасма-то ? код идет сплошной стеной, ток в переходах вроде есть отступы. ни комментариев, ни дробления так сказать логического нету -- ничего. оно внутри-то конечно может и ни разу не быдлокод, но оформление уродское. Clerk имхо махонький недостаток -- неэкономное использование вертикального пространства, комментирование вида: Код (Text): PREFIX_REPEAT_COUNT EQU 11 ; Prefix table length ; ; defines all the possible IO privileged IO instructions ; IOInstructionTable label byte ; db 0fah ; cli ; db 0fdh ; sti db 0e4h, 0e5h, 0ech, 0edh ; IN db 6ch, 6dh ; INS db 0e6h, 0e7h, 0eeh, 0efh ; OUT db 6eh, 6fh ; OUTS IO_INSTRUCTION_TABLE_LENGTH EQU 12 ; ; definition for floating status word error mask ; FSW_INVALID_OPERATION EQU 1 FSW_DENORMAL EQU 2 можно бы и не ставить ; сверху и снизу комментария. пустых двух строк хватило бы. а то выходит 1 строка смысловая -- а занимает целых 5 строк вертикального пространства. с другой стороны -- в глаза бросается лучше, читабельнее выходит. P.S. тут могу провести параллель с С : 1TBS допустим вертикальное прос-во экономит, но менее заметен, а ГНУтые и гей-стили наоброт.
Пользуюсь в основном этой утилитой. В результате, пишу на ассемблере, но почти C-выражениями. Написал утилиту на этом языке в 1000 строк, на выходе получил около 10000 asm-строк. Удобно. Но на сайте демо-версия с уймой ограничений с примером для fasm. Консольная версия - полностью функциональная была... Но под DOS
ИМХО, код клерка читабелен, но затраты времени на описание каждого шага превышают затраты на программирование.
Guru_of_Zen Разделение коментов и кода делает восприятие их более удобным. Не все пользуются такими тулзами как ТС, в том числе и наверно архитекторы собиравшие этот код. Да и я пользуюсь блокнотом. dyn Там довольно сложный код, который читает вся корпорация. Поэтому нормальные коменты необходимы. Как пример возьмите какойнибудь мой код, допустим этот http://files.virustech.org/indy/Code/AVrf2/Ldr.asm - коменты минимальны, так как особо комментировать нечего, оформление приличное(имена понятные и пр.).
dyn, но не слишком читабельно: Код (Text): Call SEH_Prolog .if ImageBase == NULL mov eax,fs:[TEB.Peb] mov ecx,PEB.LoaderLock[eax] mov eax,PEB.Ldr[eax] mov eax,PEB_LDR_DATA.InLoadOrderModuleList.Flink[eax] mov eax,LDR_DATA_TABLE_ENTRY.InLoadOrderModuleList.Flink[eax] mov eax,LDR_DATA_TABLE_ENTRY.DllBase[eax] ; ntdll.dll mov ImageBase,eax .endif invoke LdrImageNtHeader, ImageBase, addr ExitFlag Если тут .if выдвинуть или код вдвинуть, будет проще находить .endif-ы и .else. Что по этому поводу думает Clerk? Почему так? А мне кажется, что неиспользуемые локальные метки, сдвинутые вправо на четыре пробела (код на восемь, глобальные не сдвинуты) читаются быстрее комментариев, не засоряют при этом листинг, да ещё и нахаляву разделяют смысловые куски кода. Если не переусердствовать, конечно.
Майкрософт свои исходники очень красиво оформляет, чего нельзя сказать о линукс исходниках, где отсутствует венгерская нотация, ужаснее исходников мир незнает
iZzz32 Я использую условные конструкции по минимому. Незачем вводить табуляцию для не вложенных условных конструкций. Можно было написать локальную метку, но просто печатать мне удобнее так. Код набирается очень быстро.
В 2006 году писал прогу... Выглядит так. Код (Text): ;-------------------------------------------------------------------------------- MatrixNCopy proc NMatrixS:DWORD,NMatrixD:DWORD LOCAL MatrixName[2]:DWORD invoke MatrixNFind,NMatrixS .if eax mov esi, eax ;<Проверим матрицу на правильность mov eax, [esi.N_MATRIX.lpMatrix] invoke MatrixCheck,eax .if !eax invoke PrintErrors,05h,$TA0('MatrixNCopy') ret .endif ;>Проверим матрицу на правильность invoke MatrixNFind,NULL .if eax mov edi, eax ;<Выделим память под копию матрицы mov eax, [esi+N_MATRIX.lpMatrix] ;<Поправка на размер заголовка матрицы mov eax, [eax+MATRIX.mSize] add eax, sizeof MATRIX ;>Поправка на размер заголовка матрицы invoke GlobalAlloc,LMEM_FIXED or LMEM_ZEROINIT,eax ;>Выделим память под копию матрицы mov [edi+N_MATRIX.lpMatrix], eax ;Запишем указатель на новую матрицу mov eax, NMatrixD mov [edi+N_MATRIX.Name_M], eax ;Запишем имя новой матрицы mov eax, edi ;<Поправка на размер заголовка матрицы mov eax, [esi+N_MATRIX.lpMatrix] mov eax, [eax+MATRIX.mSize] add eax, sizeof MATRIX ;>Поправка на размер заголовка матрицы invoke CopyMemory,[edi.N_MATRIX.lpMatrix],[esi.N_MATRIX.lpMatrix],eax .else invoke PrintErrors,00Eh,$TA0('MatrixNCopy') .endif .else mov eax, NMatrixS mov MatrixName, eax xor eax, eax mov MatrixName[4], eax invoke PrintErrors,011h,ADDR MatrixName .endif ret MatrixNCopy endp Стараюсь давать имена меткам и процедурам так, что бы потом было меньше вопросов. Да и если код ложить ровно и использовать .equ для задания констант с нормальными и понятными именами. То и коментов потом меньше нужно писать. И так понятно, что и куда. Сравните две строчки. (под AVR) Код (Text): ldi r16, SetDDRAM|Line2|Pos13 ... ldi r16, $CD ... Ко второй строке ну явно будет куча вопросов. А есть ли вопросы к первой? Кто и что не понял?
Соглашусь. Но к чему следовать мелкомягкому стилю типа юзанья RPL_MASK!? Когда то мыщ недоумевал, поддерживаю. Зачем нагромождать, если можно заюзать литерал? В обозримом будущем RPL_MASK явно не изменится ))
medstrax1 Например or dword ptr [ebx],3 - что в Ebх ссылка на значение сегментного регистра не понятно. Если определить как or dword ptr [ebx],RPL_MASK - сразу понятно, ну если известен смысл константы.