Имеет ли смысл перевод на asm тела функци,а затем его ассемблерная вставка? Код (Text): unsigned long LFSR1() { for(int i = 0; i < 32; i++) { unsigned long int ret = 0; SReg1 = ((((SReg1 >> 31) ^ (SReg1 >> 6) ^ (SReg1 >> 4) ^ (SReg1 >> 2) ^ (SReg1 >> 1) ^ SReg1) & 0x00000001) <<31) | (SReg1 >> 1); ret <<= 1; ret |= (SReg1 & 0x00000001); } return ret; } Код (Text): unsigned long LFSR1() { unsigned long int ret = 0; asm { ... ... ... } return rt; }
Если ты уверен, что сможешь написать более эффективный (исходя из потребностей: скорость, размер и т.д.) код, чем его сгенерирует компилятор, то ответ - имеет.
А не правильнее будет так: SReg1 = ((((SReg1 & (1 << 31)) ^ (SReg1 & (1 << 6)) ^ (SReg1 & (1 << 4)) ^ (SReg1 & (1 << 2)) ^ (SReg1 & (1 << 1)) ^ SReg1) ?
Вот такую фиговину сделал MSVC++ 7.0 Код (Text): ?LFSR1@@YAKXZ PROC NEAR ; LFSR1, COMDAT ; 6 : unsigned long int ret = 0; mov ecx, DWORD PTR ?SReg1@@3IA ; SReg1 xor eax, eax mov edx, 32 ; 00000020H push esi ; 19 : } ; 20 : return ret; ; 21 : } npad 2 ; 6 : unsigned long int ret = 0; $L274: ; 7 : for(int i = 0; i < 32; i++) ; 8 : { ; 9 : SReg1 = ((((SReg1 >> 31) ; 10 : ^ (SReg1 >> 6) ; 11 : ^ (SReg1 >> 4) ; 12 : ^ (SReg1 >> 2) ; 13 : ^ (SReg1 >> 1) ; 14 : ^ SReg1) ; 15 : & 0x00000001) <<31) ; 16 : | (SReg1 >> 1); lea esi, DWORD PTR [ecx+ecx] xor esi, ecx shl esi, 1 xor esi, ecx shl esi, 2 xor esi, ecx shl esi, 2 xor esi, ecx shl esi, 25 ; 00000019H xor esi, ecx and esi, -2147483648 ; 80000000H shr ecx, 1 or ecx, esi ; 17 : ret <<= 1; ; 18 : ret |= (SReg1 & 0x00000001); mov esi, ecx and esi, 1 add eax, eax or eax, esi dec edx jne SHORT $L274 mov DWORD PTR ?SReg1@@3IA, ecx ; SReg1 pop esi ; 19 : } ; 20 : return ret; ; 21 : } ret 0 ?LFSR1@@YAKXZ ENDP ; LFSR1 На моем рабочем эстоооонском прескотте выполняется в темпе <20 тактов на одну итерацию. Кто сможет быстрее?
Ustus Если пошевелить мозгами, а не повторять выдранный из книжки код, то можно сделать покороче и побыстрее Код (Text): ;SReg1 = ((((SReg1 >> 31) ;^ (SReg1 >> 6) ;^ (SReg1 >> 4) ;^ (SReg1 >> 2) ;^ (SReg1 >> 1) ;^ SReg1) ;& 0x00000001) <<31) ;| (SReg1 >> 1); ;-------------------- mov ecx,SReg1 mov eax,ecx rol ecx,1 ;собираем все биты для xor в младший байт and ecx,10101111b setp cl ;cl = 1 если число единиц четное, т.е. серия xor = 0 sub cl,1 ;перенос, если серия xor = 1 rcr eax,1 Вроде ничего не напутал ?
DeFuckTo не забывай о том, что ассемблерные вставки привязывают тебя к компилятору, что не есть гуд и если потом ты захочешь перенести свою программу на тот же линух, то тебе придется долго трахаться. так же ассемблерные вставки срубают оптимизацию (в большей или меньше степени), в частности, компилятор, встретив асм-вставку может сгенерировать стандартный пролог и сохранять кучу регистров в стеке, в результате чего прирост производительности за счет ассемблерной оптимизации будет уничтожен тормозами компилятора. уж если и писать на асме, то всю функцию целиком.
DeFuckTo если забить на неисполняемый стек (который мало где есть), то можно поступить так: int (*foo)(); bar() { // объявляем массив и заполняем его машинным кодом char shell[]="\x0F\x31"; // RDTSC // преобразуем указатель на массив в указатель на функцию foo foo = (int(*)())shell; // вызываем функцию foo, возвращая результат ее выполнения // для простоты результат усекается до 32-бит, передаваемых в регистр EAX, // старшие 32-бита, помещаемые командой RDTSC в регистр EDX мы отбрасываем return foo(); } main() { int a; a = bar(); }
вы правы товарищи. ret там быть должен. это я просто выравл его из контекста. а еще там был пролог, обращающийся к аргументам, который я тоже сократил, поскольку там довольно муторный способ определения аргументов, зато ассемблерная вставка автоматически распознает си, паскаль и stdcall методы передачи параметров да, и еще забыл сказать, что на системах с неисполняемым стеком это работать не будет. на винде еще можно вызывать VirtualProtect. а вот в юнихе - mprotect работает не всегда. в некоторых случаях линух ложит стек в отдельный селектор, запрещая исполнение кода, и на уровне страниц атрибуты "исполняемый" просто игнорируются. но это - уже экзотика.
cpp_and_wasm В VS2005 я ещё ни разу не замечал глюки, связанные с ассемблерными вставками и оптимизацией. Может быть, Вы имеете в виду GCC? GCC действительно страшно глючит в этим плане даже в более-менее свежих версиях.