Забыл важный коммент: По значению поля type определяется какой член из списка используется. Это условие в нашем случае(попытка заполнения структуры через push) не так важно, потому что известно каков конечный вид структуры. Вот я и привел в пример самый "фатальный" - byte+dword+word, то есть type+pszVal+cchVal Проще метода, чем вычитание выровненной длины из esp((длина shr 2) * 4) и последующее заполнение через мувы, я не нашел. Будут варианты?
Tupo > Не вижу ничего общего между DBVARIANT и SSS (кроме одинаковых названий полей) - расположение в памяти различное. #pragma pack не приведена, видимо это будет выглдадеть так: Код (Text): name - offset - size type +0 1 bVal +4 1 cVal +4 1 wVal +4 2 sVal +4 2 dVal +4 4 lVal +4 4 pszVal +4 4 cchVal +8 2 cpbVal +4 2 pbVal +8 4 Какие проблемы с помещением значений в стэк push'ами ? Все аргументы можно рассматривать как dword и всё... правда при этом masm не сможет проверять размер, и не ясно как быть с командами вроде "push al"... это в fasm можно просто переопределить макрос push и он будет делать push eax
Как же лихо ты сделал всё кратное 4 Думаю, легче от того не станет, если я скажу, что #pragma pack(1) Я же привел в пример именно эту структуру, так как с ней уже работал. И меня особо не волновало "как-там-у-них-в-MSVC" - я ж её в асме обрабатываю. Так что правильные смещения такие: Код (Text): name - offset - size type +0 1 bVal +1 1 cVal +1 1 wVal +1 2 sVal +1 2 dVal +1 4 lVal +1 4 pszVal +1 4 cchVal +5 2 cpbVal +1 2 pbVal +3 4
Tupo любую структуру можно сформировать на стэке методом S_T_A_S_ независимо от выравнивания её членов. Кстати так ещё и автоматически поддерживается необходимое выравнивание стэка. Конечно push тогда не всегда будет соответствовать инициализации отдельного члена структуры. Можно и комбинированным методом в конце концов...
Код (Text): #pragma pack(1) typedef struct { BYTE type; struct { WORD cpbVal; BYTE *pbVal; }; }; } DBVARIANT_SIMPLIFIED; void __stdcall SomeAPIFunc(DBVARIANT_SIMPLIFIED *pdbv); // {{ MASMed snippet void sample() { DBVARIANT_SIMPLIFIED dbv = {1, {2, 0x12345678}}; SomeAPIFunc(&dbv); } //}} ---------------------------------------------------------------------- ----------- sample proc push 00123456h push 78000201h push esp call SomeAPIFunc add esp, 08h ret sample endp
Эт-понятно. Срезать/переносить байты я умею. Проблема в другом: В отличие от твоего примера на С, пример на асме абсолютно НЕчитаем. Когда такую структуру заполняешь раз 10-15 в разных участкх программы, то вручную осуществлять такую оптимизацию слишком накладно! Проще и нагляднее: Код (Text): @StructSize macro StructName if (sizeof StructName and 3) EXITM %((sizeof StructName shr 2) + 1) * sizeof DWORD else EXITM %sizeof StructName endif endm sample proc sub esp, @StructSize(DBVARIANT_SIMPLIFIED) mov BYTE PTR [esp+DBVARIANT_SIMPLIFIED.btype], 1 mov WORD PTR [esp+DBVARIANT_SIMPLIFIED.cpbVal], 2 mov DWORD PTR [esp+DBVARIANT_SIMPLIFIED.pbVal], 12345678h push esp call SomeAPIFunc add esp, @StructSize(DBVARIANT_SIMPLIFIED) ret sample endp P.S. Подправил малость код
Ну, думаю можно это дело макросами облегчить как-то... А вообще, IMHO, читабельность и эффективность кода на асме - взаимоисключающие критерии. Для достижения приемлемого компромисса компилятор должен быть оптимизирующим. Многие "читабельные" программы на асме не лучше кода сгенерированного скажем MS VC с отрубленной оптимизацией. :-(
Это не выход. Оптимизация кода - вещь хорошая, но для программ на ассемблере ненужная. Оптимизировать нужно не код, а алгоритм. Оптимизация кода осуществляется только в критичных участках программы. Вот оптимизатор алгоритмов - вещь нужная, ибо в подавляющем большинстве случаев(из моей личной практики) производительность программы значительно повышается за счет оптимизации алгортма этой программы. Кстати, на wasm.ru нет ни одной статьи о программах, которые позволяют удобно и быстро рисовать алгоритмы Возможно потому что настоящий генерал дзена "держит-алгоритм-в-голове" :Р
Гм... можно тогда узнать, почему ты выбрал MASM в качестве среды программирования ? И мы ведь о построении кода говорим, а не алгоритма, так ведь ? Я просто имел ввиду, что повышение читабельности ассемблерного кода почти всегда приводит к понижению качества результирующего бинарного кода и наоборот. Это обратная сторона полного контроля над генерируемым кодом, который дает асм - сильная связь между исходным и бинарным кодом. Оптимизирующий компилятор ослабляет эту связь, давая возможность программисту выразить алгоритм в более читабельном коде, сохраняя приемлемую эффективность. Конечно за счет снижения контроля над бинарным кодом. То есть IMHO на асме стоит писать в том случае, если главный критерий -- эффективность кода. А если на первом месте - читабельность, сопровождаемость, масштабируемость и т.п., то думаю следует писать на С/С++. Лично я предпочитаю смешанный вариант.
Tupo > Я изходил из приведённого кода, разве я ошибся? green > на fasme так можно: Код (Text): macro PUSH_DBVARIANT_SIMPLIFIED type, cpbVal, pbVal { local .type, .cpbVal, .pbVal local .dword1, .dword2 ; можно добвить условную компиляцию ; if type = virtual at 0 .type db type .cpbVal dw cpbVal .pbVal dd pbVal dd 0 load .dword1 dword from 0 load .dword2 dword from 4 end virtual push .dword2 .dword1 } ; используем PUSH_DBVARIANT_SIMPLIFIED 1, 2, 0x12345678 ; fasm rulezzz: 68 56341200 push 123456 68 01020078 push 78000201
S_T_A_S_ класс! я бы тоже на fasm перешёл... но AFAIK он плохо согласуется со средствами разработки от MS: нет H2INC, развитой командной стоки, генерации debug info...
S_T_A_S_ прмоединяюсь к green'у - супер! Наконец-то(на третьей странице топика) ты написал то, что обещал в самом начале топика Как говорится - вопрос исчерпан. Надо будет глянуть что за зверь этот flat assembler. Меня такие нюансы как green'а не останавливают: 1. h2inc - не использую. Ибо 7 потов сойдет, пока устранишь все места в хедере, которые не нравятся этой утилите. Плюс, в конце концов, h2inc скажет тебе, что добрую половину хэдера он не смог перевести. По мне быстрее вручную конвертнуть. И имея столь печальный опыт общения с h2inc, выработался стиль: к каждому проекту делаю "кастом"-инклуды, хоть это и занимает немного дополнительного времени, зато вспомнишь все нюансы использования функций, участвующих в проекте 2. debug info - не использую. Так как быстрее и эффективнее прогу отлаживать в отладчике. Под 98ой пользовал SoftIce, но когда переехал на XP оказалось что для моих нужд достаточно OllyDbg green Раньше я использовал связку MASM+Basic - в MASM'e писал программы, а в Бейсике отлаживал алгоритмы тех самых критичных мест - например, алгоритм расшифровки/шифровки блока данных. Затем я стал использовать MASM+MSVC98 - приоритеты те же самые. Плюс VC помог мне понять оконный механизм винды(под Win3.11 оконных приложений не писал). Сейчас, когда MSVC98 под XP не поставить, я использую связку MASM+PHP - приоритеты те же. (Был коротенький этап - использовал яву, в качестве второго языка. Но быстро утомило неимоверное количество классов) Главная причина использования MASM'а - не люблю, когда в конечном коде появляются куски кода, которые я не писал Я хотел сказать, что занесение push'ами структуры в стек - это ненужная оптимизация, так как прирост производительности программы от такой оптимизации очень незначительный! Оптимизация всего кода достаточно эффективна в HLL. Для программы на ассемблере - её нужно использовать выборочно, хотя бы потому что есть возможность использовать её выборочно Оптимизация алгоритма - очень эффективный прием повышения производительности для программ на асме, а для програм на HLL - этот приём эффективен втройне.
green > fasm может делать ms coff - мне этого достаточно. Параметры командной строки отсутствуют - это идеология fasm! Да и к чему она там? тип выходного файла определяется директивой format, что ещё нужно от ассемблера... С debug info это проблема всех трансляторов, т.к. формат pdb закрыт :-( но fasm может делать листинг, и из него можно получить практически всё что угодно (даже тот же pdb) Кстати, можно просто экспортировать нужные метки - тогда Olly "имена" для всего, что есть в секции экспорта. H2INC никогда не использовал и в masm - толку от неё мало на сложных файла. Кто-то использует perl, но можно и ручками конвертить. IMHO хорошо бы сразу .h файлы скармливать ассемблеру научаться, но это требует изменения самого синтаксиса ассемблера. Tupo > Ну это не совсем то, вернее совсем не то, да и доходит до меня долго ))) > Скорее прироста как раз не будет, только объём меньше, зато уменьшается вероятность ошибок вроде 2х mov в одно место
Ну-да, сумбурно всё как-то получилось. На самом деле меня интересовало: 1. Объявление и использование стековой структуры(спросил про переменную, так как у неё формат проще)... 2. ...в макросе... 3. ...при условии, что поля её имеют разный размер. Ранее ты сказал(и показал), что fasm без труда собирает все стековые переменные, объявленные в разных местах процедуры, в один кадр. А сейчас привел пример объявления и использования структуры с полями различной длины в макросе. Из примера видно, что выдержана и наглядность и оптимальность кода одновременно. Так что твой ответ, как говорится, прямо в десятку! Дело за малым - переехать на fasm