Почeму у процессоров i8080/i8086/z80 имеется флаг AC индикации переноса из младшего ниббла в старший, чтобы корректно работали инструкции AAA/AAS/DAA, но отсутствуют команды ветвления, управляемые этим флагом? Инженеры некогда просто сцепили два 4-битных сумматора в один 8-битный, а перемычку переноса вывели в флаг. Это всё понятно… Однако, могли бы зарезервировать отдельный регистр с результатом побитового переноса. Авось, где-нибудь да пригодился для оптимизации кода… Об этом я давно думал. Если операции DIV/IDIV выдают двойной результат - частное и остаток, почему тогда ADC/ADD/SBB/SUB/CMP не могут вернуть промежуточный результат побитового переноса? Так как ADC/ADD/SBB/SUB/CMP являются комплексным сочетанием операций XOR/AND, можно было бы вывести промежуточные биты переносов между этими звеньями… В ЯВУ типа Паскаль и Си в комплект к операциям DIV и «/» имеются ещё MOD и «%» для возврата остатка. Хотя процессор одной операцией возвращает всегда частное с остатком, в ЯВУ это - разные операции… Для чего это нужно? По школьной программе язык Бейсика осваивается за 4 часа. Наверное не все знают, что Бейсик по книжкам я осваивал около года самостоятельно! Хотя, благодаря рубрике «Радио начинающим» журналов РАДИО я вполне разбирался в логических схемах к шестому классу. Но с трудом осваивал Бейсик! Всё произошло в один миг. В журнале изучал фрагмент на ассемблере от игры «Гонки» и сопоставлял с цветной таблицей команд К580ВМ80. И в один миг что-то щёлкнуло и я понял суть операции MOV… Так из электронщика я стал программистом, который стал бить голые дампы. А потом уже махом разобрался и с Бейсиком… И вот, как электронщик, я не мог понять, почему в схеме я всегда могу взять сигнал из любой точки, а в программе для этого нужно дублировать ход операций, маскировать и сдвигать… Особенно не понравилось, что при прямой работе с графикой в ZX-Spectrum мне приходилось производить кучу операций сдвига, так как буфер экрана там нелинейный. P.S.: Выбрось из процессора любую, казалось бы, ненужную инструкцию редкого использования, как большинство программ тут же не смогут работать! Тем самым, будь у процессоров не один/два флага переноса, а целый отдельный регистр, программы бы и его использовали и не могли без него… Файл таблицы промежуточных результатов переносов между звеньями сумматора
Eсли мы эмулируем процессор, естественно, 40-летнего возраста, то без этих команд, с большей или меньшей вероятностью, программы могут словить глюк. (Бывали случаи, когда многочисленные игры работали нормально, а Бейсик спотыкался даже на PRINT с печатью константы) А при переходе между поколениями одной архитектуры, когда инженерами удаляются команды и это документируется, то, естественно, всё будет гладко
Интересныe ссылочки нашёл: lock cmpxchg8b eax NTAPI Undocumented Functions long nop (Эти nop'ы, например, можно эзотерически включать в свой код и организовать WhiteSpace-язык на уровне x86-инструкций… Интересно было бы написать программу, которая запускает и исполняет код из одних nop'ов, хотя сам по себе этот код самостоятельно при запуске ничего не делает и отладчиком одни лишь nop'ы трассируются… Практически, обфускация по-чёрному!) P.S.: Может, кому пригодятся… И мне, чтобы не потерять…
Ммм... зачем? Исходник по третьей ссылке умеет выравнивать метки либо вариациями на тему lea esi,[esi] (играясь с mod/rm и sib), либо разными вариантами NP 0F 1F /0, the multi-byte form of NOP, точно так же играясь с mod/rm и sib. В зависимости от того, поддерживает ли процессор такой ноп. The multi-byte NOP instruction does not alter the content of a register and will not issue a memory operation. То есть такой код ну совсем ничего не делает. ЗЫ: интеловский справочник потерять сложней, а в нем все то же самое изложено
Одни из первых реализаций по обходу ав(полиморфы) использовали не мод кода, а затирание его частей нопами. Добро пожаловать в 90-е года.
A я их и не покидал! A я и написал, что WhiteSpace-язык в Блокноте тоже ничего не делает: Нужен интерпретатор-транслятор. Так и с nop'ами: Запустил программу - ничего не происходит и дебаггер не помогает. Но, с помощью nop-конвертора, эти nop'ы парсятся и сохраняются в другой файл, в котором вместо длиннющих nop'ов - какие-то реальные операции. P.S.: Очень быстро читали текст, скорее всего, и не вникли в мою мысль…
Paguo_86PK, > Запустил программу - ничего не происходит и дебаггер не помогает. Это только означает что ты не умеешь(тк не знаешь архитектуру) пользоваться отладчиком. > Но, с помощью nop-конвертора, эти nop'ы парсятся и сохраняются в другой файл Я об этом и говорю, полностью тебя понял. Это древние идеи полиморфизма, самые начала виксов. Это столь примитивные техники, не удивительно что ты немного отстал лет на 20.
Нет, про идею кодировать в этих нопах что-то свое я понял, но упоминание об исполнении этого кода в отладчике как бы подразумевает прямое исполнение.
Простo, пока возился с своей тематикой портово-/эскейпного API, наткнулся ещё на эти nop'ы, которые никаким образом исключения не генерируют и поломали мне мозг. И вдруг подумалось, что если Escape-инструкции я изыму из-под FPU, то как раз эти nop'ы можно было бы подставить для FPU-команд. Прежде, чем что-то сейчас писать мне в ответ … P.S.: Вспомните про мой принцип с гвоздями! Или мы уже забыли друг друга?
Paguo_86PK, Помню хорошо, дело не в этом. Вы чётко описали очень старую реализацию, где сигнатуры удаляются путём добавления фиксированного мусора(именно нопы). Сигнатуры или криптофункции вычисляются не от кода, а от его кодирующих данных. Эта простота и дала работу аверам. > которые никаким образом исключения не генерируют Какого рода исключения ? Кодировка эффективного адреса хоть в инструкции имеется, но нет выборки - есть есчо инструкция LEA.
Этo я знаю. Особенно, если «LEA R,R1», а не «LEA R,M», так как она любит только векторы вычислять… Итого, через LEA имеем 64 комбинации, ведущие к исключению.
Вопрос? Код (ASM): nop2 MACRO mov ecx, ecx ENDM nop3 MACRO lea ecx, [ecx+12h] org $-1 db 0 ENDM nop4 MACRO lea esp, [esp+12h] org $-1 db 0 ENDM nop5 MACRO mov edx, edx lea ecx, [ecx+12h] org $-1 db 0 ENDM nop6 MACRO lea ecx, [ecx+12345678h] org $-4 dd 0 ENDM nop7 MACRO lea esp, [esp+12345678h] org $-4 dd 0 ENDM Есть ли более длинные NOP'ы? Использую х86 MASM, UASM.
Выше ссылка была на стандартные последовательности Код (C): /* Various efficient no-op patterns for aligning code labels. Note: Don't try to assemble the instructions in the comments. 0L and 0w are not legal. */ static const unsigned char f32_1[] = {0x90}; /* nop */ static const unsigned char f32_2[] = {0x66,0x90}; /* xchg %ax,%ax */ static const unsigned char f32_3[] = {0x8d,0x76,0x00}; /* leal 0(%esi),%esi */ static const unsigned char f32_4[] = {0x8d,0x74,0x26,0x00}; /* leal 0(%esi,1),%esi */ static const unsigned char f32_5[] = {0x90, /* nop */ 0x8d,0x74,0x26,0x00}; /* leal 0(%esi,1),%esi */ static const unsigned char f32_6[] = {0x8d,0xb6,0x00,0x00,0x00,0x00}; /* leal 0L(%esi),%esi */ static const unsigned char f32_7[] = {0x8d,0xb4,0x26,0x00,0x00,0x00,0x00}; /* leal 0L(%esi,1),%esi */ static const unsigned char f32_8[] = {0x90, /* nop */ 0x8d,0xb4,0x26,0x00,0x00,0x00,0x00}; /* leal 0L(%esi,1),%esi */ static const unsigned char f32_9[] = {0x89,0xf6, /* movl %esi,%esi */ 0x8d,0xbc,0x27,0x00,0x00,0x00,0x00}; /* leal 0L(%edi,1),%edi */ static const unsigned char f32_10[] = {0x8d,0x76,0x00, /* leal 0(%esi),%esi */ 0x8d,0xbc,0x27,0x00,0x00,0x00,0x00}; /* leal 0L(%edi,1),%edi */ static const unsigned char f32_11[] = {0x8d,0x74,0x26,0x00, /* leal 0(%esi,1),%esi */ 0x8d,0xbc,0x27,0x00,0x00,0x00,0x00}; /* leal 0L(%edi,1),%edi */ static const unsigned char f32_12[] = {0x8d,0xb6,0x00,0x00,0x00,0x00, /* leal 0L(%esi),%esi */ 0x8d,0xbf,0x00,0x00,0x00,0x00}; /* leal 0L(%edi),%edi */ static const unsigned char f32_13[] = {0x8d,0xb6,0x00,0x00,0x00,0x00, /* leal 0L(%esi),%esi */ 0x8d,0xbc,0x27,0x00,0x00,0x00,0x00}; /* leal 0L(%edi,1),%edi */ static const unsigned char f32_14[] = {0x8d,0xb4,0x26,0x00,0x00,0x00,0x00, /* leal 0L(%esi,1),%esi */ 0x8d,0xbc,0x27,0x00,0x00,0x00,0x00}; /* leal 0L(%edi,1),%edi */ static const unsigned char f16_3[] = {0x8d,0x74,0x00}; /* lea 0(%esi),%esi */ static const unsigned char f16_4[] = {0x8d,0xb4,0x00,0x00}; /* lea 0w(%si),%si */ static const unsigned char f16_5[] = {0x90, /* nop */ 0x8d,0xb4,0x00,0x00}; /* lea 0w(%si),%si */ static const unsigned char f16_6[] = {0x89,0xf6, /* mov %si,%si */ 0x8d,0xbd,0x00,0x00}; /* lea 0w(%di),%di */ static const unsigned char f16_7[] = {0x8d,0x74,0x00, /* lea 0(%si),%si */ 0x8d,0xbd,0x00,0x00}; /* lea 0w(%di),%di */ static const unsigned char f16_8[] = {0x8d,0xb4,0x00,0x00, /* lea 0w(%si),%si */ 0x8d,0xbd,0x00,0x00}; /* lea 0w(%di),%di */ static const unsigned char jump_31[] = {0xeb,0x1d,0x90,0x90,0x90,0x90,0x90, /* jmp .+31; lotsa nops */ 0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90, 0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90, 0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90}; static const unsigned char *const f32_patt[] = { f32_1, f32_2, f32_3, f32_4, f32_5, f32_6, f32_7, f32_8, f32_9, f32_10, f32_11, f32_12, f32_13, f32_14 }; static const unsigned char *const f16_patt[] = { f32_1, f32_2, f16_3, f16_4, f16_5, f16_6, f16_7, f16_8 };