<?xml version='1.0' encoding="utf-8"?>
      <rss version='2.0'>
      <channel>
      <title>Форум на Исходниках.RU</title>
      <link>https://forum.sources.ru</link>
      <description>Форум на Исходниках.RU</description>
      <generator>Форум на Исходниках.RU</generator>
  	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=458534&amp;view=findpost&amp;p=3919635</guid>
        <pubDate>Sat, 22 Mar 2025 09:24:46 +0000</pubDate>
        <title>MMX и x87 FPU - общие регистры и переключение режимов</title>
        <link>https://forum.sources.ru/index.php?showtopic=458534&amp;view=findpost&amp;p=3919635</link>
        <description><![CDATA[Majestio: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=458534&view=findpost&p=3919632'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Jin X &#064; <time class="tag-quote__quoted-time" datetime="2025-03-21T19:08:09+03:00">21.03.25, 16:08</time></span><div class='quote '>Majestio, зачем тебе MMX? Чисто из исторического интереса?</div></div><br>
Ага.<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=458534&view=findpost&p=3919632'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Jin X &#064; <time class="tag-quote__quoted-time" datetime="2025-03-21T16:08:09+00:00">21.03.25, 16:08</time></span><div class='quote '>3DNow&#33; особо не имеет отношения к MMX, это типа AMD-шное расширение MMX&#39;а, но это не MMX.<br>
Это всё равно, что говорить, что расширение AES или SHA – это SSE или AVX, потому что они используют те же регистры </div></div><br>
Вычёркиваем&#33; :lol:]]></description>
        <author>Majestio</author>
        <category>Assembler</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=458534&amp;view=findpost&amp;p=3919632</guid>
        <pubDate>Fri, 21 Mar 2025 16:08:09 +0000</pubDate>
        <title>MMX и x87 FPU - общие регистры и переключение режимов</title>
        <link>https://forum.sources.ru/index.php?showtopic=458534&amp;view=findpost&amp;p=3919632</link>
        <description><![CDATA[Jin X: <strong class='tag-b'>Majestio</strong>, зачем тебе MMX? Чисто из исторического интереса?<br>
Сейчас SSE2 есть ну прям везде. На компах 20-25-летней давности (начиная с Pentium 4).<br>
Они шире в 2 раза, чем MMX, есть возможность работать с float&#39;ами/double&#39;ами (помимо int&#39;ов).<br>
Про AVX/FMA уж не буду, можно ещё встретить старые компы/ноуты/нетбуки (или какие-нибудь более-менее современные Atom/Celeron/Pentium&#39;ы), в которых этого нет. <br>
<br>
<span class="tag-color tag-color-named" data-value="mergepost" style="color: mergepost"><span class='tag-size' data-value='7' style='font-size:7pt;'>Добавлено <time class="tag-mergetime" datetime="2025-03-21T16:22:55+00:00">21.03.25, 16:22</time></span></span><br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=458534&view=findpost&p=3919469'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Majestio &#064; <time class="tag-quote__quoted-time" datetime="2025-03-19T16:54:16+00:00">19.03.25, 16:54</time></span><div class='quote '>Это означает, что при выполнении MMX-инструкций (они же 3DNow&#33;-инструкции)</div></div>3DNow&#33; особо не имеет отношения к MMX, это типа AMD-шное расширение MMX&#39;а, но это не MMX.<br>
Это всё равно, что говорить, что расширение AES или SHA – это SSE или AVX, потому что они используют те же регистры  :-?]]></description>
        <author>Jin X</author>
        <category>Assembler</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=458534&amp;view=findpost&amp;p=3919517</guid>
        <pubDate>Thu, 20 Mar 2025 08:52:23 +0000</pubDate>
        <title>MMX и x87 FPU - общие регистры и переключение режимов</title>
        <link>https://forum.sources.ru/index.php?showtopic=458534&amp;view=findpost&amp;p=3919517</link>
        <description><![CDATA[Majestio: +1  :good:]]></description>
        <author>Majestio</author>
        <category>Assembler</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=458534&amp;view=findpost&amp;p=3919502</guid>
        <pubDate>Thu, 20 Mar 2025 07:58:50 +0000</pubDate>
        <title>MMX и x87 FPU - общие регистры и переключение режимов</title>
        <link>https://forum.sources.ru/index.php?showtopic=458534&amp;view=findpost&amp;p=3919502</link>
        <description><![CDATA[macomics: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=458534&view=findpost&p=3919492'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Majestio &#064; <time class="tag-quote__quoted-time" datetime="2025-03-20T06:38:45+00:00">20.03.25, 06:38</time></span><div class='quote '>Попутно вопрос ... Допустим мы использовали инструкции MMХ, а затем мы решили использовать инструкции, использующие ST* (первый раз с начала исполнения).<br>
<br>
Что мы должны сделать:<br>
<br>
Хватит просто EMMS<br>
Нужно только FINIT<br>
Нужно EMMS, а потом FINIT<br>
Что-то другое<br>
<br>
Собственно, в этом вопрос.</div></div><br>
Для ответа на это не надо читать других источников, кроме документации на процессор<br>
<span class="b-attach" data-size="169848" data-hits="81" data-attach-id="66923" data-attach-post-id="0">
			<span class="b-attach__title"></span><a class='b-attach-link' href='https://forum.sources.ru/index.php?act=Attach&amp;type=post&amp;id=0&amp;attach_id=66923' title='Скачать файл' target='_blank'>__________________________20250320_115723.png</a> (, : 81)
		</span> <br>
<br>
<span class="tag-color tag-color-named" data-value="mergepost" style="color: mergepost"><span class='tag-size' data-value='7' style='font-size:7pt;'>Добавлено <time class="tag-mergetime" datetime="2025-03-20T08:00:11+00:00">20.03.25, 08:00</time></span></span><br>
Достаточно EMMS]]></description>
        <author>macomics</author>
        <category>Assembler</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=458534&amp;view=findpost&amp;p=3919492</guid>
        <pubDate>Thu, 20 Mar 2025 06:38:45 +0000</pubDate>
        <title>MMX и x87 FPU - общие регистры и переключение режимов</title>
        <link>https://forum.sources.ru/index.php?showtopic=458534&amp;view=findpost&amp;p=3919492</link>
        <description><![CDATA[Majestio: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=458534&view=findpost&p=3919472'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Qraizer &#064; <time class="tag-quote__quoted-time" datetime="2025-03-19T18:08:11+00:00">19.03.25, 18:08</time></span><div class='quote '>Перед использованием MMX никаких специфических действий не требуется. &quot;Перевод&quot; FPU в режим MMX осуществляется автоматически на первой же MMX инструкции. При этом тэги выставляются не обязательно в NaN/inf, нули распознаются корректно. Только лишь после использования MMX для перевода в &quot;нормальный&quot; режим нужна EMMS.</div></div><br>
Попутно вопрос ... Допустим мы использовали инструкции MMХ, а затем мы решили использовать инструкции, использующие ST* (первый раз с начала исполнения). <br>
<br>
Что мы должны сделать:<br>
<br>
<ol class="tag-list" type="1"><li>Хватит просто EMMS</li><li>Нужно только FINIT</li><li>Нужно EMMS, а потом FINIT</li><li>Что-то другое</li></ol><br>
Собственно, в этом вопрос.<br>
<br>
<div class="tag-spoiler spoiler closed"><div class="spoiler_header" onclick="openCloseParent(this)">Скрытый текст</div><div class="body">Это было в моей статье:<br>
<div class='tag-quote'><span class='tag-quote-prefix'>Цитата</span> <div class='quote '>Основные моменты: MMX и x87 разделяют одни и те же регистры; смешанное использование без очистки приводит к конфликтам; после блока MMX-команд всегда нужно выполнять EMMS (<strong class='tag-b'><span class="tag-color tag-color-named" data-value="red" style="color: red">а при необходимости — FINIT</span></strong>) перед возобновлением работы с FPU. Это гарантирует корректность результатов и стабильность работы приложения.​</div></div><br>
Это правильно?</div></div>]]></description>
        <author>Majestio</author>
        <category>Assembler</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=458534&amp;view=findpost&amp;p=3919482</guid>
        <pubDate>Thu, 20 Mar 2025 05:53:08 +0000</pubDate>
        <title>MMX и x87 FPU - общие регистры и переключение режимов</title>
        <link>https://forum.sources.ru/index.php?showtopic=458534&amp;view=findpost&amp;p=3919482</link>
        <description><![CDATA[Majestio: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=458534&view=findpost&p=3919477'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>macomics &#064; <time class="tag-quote__quoted-time" datetime="2025-03-19T20:12:16+00:00">19.03.25, 20:12</time></span><div class='quote '>Иногда возникают ситуации, когда не нужно балансировать push и pop.</div></div><br>
Ну это triks за счет <span class="tag-font" data-value="Courier" style="font-family:Courier"><span class="tag-color tag-color-named" data-value="blue" style="color: blue">leave</span></span> ;) Но, в общем случае, <span class="tag-font" data-value="Courier" style="font-family:Courier"><span class="tag-color tag-color-named" data-value="blue" style="color: blue">pop</span></span> все же нужен.]]></description>
        <author>Majestio</author>
        <category>Assembler</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=458534&amp;view=findpost&amp;p=3919477</guid>
        <pubDate>Wed, 19 Mar 2025 20:12:16 +0000</pubDate>
        <title>MMX и x87 FPU - общие регистры и переключение режимов</title>
        <link>https://forum.sources.ru/index.php?showtopic=458534&amp;view=findpost&amp;p=3919477</link>
        <description><![CDATA[macomics: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=458534&view=findpost&p=3919476'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Majestio &#064; <time class="tag-quote__quoted-time" datetime="2025-03-19T20:03:56+00:00">19.03.25, 20:03</time></span><div class='quote '>Ну тут бы я готов поверить...  Но что-то чуйка меня &quot;тормозит&quot;. Просто логика подсказывает: после того как &quot;положил&quot; - достань&#33; Стек - это &quot;алгоритм/механизм&quot;. Или ты должен 1) &quot;сам достать&quot; или это 2) &quot;достают за тебя&quot;. Я предположил, что это &quot;достают за тебя&quot; (п.2) в следствии простого убиения процесса и аллоцируемой им памяти. С предоставленной тобой ссылкой ознакомлюсь завтро - сення не хочу портить себе настрой, если я не прав </div></div><br>
Это логика работы объектов, а не процессора. У процессора стек это просто область памяти и указатель на вершину. Его можно двигать как напрямую через add/sub/lea так и спец командами push/pop. Иногда возникают ситуации, когда не нужно балансировать push и pop. Например<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">proc:</div><div class="code_line">&nbsp;&nbsp; &nbsp;push rbp &nbsp; &nbsp; &nbsp;; положили в стек 8 байт со значением из rbp</div><div class="code_line">&nbsp;&nbsp; &nbsp;mov &nbsp;rbp, rsp ; изменили значение в rbp на значение из rsp</div><div class="code_line">&nbsp;&nbsp; &nbsp;sub &nbsp;rsp, 32 &nbsp;; изменили указатель стека еще на 32 байта, выделив место для локальных переменных</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;fldpi</div><div class="code_line">&nbsp;&nbsp; &nbsp;fstp qword [rbp - 10] ; обращение к адресу кратному не 8 для записи числа длиной 8 байт (для FPU это не критично)</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;movdqa xmm3, [rbp - 20] ; а вот тут уже будет ошибка</div><div class="code_line">&nbsp;&nbsp; &nbsp;movdqu [rbp - 21], xmm3 ; тут ошибки не будет</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;leave &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;; а вот хитрая команда. Он делает две инструкции разом: mov rsp, rbp и pop rbp (но это для однократной вложенности)</div><div class="code_line">&nbsp;&nbsp; &nbsp;retn &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ; после leave стек сбалансирован и не понадобилось запоминать количество байт для локальных переменных.</div></ol></div></div></div></div><script>preloadCodeButtons('1');</script><br>
<br>
Посмотрите как работают связка <strong class='tag-b'>enter N,M</strong> и <strong class='tag-b'>leave</strong>. Особенно интересно когда M &gt; 0]]></description>
        <author>macomics</author>
        <category>Assembler</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=458534&amp;view=findpost&amp;p=3919476</guid>
        <pubDate>Wed, 19 Mar 2025 20:03:56 +0000</pubDate>
        <title>MMX и x87 FPU - общие регистры и переключение режимов</title>
        <link>https://forum.sources.ru/index.php?showtopic=458534&amp;view=findpost&amp;p=3919476</link>
        <description><![CDATA[Majestio: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=458534&view=findpost&p=3919475'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>macomics &#064; <time class="tag-quote__quoted-time" datetime="2025-03-19T19:50:03+00:00">19.03.25, 19:50</time></span><div class='quote '>Нет. Не нужно ничего из стека вытаскивать.</div></div><br>
Ну тут бы я готов поверить... :lol: Но что-то чуйка меня &quot;тормозит&quot;. Просто логика подсказывает: после того как &quot;положил&quot; - достань&#33; Стек - это &quot;алгоритм/механизм&quot;. Или ты должен 1) &quot;сам достать&quot; или это 2) &quot;достают за тебя&quot;. Я предположил, что это &quot;достают за тебя&quot; (п.2) в следствии простого убиения процесса и аллоцируемой им памяти. С предоставленной тобой ссылкой ознакомлюсь завтро - сення не хочу портить себе настрой, если я не прав  :lol:]]></description>
        <author>Majestio</author>
        <category>Assembler</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=458534&amp;view=findpost&amp;p=3919475</guid>
        <pubDate>Wed, 19 Mar 2025 19:50:03 +0000</pubDate>
        <title>MMX и x87 FPU - общие регистры и переключение режимов</title>
        <link>https://forum.sources.ru/index.php?showtopic=458534&amp;view=findpost&amp;p=3919475</link>
        <description><![CDATA[macomics: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=458534&view=findpost&p=3919474'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Majestio &#064; <time class="tag-quote__quoted-time" datetime="2025-03-19T19:39:10+00:00">19.03.25, 19:39</time></span><div class='quote '>Ну, т.е. ты забыл выкинуть из стека по выходу raх. Хотя, думаю, это не только не важно, но и не нужно - ибо по завершении процесса вся им аллоцируемая память уничтожается. Смысл тогда?</div></div><br>
Нет. Не нужно ничего из стека вытаскивать.<br>
<br>
Тут все просто. Это инфа из <a class='tag-url' href='https://learn.microsoft.com/en-us/cpp/build/x64-calling-convention?view=msvc-170#alignment' target='_blank'>MSDN</a><br>
Оттого, что Windows активно использует стековую память для работы с xmm регистрами и командами обращения с выровненной памятью, то перед вызовом функции значение в rsp должно быть выровнено на 16. После вызова оно опять не выровнено (команда call записала в стек 8 байт - адрес возврата), но после push rbp/mov rbp, rsp оно опять выровнено (записано еще 8 байт - значение rbp и всего это будет 16 байт). Так вот на метку start вашей программы из ntdll будет команда call rax (или видел в некоторых версиях call qword [var]). Это сбивает значение rsp на метке start до не выровненного на 16 и push rax просто все исправляет.<br>
<br>
Хотя при выделении локальных переменных все точно так же. Надо поддерживать значение в rsp кратное 16.<br>
Если этого не делать, тогда в винде есть куча movdqa, из-за которых возникает исключение обращения к не выровненному адресу. В случае с ExitProcess сообщения с ошибкой может и не успеть появиться, но вот звук его появления MB_ICONERROR вы услышите.<br>
<br>
Даже если заглянуть в макросы к fasm можно найти в PROC64.INC<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">macro prologuedef procname,flag,parmbytes,localbytes,reglist</div><div class="code_line">&nbsp;{ local loc,fill,counter</div><div class="code_line">&nbsp;&nbsp; loc = (localbytes+15) and (not 15) ; Поддержание выровненного значение в rsp</div><div class="code_line">&nbsp;&nbsp; parmbase@proc equ rbp+16</div><div class="code_line">&nbsp;&nbsp; localbase@proc equ rbp-loc</div></ol></div></div></div></div>]]></description>
        <author>macomics</author>
        <category>Assembler</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=458534&amp;view=findpost&amp;p=3919474</guid>
        <pubDate>Wed, 19 Mar 2025 19:39:10 +0000</pubDate>
        <title>MMX и x87 FPU - общие регистры и переключение режимов</title>
        <link>https://forum.sources.ru/index.php?showtopic=458534&amp;view=findpost&amp;p=3919474</link>
        <description><![CDATA[Majestio: <strong class='tag-b'>Qraizer</strong> и <strong class='tag-b'>macomics</strong>, очень прошу привести пруфы, откуда ваша инфа&#33; Это не прецедент &quot;недоверия&quot;, мне нужно просто ознакомиться с тем что знаете вы, и чего не знаю я&#33; ;) <br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=458534&view=findpost&p=3919472'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Qraizer &#064; <time class="tag-quote__quoted-time" datetime="2025-03-19T18:08:11+00:00">19.03.25, 18:08</time></span><div class='quote '>Перед использованием MMX никаких специфических действий не требуется. &quot;Перевод&quot; FPU в режим MMX осуществляется автоматически на первой же MMX инструкции. При этом тэги выставляются не обязательно в NaN/inf, нули распознаются корректно. Только лишь после использования MMX для перевода в &quot;нормальный&quot; режим нужна EMMS.</div></div><br>
Откуда инфа?<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=458534&view=findpost&p=3919473'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>macomics &#064; <time class="tag-quote__quoted-time" datetime="2025-03-19T18:54:13+00:00">19.03.25, 18:54</time></span><div class='quote '>Для числа PI есть fldpi</div></div><br>
Ну ... не очень существенно, но полезно. Записываю&#33; ;) <br>
<br>
Другой вопрос...<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=458534&view=findpost&p=3919473'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>macomics &#064; <time class="tag-quote__quoted-time" datetime="2025-03-19T18:54:13+00:00">19.03.25, 18:54</time></span><div class='quote '>start: push rax ; чтобы выровнять стек на 16 после call из ntdll. Хотя тут это не критично, но может падать в ExitProcess без выравнивания стека.</div></div><br>
Немного прокачал тему. Зацени - всё ли правильно?<br>
<br>
<div class='tag-quote'><span class='tag-quote-prefix'>Цитата</span> <div class='quote '>В 64-битных системах (x86-64) существует требование к выравниванию стека на 16 байт перед вызовом функций. Это связано с соглашениями о вызовах (calling conventions), которые используются в Windows (Microsoft x64 calling convention) и других системах. <strong class='tag-b'>Как оказалось потом и в Linux, MacOSX, FreeBSD (мне интересных, дальше не смотрел)</strong></div></div><br>
Но рекомендуют чуть полнее, просто чтобы не забыть:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">start:</div><div class="code_line">&nbsp;&nbsp; &nbsp;push rax ; Выравниваем стек на 16 байт</div><div class="code_line">&nbsp;&nbsp; &nbsp;; Ваш код</div><div class="code_line">&nbsp;&nbsp; &nbsp;pop rax ; Восстанавливаем значение rax (если нужно)</div><div class="code_line">&nbsp;&nbsp; &nbsp;; Тут код завершение программы</div></ol></div></div></div></div><br>
Ну, т.е. ты забыл выкинуть из стека по выходу raх. Хотя, думаю, это не только не важно, но и не нужно - ибо по завершении процесса вся им аллоцируемая память уничтожается. Смысл тогда?]]></description>
        <author>Majestio</author>
        <category>Assembler</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=458534&amp;view=findpost&amp;p=3919473</guid>
        <pubDate>Wed, 19 Mar 2025 18:54:13 +0000</pubDate>
        <title>MMX и x87 FPU - общие регистры и переключение режимов</title>
        <link>https://forum.sources.ru/index.php?showtopic=458534&amp;view=findpost&amp;p=3919473</link>
        <description><![CDATA[macomics: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=458534&view=findpost&p=3919469'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Majestio &#064; <time class="tag-quote__quoted-time" datetime="2025-03-19T16:54:16+00:00">19.03.25, 16:54</time></span><div class='quote '><div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">start:</div></ol></div></div></div></div></div></div><div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">start: push rax ; чтобы выровнять стек на 16 после call из ntdll. Хотя тут это не критично, но может падать в ExitProcess без выравнивания стека.</div></ol></div></div></div></div><br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=458534&view=findpost&p=3919469'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Majestio &#064; <time class="tag-quote__quoted-time" datetime="2025-03-19T16:54:16+00:00">19.03.25, 16:54</time></span><div class='quote '><div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">fld qword [fp_value] &nbsp;; ST0 = 3.14</div></ol></div></div></div></div></div></div>Для числа PI есть fldpi]]></description>
        <author>macomics</author>
        <category>Assembler</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=458534&amp;view=findpost&amp;p=3919472</guid>
        <pubDate>Wed, 19 Mar 2025 18:08:11 +0000</pubDate>
        <title>MMX и x87 FPU - общие регистры и переключение режимов</title>
        <link>https://forum.sources.ru/index.php?showtopic=458534&amp;view=findpost&amp;p=3919472</link>
        <description><![CDATA[Qraizer: Перед использованием MMX никаких специфических действий не требуется. &quot;Перевод&quot; FPU в режим MMX осуществляется автоматически на первой же MMX инструкции. При этом тэги выставляются не обязательно в NaN/inf, нули распознаются корректно. Только лишь после использования MMX для перевода в &quot;нормальный&quot; режим нужна EMMS.]]></description>
        <author>Qraizer</author>
        <category>Assembler</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=458534&amp;view=findpost&amp;p=3919469</guid>
        <pubDate>Wed, 19 Mar 2025 16:54:16 +0000</pubDate>
        <title>MMX и x87 FPU - общие регистры и переключение режимов</title>
        <link>https://forum.sources.ru/index.php?showtopic=458534&amp;view=findpost&amp;p=3919469</link>
        <description><![CDATA[Majestio: <strong class='tag-b'><span class='tag-size' data-value='17' style='font-size:17pt;'><span class="tag-color" data-value="237de0" style="color: #237de0">MMX и x87 FPU - общие регистры и переключение режимов</span></span></strong><br>
<br>
MMX-регистры (MM0–MM7) используют те же физические регистры, что и FPU-регистры (ST0–ST7) в сопроцессоре x87. Это означает, что при выполнении MMX-инструкций данные в регистрах FPU могут быть перезаписаны – и наоборот. Ниже разберём, как именно организовано такое перекрытие, какие возникают конфликты при смешанном использовании, и как правильно переключаться между режимами с помощью инструкций FINIT и EMMS. <br>
<br>
<img class='tag-img' src='https://majestio.info/assets/img/stuff/MMX-FPUx86.png' alt='user posted image'><br>
<br>
Восьмеричный стек 80-битных регистров x87 FPU (ST0–ST7) с отображением регистров MMX (MM0–MM7) на их младшие 64 бита. Верхние 16 бит каждого FPU-регистра (область экспоненты) при работе MMX помечаются как 1, формируя специальное значение (NaN/∞)<br>
<br>
<strong class='tag-b'><span class='tag-size' data-value='14' style='font-size:14pt;'>Общий регистровый файл (MMX поверх FPU)</span></strong><br>
<br>
Архитектурно <strong class='tag-b'>восемь 64-разрядных регистров MMX являются алиасами (логическими копиями) восьми 80-разрядных регистров FPU</strong>.<br>
Процессор не вводит отдельного физического хранилища для MMX: вместо этого нижние 64 бита каждого регистра сопроцессора x87 (часть мантиссы) используются для хранения данных MMX, а верхние 16 бит остаются зарезервированы (и устанавливаются равными 1 при записи MMX-данных).Таким образом, <strong class='tag-b'>запись значения в регистр MMX автоматически заносит его в соответствующий FPU-регистр</strong>, и наоборот – загрузка числа в стек FPU приводит к появлению этого значения (его 64-битной части) в связном MMX-регистре. Такое решение было принято Intel по соображениям совместимости: <strong class='tag-b'>новые MMX-регистры “наложили” на существующие FPU-регистры, чтобы не нарушить механизмы сохранения/восстановления контекста</strong> в операционных системах. Проще говоря, раз ОС уже умела сохранять состояние FPU (например, при переключении задач), то дополнительного кода под MMX не потребовалось – состояние MMX сохраняется и загружается вместе с FPU благодаря общим физическим регистрам.<br>
<br>
<strong class='tag-b'><span class='tag-size' data-value='14' style='font-size:14pt;'>Конфликт при смешанном использовании MMX и FPU</span></strong><br>
<br>
Из-за общих регистров <strong class='tag-b'>невозможно одновременно полноценно пользоваться инструкциями x87 FPU и MMX</strong>. Любая операция с плавающим стеком FPU может затереть содержимое MMX-регистров, и наоборот – выполнение MMX-инструкций меняет состояние тех же регистров, что ожидаются FPU​. Когда выполняются <strong class='tag-b'>MMX-инструкции, FPU “видит” что его регистры заняты нестандартными данными</strong>. Аппаратно это реализовано так: при любой операции MMX сопроцессор помечает все восемь FPU-регистров как занятые действительными значениями (их тэги устанавливаются в 00b)​. Более того, верхние биты (экспоненты) каждого затронутого регистра устанавливаются в 1 (получается битовая маска, соответствующая NaN или бесконечности)​. В результате, если сразу после MMX попытаться выполнить обычную FPU-инструкцию без очистки, сопроцессор воспримет содержимое как некорректные числа с плавающей точкой. Это может привести к ошибкам, неожиданным результатам или исключениям (наподобие <strong class='tag-b'>#MF</strong> – FPU Floating-Point Error). Проще говоря, <strong class='tag-b'>смешивание FPU и MMX без специальной очистки состояния приводит к конфликту из-за неверного интерпретирования данных</strong>. Практическое следствие: чтобы избежать постоянно возникающего конфликта, <strong class='tag-b'>программы обычно разделяют использование MMX и x87 на разные участки</strong> времени. Например, сначала выполняются все необходимые вычисления в формате с плавающей запятой, затем результат преобразуется и обрабатывается MMX-инструкциями (или наоборот)​. Одновременное чередование инструкций FPU и MMX нежелательно: во-первых, оно требует постоянного переключения контекста (что само по себе имеет накладные расходы по времени)​; во-вторых, повышает риск ошибки при неверной последовательности команд.<br>
<br>
<strong class='tag-b'><span class='tag-size' data-value='14' style='font-size:14pt;'>Инструкции FINIT и EMMS для очистки состояния</span></strong><br>
<br>
Чтобы <strong class='tag-b'>корректно переключиться между использованием MMX и FPU</strong>, архитектура x86 предоставляет специальные инструкции для сброса состояния:<br>
<br>
<ul class="tag-list"><li><strong class='tag-b'>EMMS</strong> (Empty MMX State) – инструкция, освобождающая MMX-регистры. Она помечает все восемь регистров FPU как пустые (устанавливает их тэги в 11b)​, тем самым сообщая сопроцессору, что данные в них более не используются в формате MMX. После выполнения <strong class='tag-b'>EMMS процессор «возвращается» в режим FPU</strong> – последующие операции с плавающей запятой будут нормально работать, не обнаруживая конфликтующих остатков данных MMX​. Обычно <strong class='tag-b'>EMMS</strong> вызывается сразу после блока MMX-инструкций, до возобновления каких-либо вычислений на FPU или вызова функций, которые могут использовать FPU.</li><li><strong class='tag-b'>FINIT</strong> (Floating-point INITialize) – инструкция, которая инициализирует FPU до известного начального состояния. Она сбрасывает регистровый стек FPU, очищает флаги состояния, переустанавливает управляющее слово и т.д. Практически, <strong class='tag-b'>FINIT</strong> также приведёт к очистке любых «мусорных» значений, остающихся от предыдущего использования FPU/MMX. <strong class='tag-b'>Важно</strong>: <strong class='tag-b'>FINIT</strong> не заменяет <strong class='tag-b'>EMMS</strong> в обычном коде, поскольку <strong class='tag-b'>FINIT</strong> не предназначен специально для MMX. Обычно её применяют при инициализации сопроцессора (например, при старте программы) или для экстренного сброса FPU при ошибке. В контексте MMX же, чаще достаточно выполнить <strong class='tag-b'>EMMS</strong>. Однако, если по каким-то причинам требуется <strong class='tag-b'>полностью сбросить и переинициализировать FPU после работы MMX</strong>, можно выполнить последовательность <strong class='tag-b'>EMMS</strong> (чтобы очистить тэги) и затем <strong class='tag-b'>FINIT</strong> (чтобы реинициализировать сопроцессор).</li></ul><br>
<strong class='tag-b'>Правильное чередование MMX и FPU</strong>: Всегда завершавайте блок MMX-кода инструкцией <strong class='tag-b'>EMMS</strong> перед возвратом к вещественным вычислениям. Если до этого на FPU выполнялись вычисления и важны его настройки (режим округления, флаги и т.д.), может потребоваться <strong class='tag-b'>FINIT</strong> или сохранение/восстановление состояния FPU. Но в большинстве случаев для переключения обратно на FPU достаточно выполнить <strong class='tag-b'>EMMS</strong>, после чего можно безопасно использовать инструкции x87​. Пренебрежение этой инструкцией рано или поздно приводит к сбоям: например, стандартная библиотека языка Си, обнаружив неочищенное MMX-состояние при попытке выполнить <strong class='tag-b'><span class="tag-font" data-value="Courier" style="font-family:Courier">printf</span></strong> с форматированием <strong class='tag-b'><span class="tag-font" data-value="Courier" style="font-family:Courier">%f</span></strong>, может аварийно завершить программу.<br>
<br>
<strong class='tag-b'><span class='tag-size' data-value='14' style='font-size:14pt;'>Производительность и современные альтернативы</span></strong><br>
<br>
Стоит отметить, что <strong class='tag-b'>переключение между режимами FPU и MMX влечёт за собой ощутимые накладные расходы</strong>. Выполнение <strong class='tag-b'>EMMS</strong>/<strong class='tag-b'>FINIT</strong> и связанная очистка тегов — сравнительно медленная операция​. По этой причине высокопроизводительное ПО старалось <strong class='tag-b'>группировать однородные вычисления</strong>: например, все MMX-операции выполнять подряд, отложив использование FPU до тех пор, пока это возможно​. В современных x86-64 системах проблема смешанного использования частично утратила актуальность: начиная с SSE2, <strong class='tag-b'>SIMD-расширения получили независимые регистровые файлы (XMM, YMM и т.д.)</strong>, не связанные с x87 FPU​. Это позволяет свободно сочетать векторные операции с плавающей запятой без необходимости сбрасывать состояние сопроцессора после каждой серии команд. Однако понимание устройства MMX и x87 важно при работе с наследуемым кодом и низкоуровневыми оптимизациями. <br>
<br>
<strong class='tag-b'>Вывод</strong>: Регистры MMX и x87 FPU фактически являются двумя представлениями одного и того же набора физических регистров​. Выполнение операций в одном режиме неизбежно воздействует на другой, поэтому <strong class='tag-b'>необходимо явно разграничивать использование MMX и FPU</strong>. Инструкция <strong class='tag-b'>EMMS</strong> служит основным инструментом для такого разграничения, освобождая регистры после MMX-вычислений, а <strong class='tag-b'>FINIT</strong> при необходимости возвращает сопроцессор в начальное состояние. Соблюдение этих правил позволяет избегать ошибок и эффективно использовать возможности процессора. <br>
<br>
<strong class='tag-b'>Основные моменты</strong>: MMX и x87 разделяют одни и те же регистры; смешанное использование без очистки приводит к конфликтам; после блока MMX-команд всегда нужно выполнять <strong class='tag-b'>EMMS</strong> (а при необходимости — <strong class='tag-b'>FINIT</strong>) перед возобновлением работы с FPU. Это гарантирует корректность результатов и стабильность работы приложения.​<br>
<br>
<strong class='tag-b'><span class='tag-size' data-value='14' style='font-size:14pt;'>Пример кода на fasm</span></strong><br>
<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">format PE64 console</div><div class="code_line">entry start</div><div class="code_line">&nbsp;</div><div class="code_line">include &#39;win64a.inc&#39;</div><div class="code_line">&nbsp;</div><div class="code_line">section &#39;.data&#39; data readable writeable</div><div class="code_line">&nbsp;&nbsp; &nbsp;fp_value dq 3.14 &nbsp;; Пример значения с плавающей точкой (double)</div><div class="code_line">&nbsp;&nbsp; &nbsp;mm_value dq 12345678h &nbsp;; Пример значения для MMX</div><div class="code_line">&nbsp;</div><div class="code_line">section &#39;.code&#39; code readable executable</div><div class="code_line">start:</div><div class="code_line">&nbsp;&nbsp; &nbsp;; Инициализация FPU</div><div class="code_line">&nbsp;&nbsp; &nbsp;finit &nbsp;; Инициализируем FPU (сбрасываем регистры и настройки)</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;; Загружаем значение в ST0</div><div class="code_line">&nbsp;&nbsp; &nbsp;fld qword [fp_value] &nbsp;; ST0 = 3.14</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;; Выполняем операции с ST0</div><div class="code_line">&nbsp;&nbsp; &nbsp;fadd st0, st0 &nbsp;; ST0 = ST0 + ST0 (3.14 + 3.14 = 6.28)</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;; Сохраняем ST0 в память, чтобы освободить регистр</div><div class="code_line">&nbsp;&nbsp; &nbsp;fstp qword [fp_value] &nbsp;; Сохраняем ST0 в память и освобождаем ST0</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;; Очистка состояния MMX перед использованием MMX-регистров</div><div class="code_line">&nbsp;&nbsp; &nbsp;emms &nbsp;; Очищаем состояние MMX (переводим FPU в обычный режим)</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;; Загружаем значение в MM0</div><div class="code_line">&nbsp;&nbsp; &nbsp;movq mm0, [mm_value] &nbsp;; MM0 = 12345678h</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;; Выполняем операции с MM0</div><div class="code_line">&nbsp;&nbsp; &nbsp;paddb mm0, mm0 &nbsp;; MM0 = MM0 + MM0 (по байтам)</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;; Сохраняем MM0 в память, чтобы освободить регистр</div><div class="code_line">&nbsp;&nbsp; &nbsp;movq [mm_value], mm0 &nbsp;; Сохраняем MM0 в память</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;; Очистка состояния MMX после использования MMX-регистров</div><div class="code_line">&nbsp;&nbsp; &nbsp;emms &nbsp;; Очищаем состояние MMX (переводим FPU в обычный режим)</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;; Восстанавливаем ST0 из памяти</div><div class="code_line">&nbsp;&nbsp; &nbsp;fld qword [fp_value] &nbsp;; ST0 = 6.28</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;; Выполняем еще операции с ST0</div><div class="code_line">&nbsp;&nbsp; &nbsp;fsqrt &nbsp;; ST0 = sqrt(ST0) (sqrt(6.28) ≈ 2.506)</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;; Сохраняем ST0 в память, чтобы освободить регистр</div><div class="code_line">&nbsp;&nbsp; &nbsp;fstp qword [fp_value] &nbsp;; Сохраняем ST0 в память и освобождаем ST0</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;; Очистка состояния MMX перед использованием MMX-регистров</div><div class="code_line">&nbsp;&nbsp; &nbsp;emms &nbsp;; Очищаем состояние MMX (переводим FPU в обычный режим)</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;; Восстанавливаем MM0 из памяти</div><div class="code_line">&nbsp;&nbsp; &nbsp;movq mm0, [mm_value] &nbsp;; MM0 = 12345678h + 12345678h (по байтам)</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;; Очистка состояния MMX после использования MMX-регистров</div><div class="code_line">&nbsp;&nbsp; &nbsp;emms &nbsp;; Очищаем состояние MMX (переводим FPU в обычный режим)</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;; Завершение программы</div><div class="code_line">&nbsp;&nbsp; &nbsp;invoke ExitProcess, 0</div><div class="code_line">&nbsp;</div><div class="code_line">section &#39;.idata&#39; import data readable writeable</div><div class="code_line">&nbsp;&nbsp; &nbsp;library kernel32, &#39;kernel32.dll&#39;</div><div class="code_line">&nbsp;&nbsp; &nbsp;import kernel32, ExitProcess, &#39;ExitProcess&#39;</div></ol></div></div></div></div>]]></description>
        <author>Majestio</author>
        <category>Assembler</category>
      </item>
	
      </channel>
      </rss>
	