Народ подскажите траблу.Из asm проги нужно вызвать atoi(без нее никак) или что-то вроде нее. Посмотрел в отладчике прогу на с, эта гадостная функция ни откуда не вызывается, а ассемблируется вместе с прогой.Подскажите, как быть.
Написано давно, тут уже обсуждалось. Оптимизировалось по скорости. То что тут предлогалось скорости явно не добавляло, или резало функционал. Вобщем этот код должен работать как стандартный сишный atoi() не больше и не меньше =) Код (Text): ;; crt atoi() implementation by Dr.Golova ;; [email=]mailto:[/email] dr_golova@mail.ru ;; compile it with NetWide Assembler (NASM) ;; nasmw.exe -o atoi.obj -f coff -L atoi.asm bits 32 atoi: push ebx mov ecx, dword [esp+8] ;; input string ptr ;; scan and skip leading spaces .skip_space: movzx eax, byte [ecx] cmp eax, ' ' jnz short .check_sign inc ecx jmp short .skip_space ;; check and save sign .check_sign: mov edx, eax ;; save posible sign byte xor ebx, ebx cmp eax, '-' jz short .check_char cmp eax, '+' jnz short .no_sign .check_char: inc ecx movzx eax, byte [ecx] .no_sign: sub eax, '0' cmp eax, 9 ja short .non_digit lea ebx, [ebx+ebx*4] lea ebx, [eax+ebx*2] jmp short .check_char .non_digit: cmp edx, '-' ;; check sign byte jnz short .done neg ebx .done: mov eax, ebx pop ebx retn end
В ntdll.dll есть такая функция, если важен маленький размер, то используй ее. З.Ы. Я пользуюсь StrToIntA из shlwapi.dll
Если уж речь зашла о спаривании инструкций Код (Text): inc ecx movzx eax, byte [ecx] можно заменить на Код (Text): movzx eax, byte [ecx+1] add ecx, 1 ; inc ecx ; как больше нравится
Dr.Golova Я бы на свой вкус тоже movzx использовал, но на твой многозначительный [beep] отвечаю ) Во-первых, понятие спаривания инструкций благополучно скончалось вместе с последними реликтовыми PMMX. И инструкция movzx eax,[mem] на PPlain\PMMX как раз и является неспариваемой и ее рекомендовалось заменять на xor eax,eax + mov al, byte[mem] Во-вторых, ты наверное имел ввиду не спаривание, а проблему partial registers. Но в рассматриваемом случае она благополучно решается путем вставки одной единственной xor eax,eax в начало функции, поэтому кроме лишних 2-х байт кода никаких других отрицательных последствий от использования операций с AL, а не EAX тутa нема )) Хотя с movzx конечно "правильнее" PS: Повторив матчасть , приходим к выводу что с AL код получается короче, т.к. 1) movzx на байт длиннее mov, 2) cmp\sub al,imm8 в минимальной кодировке - два байта, а cmp\sub eax,imm8 - минимум 3
Да в msvcrt, но реализована она там с ужасными наворотами, а вот в ntdll гораздо проще - по кр.мере в XP
leo > Можно и так сказать, если под спариванием понимать выполнение _двух_ команд. Назавём это спараллеливанием, глубокий смысл не поменяется. Вот это не может выполняться параллельно - зависимость по данным: Код (Text): inc ecx movzx eax, byte [ecx] Если инструкции поменять местами - зависимость исчезает. > Вот здесь возможна зависимость по данным, которая мешает параллелиться: Код (Text): mov al, byte [ecx] ;... lea ebx, [eax+ebx*2] хотя реально инструкции находятся далеко, и это может быть не заметно.
S_T_A_S_ > "здесь возможна зависимость по данным, которая мешает параллелиться" Совершенно верно Причем эта зависимость точно такая же как и при замене mov al,[ecx] на movzx eax,[ecx] (ес-но при условии, что в начале цикла был xor) PS: А мануальные страшилки о предпочтительности movzx eax перед mov al относятся к случаю, когда xor eax стоит непосредственно перед mov al и тогда ес-но имеем и зависмость mov от xor и лишнюю нагрузку на декодер
S_T_A_S_ Угу, совершенно верно У partial register access есть два implementation depended аспекта: 1) зависимость по данным, 2) возможный дополнительный штраф при чтении целого регистра после записи в частичный регистр В семействе P6 (включая Pentium M, model < 13) аллокатор назначает независимые темп-регистры операциям записи в EAX, AX, AH, AL не заботясь о соответствии данных в старших разрядах (по-видимому просто забивает нулями старшие разряды частичных темп-регистров). Поэтому в P6 операции записи в разные части одного регистра независимы по данным. Зато возникает проблема объединения данных при обращении к целому регистру после записи в частичный, т.к. проц должен скомбинировать (наложить) данные частичного регистра AL на текущее состояние всего EAX. Объединение данных происходит в момент отставки инструкции записи, а это задержка минимум в 6-7 тиков => partial register stall. Чтобы его избежать в P6 предусмотрено отслеживание обнуления 32-битных регистров операциями xor и sub. Если EAX был обнулен, то комбинировать нечего и ждать отставки mov AL,X незачем, т.к. текущий темп-регистр AL с нулевыми старшими разрядами по сути и есть текущее представление регистра EAX => no partial stall. В атлонах, P4 и старших моделях Pentium M есть только одна текущая копия GPR регистра, т.е. при записи в AL проц всегда берет содержимое текущего регистр EAX, перезаписывает младший байт и полученное значение является новым представлением всего регистра EAX. Поэтому 1) операция чтения\записи любой части регистра зависима по данным от предыдущей модификации всего или любой части этого же регистра, 2) кроме зависимости по данным никакого доп. штрафа при чтении целого регистра после частичной записи - нет. Никакого partial register stall нет, а есть обычная зависимость по данным с учетом того, что AX, AH, AL это ни какие-то особые регистры, а просто части единого EAX PS: Далеко однако нас занесло от atoi, и куда она делась - прям в соответствии с названием темы
Думаю, документация содержит не более 20% информации. Смотри сам - al - один теневой регистр, eax - другой теневой регистр. Может, теневых регистров не хватит?
S_T_A_S_ Неправильно думаешь Инфы достаточно, если конечно не зацикливаться только на последних мануалах IA-32. В частности про partial registers в P6 есть инфа в мануалах по оптимизации от 1997 и 1999 гг. Да и в статьях Intel Technology Jornal можно много полезного найти, и А.Фог свою инфу не из пальца высосал Переименование регистров это основа основ out-of-order execution. Чтобы не усложнять логику переименования, при любой модификации архитектурного регистра EAX, ему назначается новый физический регистр. Это делается потому, что перед операцией модификации могла быть одна или несколько инструкций чтения этого регистра и за счет переупорядочивания эти инструкции могут в итоге выполниться позже, чем запись нового значения в EAX. А помнить предисторию чтений всех регистров (GPR,FPU,XMM) ес-но накладно - проще при каждой модификации назначать новый физический регистр. А по поводу того, что регистров не хватит переживать не стоит, т.к. число физических регистров связано с емкостью ROB, а большинство микроопов могут изменять только один регистр. Раз число мопов в ROB ограничено, то совершенно неважно изменяют они разные регистры или один и тот же - если и будет переполнение, то оно будет определяться числом мопов, а не тем какие регистры они изменяют