Учебник Нортона/Соухэ под Win64

Тема в разделе "WASM.BOOKS и WASM.BLOGS", создана пользователем ormoulu, 30 ноя 2022.

  1. ormoulu

    ormoulu Well-Known Member

    Публикаций:
    0
    Регистрация:
    24 янв 2011
    Сообщения:
    1.170
    Внезапно у меня при перечитывании тов. Икзелиона проявилась давнишняя идея переписать легендарный том тов.Нортона и тов.Соухэ (или он все же Соча?) так, чтобы любое школоло могло начать втыкать непосредственно с азов, но не под Дос, а под Вин64. Ниже приблизительно как оно должно выглядеть. Жду ваших мнений, советов, рекомендаций, собственно нужно ли такое вообще в этой вселенной или ну его.
    Мнения целевой аудитории, т.е. самих школоло будут особо ценными.

    Эти статья - первая из серии, задуманной как адаптация классической (и легендарной) книги Нортона и Соухэ "Язык ассемблера для IBM PC". От прочих учебников по ассемблеру эта уже довольно древняя книга заметно отличается тем, что начинает обучение с азов, при этом не насыщена излишне скучной теорией и старается как можно раньше помочь читателю применить свои новые знания на практике.
    Целью статьи было в том числе дать возможность абсолютному новичку познакомиться с программированием на ассемблере уже не для MS-DOS, а для Windows x64. Однако не будет лишним, если у читателя уже имеются навыки работы с другими языками программирования.
    Для самостоятельного решения практических задач необходимо наличие компьютера с установленной ОС Windows. Предполагается использование Windows версии 10 или 11. Для установки необходимого ПО понадобится доступ в интернет.
    Статья ориентирована на читателя, знакомого с Windows и имеющего базовые навыки работы в командной строке. Пригодится также школьный курс математики.
    --------------------------------------
    Установка MASM64

    Для изучения языка ассемблера нам понадобится транслятор ассемблера. Это специальная программа, превращающая наш текстовый файл с кодом на ассемблере в исполняемый (executable) файл, то есть программу, которую может запустить операционная система Windows. Транслятор ассемблера от Microsoft называется MASM, или же, Microsoft Macro Assembler. Так как мы будем изучать ассемблер для 64-разрядной Windows, будем использовать MASM64.

    Транслятор MASM64 можно получить с набором компиляторов от Microsoft, идущим в комплекте с Microsoft Visual Studio. Компилятор - специальная программа для создания программ из "исходного кода", то есть, текстовых файлов. Компилятор ассемблера принято называть "транслятором" потому, что тексты программ на ассемблере максимально приближены к набору машинных кодов, который будет в итоговом исполняемом файле.

    Для целей данной статьи достаточно скачать набор компиляторов C++ для командной строки. Найдите утилиту для скачивания Build Tools for Visual Studio (на момент написания ее можно найти в интернете по адресу:
    https://visualstudio.microsoft.com/downloads/,
    Tools for Visual Studio -> Build Tools for Visual Studio 2022),
    скачайте и запустите. Для работы утилиты необходим доступ в интернет! Для установки набора компиляторов достаточно выбрать MSVC (Microsoft Visual C++) самой современной версии в списке индивидуальных компонентов.

    upload_2022-12-10_19-37-27.png

    После завершения установки в меню "Пуск" должны появиться ярлыки для запуска командной строки для создания различных конфигураций программ. Нам необходима конфигурация для 64-разрядных приложений. Для Visual Studio 2022 нужный ярлык может называться "x64 Native Tools Command Prompt for VS 2022". Возможно, в вашей системе он будет называться как-то еще.

    Запустите командную строку для сборки 64-разрядных приложений и наберите ml64.exe. Если все прошло успешно, вы получите сообщение о версии транслятора ассемблера.
    Код (DOS):
    1.  
    2. C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools>ml64.exe
    3. Microsoft (R) Macro Assembler (x64) Version 14.34.31935.0
    4. Copyright (C) Microsoft Corporation.  All rights reserved.
    5.  
    6. usage: ML64 [ options ] filelist [ /link linkoptions]
    7. Run "ML64 /help" or "ML64 /?" for more info
    8.  
    Создание тестового исполняемого файла

    Первая "программа", которую мы создадим при помощи MASM64, не будет настоящей программой. Мы соберем файл, который будет восприниматься операционной системой как исполняемый, и который мы сможем открыть в отладчике.
    Создайте директорию, в которой вы будете работать в дальнейшем. Можно использовать и уже существующую, например, рабочий стол. Смените в командной строке директорию на рабочую и создайте файл с расширением .asm. Можете придумать файлу любое имя, в нашем примере он будет называться test64.asm.

    upload_2022-12-10_19-43-45.png

    Добавьте в .asm файл следующий текст и сохраните (в рабочей папке):

    Код (ASM):
    1. option casemap:none
    2. public start
    3. .data
    4. .code
    5. start:
    6.     db 100h dup (090h)
    7. end
    Соберите исполняемый файл, выполнив в командной строке:

    Код (DOS):
    1. ml64 /c test64.asm
    2. link test64.obj /entry:start /SUBSYSTEM:WINDOWS
    3.  
    В вашей рабочей директории должен появиться файл с расширением .obj и исполняемый файл test64.exe. Не запускайте его пока. Эта программа неработоспособна, если вы попытаетесь ее запустить - скорее всего, увидите сообщение об ошибке. Но она пригодится нам для работы с отладчиком, программой, с которой мы познакомимся далее.

    Установка Windbg Preview

    Если вы решили заняться низкоуровневым программированием, как в целом любым программированием, не обойтись без отладчика. Классическим отладчиком от производителя ОС Windows, Microsoft, является Windbg (сокращение от Windows Debugger).

    С Windows понятно, но почему программа называется Debugger? "Bugs" (дословно "насекомые") в переводе со слэнга программистов означает "ошибки в программе". Используя специальную управляющую программу для пошагового запуска нашей программы и наблюдая за состоянием последней на каждом этапе, мы можем найти ошибки и исправить их. Этот процесс называется отладка ("debugging"), а программа для отладки - отладчик ("debugger").

    Итак, нам необходимо скачать и установить отладчик Windbg. На момент написания этих строк самую современную версию Windbg Preview можно установить через Microsoft Store ("магазин приложений Microsoft").

    Запустите Microsoft Store (например, найдите в меню "Пуск" либо выполните "ms-windows-store:home" в окне "Запуск"). В строке поиска магазина приложений наберите "windbg", выберите "Windbg Preview" и установите отладчик.
    Закройте Microsoft Store и запустите ваш только что установленный Windbg Preview (вы найдете его в меню "Пуск"). С помощью меню File->Launch executable (либо Ctrl+E) найдите и откройте test64.exe, который вы только что создали при помощи MASM64. Если вы корректно выполнили предыдущие шаги, то увидите, что Windbg успешно загрузил наш исполняемый файл.

    upload_2022-12-10_19-50-50.png

    --------------------------------------
    Начнем наше знакомство с низкоуровневым программированием с представления того, как компьютер считает.

    В повседневной деятельности мы привыкли к счету с применением десяти цифр 1,2,3 и так далее. Вследствие чисто технических особенностей компьютер применяет другой метод счета, в котором задействованы только две цифры 0 и 1. Например, до пяти он считает следующим образом: 1, 10, 11, 100, 101. Числа 10, 11, 100, 101 являются двоичными, то есть базирующимися на системе счисления, состоящей всего из двух цифр - единицы и нуля, в отличие от десяти цифр, соответствующих более привычной для нас десятичной системе. Таким образом, двоичное число 10 соответствует десятичному 2.

    Однако двоичные числа обладают существенным недостатком - выглядят они длинно и громоздко. Шестнадцатеричные числа - гораздо более компaктный спocoб записи двоичных чисел. В этой главе вы познакомитесь с двумя способами записи чисел: шестнадцатеричным и двоичным. Это поможет понять процесс счета в компьютере и способ хранения чисел - в битах, байтах и словах. Если вы уже имеете представление о двоичных и шестнадцатеричных числах, битах, байтах и словах, то вам достаточно ознакомиться лишь с итогом этой главы.

    Вернемся к Windbg

    Так как с шестнадцатеричными числами легче обращаться, чем с двоичными числами (по крайней мере, из-за длины), то мы начнем со знакомства с шестнадцатеричными числами, и будем использовать для этого отладчик Windbg. Установите Windbg и запустите его с нашей тестовой "программой" так, как это было описано ранее, если вы этого еще не сделали. Для вашего удобства, вы можете также закрыть все дочерние окна кроме "Command" ("окно команд") и очистить предыдущий вывод выбрав "Clear command history" в контекстном меню, которое открывается правым кликом по заголовку окна "Command".

    upload_2022-11-30_21-41-37.png

    Шестнадцатеричная арифметика

    Мы будем использовать команду Windbg, которая называется "Evaluate Expression" ("вычислить выражение"), а записывается как "?"(знак вопроса). Эта команда вычисляет выражение после знака "?" и в случае успеха записывает ответ в шестнадцатиричном виде, в разрядности используемой процессором. Убедитесь, что вы открыли исполняемый файл в отладчике и фокус находится в окне "Command", после чего наберите
    Код (Text):
    1. ? 3+2
    и нажмите "Ввод". Вы должны увидеть следующий текст:

    Код (Text):
    1. 0:000> ? 3+2
    2. Evaluate expression: 5 = 00000000`00000005
    Теперь попробуйте
    Код (Text):
    1. ? 3-2
    Код (Text):
    1. 0:000> ? 3-2
    2. Evaluate expression: 1 = 00000000`00000001
    Итак, результаты пока одинаковы для шестнадцатеричных и десятичных чисел: и для десятичной системы счисления 5 сумма 2 и 3, а 1 разность. Но в дальнейшем вы можете столкнуться с некоторыми сюрпризами.
    Например, что будет, если мы напечатаем "? 2 - 3", то есть вычесть из двух три, а не из трех два? Если мы попытаемся это сделать, то:

    Код (Text):
    1. 0:000> ? 2-3
    2. Evaluate expression: -1 = ffffffff`ffffffff
    Мы получили FFFFFFFFFFFFFFFF равным -1 для 2 - 3 (символ "`" в записи числа используется лишь для наглядности). Возможно, это выглядит странно, но FFFFFFFFFFFFFFFF - шестнадцатеричное число, соответствующее единице со знаком минус "-1".
    В дальнейшем мы вернемся к этой необычной -1. Но сначала давайте возьмем другие числа, чтобы увидеть, каким образом F может появиться в качестве числа.
    Попробуем сложить девять и один, что должно дать нам десятичное число 10:

    Код (Text):
    1. 0:000> ? 9+1
    2. Evaluate expression: 10 = 00000000`0000000a
    Десять равняется А? Да, это так: А - шестнадцатеричное число, соответствующее десяти. Так, а что если мы попробуем получить еще большее число, такое, например, как 15:

    Код (Text):
    1. 0:000> ? 9+6
    2. Evaluate expression: 15 = 00000000`0000000f
    Если вы попробуете исследовать остальные числа между десятью и пятнадцатью, то вы обнаружите всего 16 цифр от 0 до F (от 0 до 9 и от А до F). Название "шестнадцатеричные" произошло от числа 16. Цифры от 0 до 9 одинаковы и для шестнадцатеричной, и для десятичной системы счисления; шестнадцатеричные цифры от А до F соответствуют десятичным числам от 10 до 15.

    Код (Text):
    1.  
    2.   Decimal  Hex digit
    3.     0          0
    4.     1          1
    5.     2          2
    6.     3          3
    7.     4          4
    8.     5          5
    9.     6          6
    10.     7          7
    11.     8          8
    12.     9          9
    13.    10          A
    14.    11          B
    15.    12          C
    16.    13          D
    17.    14          E
    18.    15          F
    19.  
    Почему Windbg говорит на шестнадцатеричном языке? Скоро вы увидите, что мы можем записать 256 различных чисел с помощью двух шестнадцатеричных цифр. Как вы уже наверное подозреваете, 256 также имеет некоторое отношение к элементу, известному как байт, и байт играет главную роль в компьютерах и в этой статье. Вы найдете значительно большую информацию о байтах ближе к концу этой главы, но сейчас мы продолжим изучение шестнадцатеричных чисел, системы счисления, с которой любому низкоуровневому программисту приходится сталкиваться постоянно, и шестнадцатеричной математики.

    Перевод шестнадцатеричных чисел в десятичную форму

    До этого мы рассматривали шестнадцатеричные числа, состоящие из одной цифры. Теперь давайте посмотрим, как выглядят шестнадцатеричные числа большей длины и как переводить эти числа в десятичную форму.

    Как и с десятичными числами, мы получаем шестнадцатеричное число, состоящее из нескольких цифр, добавляя цифры слева. Предположим, например, что мы складываем число 1 и наибольшее десятичное число, состоящее из одной цифры, 9. В результате получается число, состоящее из двух цифр, 10 (десять). Что произойдет, если мы прибавим 1 к наибольшему шестнадцатеричному числу, состоящему из одной цифры, F? Мы опять получим 10.

    Ho подождите, 10 в шестнадцатеричной системе на самом деле 16, а не десять. Так может получиться небольшая путаница. Нам нужно как-то различать эти две десятки, поэтому, начиная с этого места, мы будем помещать букву "h" после каждого шестнадцатеричного числа. Таким образом, мы будем понимать, что 10h это шестнадцатеричное 16, а 10 это десятичное десять.

    Теперь мы подошли к вопросу том, как переводить числа из шестнадцатеричной в десятичную форму и обратно. Мы знаем, что 10h это 16, но как мы переведем большее шестнадцатеричное число, такое, например, как D3h, в десятичную форму без того, чтобы считать до D3h, начиная с 10h? Или как нам перевести десятичное число 173 в шестнадцатеричную форму?

    Мы можем положиться на помощь Windbg, так как Windbg понимает и десятичные числа. Но сейчас, ради обучения и тренировки, придется выполнять эти действия вручную, так что мы начнем с возвращения в знакомый мир десятичных чисел.

    Что означает число 276? В младшей школе мы узнали, что 276 состоит из двух сотен, семи десятков и шести единиц. Графически это можно представить следующим образом:
    Код (Text):
    1. 2   * 100 = 200
    2.  7  *  10 =  70
    3.   6 *   1 =   6
    4. ----------------
    5. 276       = 276
    Такое представление числа помогает нам визуально понять значение входящих в него цифр. Можем ли мы использовать такое представление при работе шестнадцатеричным числом? Конечно.

    Возьмем число D3h, которое мы упоминали ранее. D - это шестнадцатеричная цифра 13, и там 16 таких цифр (по аналогии с 10 для десятичного числа). Таким образом, D3h это тринадцать раз по шестнадцать и три единицы. Или, в графическом представлении:
    Код (Text):
    1. D    -->13 * 16 = 208
    2.  3   --> 3 *  1 = 3
    3. ----------------------
    4. D3h             = 211
    Когда мы рассматривали десятичное число 276, мы умножали цифры на 100, 10 и 1, а цифры шестнадцатеричного числа D3h мы умножили на 16 и 1. Если бы мы имели десятичное число из четырех цифр, мы бы умножали на 1000, 100, 10 и 1. Какие четыре числа нам использовать, имея шестнадцатеричное число из четырех цифр?

    Для десятичной системы счисления используются числа 1000, 100, 10 и 1 - степени числа 10:
    Код (Text):
    1. 10^3  = 1000
    2. 10^2  =  100
    3. 10^1  =   10
    4. 10^0  =    1
    Мы можем использовать тот же метод для шестнадцатеричных цифр, но со степенями 16, а не 10, и поэтому будем применять следующие четыре числа:
    Код (Text):
    1. 16^3 = 4096
    2. 16^2 =  256
    3. 16^1 =   16
    4. 16^0 =    1
    Переведем ЗАС8h в десятичную форму, используя четыре числа, которые мы только что вычислили:
    Код (Text):
    1. 3    -->  3 * 4096 = 12288
    2.  A   --> 10 *  256 =  2560
    3.   C  --> 12 *   16 =   192
    4.    8 -->  8 *    1 =     8
    5. ---------------------------
    6. 3AC8h              = 15048
    Вы можете проверить ответ при помощи Windbg:
    Код (Text):
    1. 0:000> ? 3AC8h
    2. Evaluate expression: 15048 = 00000000`00003ac8
    Теперь посмотрим, что произойдет, если мы сложим шестнадцатеричные числа, состоящие более чем из одной цифры. Для этого мы используем Windbg и числа 3А7h и 1EDh:
    Код (Text):
    1. 0:000> ? 3A7+1ED
    2. Evaluate expression: 1428 = 00000000`00000594
    Таким образом, мы видим, что ЗА7h + 1EDh = 594h. Вы можете проверить результаты, переведя эти числа в десятичную форму и выполнив сложение в десятичной форме; если вы отважны, выполните вычисления прямо в шестнадцатеричной форме.
    Код (Text):
    1.   1      1         1
    2.  2A7      F451      C
    3. +92A     +CB03     +D
    4. _____    ______    ___
    5. BD1     1BF54     19
    Код (Text):
    1.  1111       1 1
    2.  BCD8      BCD8
    3. +FAE9     + 509
    4. ______    ______
    5. 1B7C1      C1E1
    Примеры сложения шестнадцатеричных чисел

    Шестнадцатеричные числа большой разрядности

    Итак, шестнадцатеричная математика продолжается. Что произойдет, если мы попытаемся сложить очень большие шестнадцатеричные числа? Сложим 90000000`00000000 и A0000000`00000000:
    Код (Text):
    1. 0:000> ? 90000000`00000000 + A0000000`00000000
    2. Evaluate expression: 3458764513820540928 = 30000000`00000000
    Да, это неожиданный ответ. Почему Windbg вернул такой результат? Причина этого связана с единицей хранения и обработки информации, обозначаемой как QWORD ("quadword", "четверное слово"). Современный 64-разрядный процессор работает с четверными словами, а длина этих единиц такова, что они могут содержать не более шестнадцати шестнадцатеричных цифр.

    Более подробно о единицах хранения информации мы узнаем через несколько страниц, ну а сейчас запомните, что "Evaluate expression" может работать только с шестнадцатью шестнадцатеричными цифрами. Таким образом, если вы пытаетесь сложить два шестнадцатизначных шестнадцатеричных числа, например таких, как С0000000`00000000h и D0000000`00000000h (которые в сумме дадут 1`90000000`00000000h), то вы получите 90000000`00000000h:
    Код (Text):
    1. 0:000> ? C0000000`00000000 + D0000000`00000000
    2. Evaluate expression: -8070450532247928832 = 90000000`00000000
    Дело в том, что Windbg сохраняет только шестнадцать правых цифр ответа.

    Перевод десятичных чисел в шестнадцатеричную форму

    До этого мы рассматривали только перевод из шестнадцатеричной формы представления числа в десятичную. Теперь мы научимся переводить десятичные числа в шестнадцатеричные. Начнем изучение с того, как подобные действия выполняются вручную. Мы опять воспользуемся знаниями математики, полученными в младшей школе.

    Когда нас обучали делению, мы делили 9 на 2 и получали остаток 1. Остаток применяется при переводе числа из десятичной формы в шестнадцатеричную. Посмотрим, что произойдет, если мы будем последовательно делить десятичное число, на этот раз 493, на 10:
    Код (Text):
    1. 493 / 10 = 49 remainder 3......
    2.  49 / 10 = 4  remainder 9.... |
    3.   4 / 10 = 0  remainder 4.. | |
    4.                           4 9 3
    Цифры числа 493 появляются в виде остатка, расположенного в обратном порядке - начиная с крайней правой цифры (3).

    Ранее мы уже узнали, что для перевода шестнадцатеричного числа в десятичную форму потребовалось лишь заменить степени 10 степенями 16. Можем ли мы для того, чтобы перевести десятичное число в шестнадцатеричную форму, также разделить его на 16, а не на 10? Да, конечно, в действительности перевод из десятичной системы счисления в шестнадцатеричную производится именно таким образом.

    Например, найдем шестнадцатеричный эквивалент числа 493. Делим на 16, как показано ниже:
    Код (Text):
    1. 493 / 16 = 30 remainder 13 (Dh)......
    2.  30 / 16 =  1 remainder 14 (Eh).... |
    3.   1 / 16 =  0 remainder  1 (1h).. | |
    4. 493      =                      1 E D h
    Мы нашли, что 1EDh является шестнадцатеричным эквивалентом десятичного числа 493. Другими словами, делим на 16 и формируем результирующее шестнадцатеричное число из остатков. Вот и все.

    Отрицательные числа

    Если вы помните, у нас есть неразрешенная загадка в виде числа FFFFFFFF`FFFFFFFFh. Мы сказали, что FFFFFFFF`FFFFFFFFh фактически равно -1. Так ли это? Ведет ли себя FFFFFFFF`FFFFFFFFh действительно как отрицательное число?

    Пусть так, тогда если мы сложим FFFFFFFF`FFFFFFFFh (по нашей гипотезе -1) и 5, результат должен быть 4, так как 5-1=4. Произойдет ли это? Используя команду "?", получим:
    Код (Text):
    1. 0:000> ? FFFFFFFF`FFFFFFFF + 5
    2. Evaluate expression: 4 = 00000000`00000004
    Windbg, кажется, обращается с FFFFFFFF`FFFFFFFFh, как с -1. Но FFFFFFFF`FFFFFFFFh не всегда будет вести себя как -1 в программах, которые мы будем писать. Чтобы увидеть, почему это происходит, произведем сложение вручную.

    При сложении двух десятичных чисел мы часто выполняем перенос единицы в следующий столбец, как, например, в данном случае:
    Код (Text):
    1.  95
    2. +58
    3. ----
    4. 153
    Сложение двух шестнадцатеричных чисел производится аналогично. Например, сложение 3 и F дает нам 2 с переносом 1 в следующий столбец:
    Код (Text):
    1.  F
    2. +3
    3. ---
    4. 12h
    А теперь посмотрим, что произошло, когда мы сложили 5h и FFFFFFFF`FFFFFFFFh:
    Код (Text):
    1.    00000000`00000005
    2. +  FFFFFFFF`FFFFFFFF
    3. ---------------------
    4. 1`00000000`00000004h
    Так же как при Fh + 1h = 10h, происходит последовательный перенос единицы в крайнюю левую позицию, то есть, если мы игнорируем эту единицу, мы получаем правильный ответ для 5 - 1: именно, 4. Как ни странно это покажется, FFFFFFFF`FFFFFFFFh ведет себя как -1, когда мы игнорируем это переполнение. Оно названо переполнением, так как число теперь семнадцатизначное, а Windbg сохраняет только правые шестнадцать цифр.

    Переполнение - ошибка, или правильный ответ? И на тот, и на другой вопрос можно ответить "да". Не противоречат ли ответы между собой? Нет, так как эти числа могут рассматриваться двумя способами.

    Допустим, мы приняли FFFFFFFF`FFFFFFFFh за положительное число, и оно максимальное из тех, что мы можем записать с помощью шестнадцати шестнадцатеричных цифр. Мы говорим, что FFFFFFFF`FFFFFFFFh число без знака ("unsigned"). Оно действительно беззнаковое, так как мы только что определили все шестнадцатизначные числа как положительные. Сложение 5 и FFFFFFFF`FFFFFFFFh дает нам 1`00000000`00000004h: это единственный верный ответ. Следовательно, в случае чисел без знака переполнение - ошибка.

    С другой стороны, мы можем рассматривать FFFFFFFF`FFFFFFFFh как отрицательное число, как это делал Windbg, когда мы использовали команду "?", чтобы сложитьFFFFFFFF`FFFFFFFFh и 5. FFFFFFFF`FFFFFFFFh ведет себя как -1, пока мы игнорируем переполнение. Фактически, все числа от 80000000`00000000h до FFFFFFFF`FFFFFFFFh прекрасно ведут себя как отрицательные числа. Для чисел со знаком, как здесь и показано, переполнение не является ошибкой. Процессор может рассматривать числа как со знаком, так и без знака; выбирать вам. Инструкции для тех и других слегка различаются, и мы (возможно) рассмотрим эти различия в следующих главах. Сейчас же, до того, как вы сможете записать отрицательное число, соответствующее, скажем, числу 38h, нам необходимо разобраться со специфическим понятием бита и его связью с байтом, четверным словом и шестнадцатеричным числом.

    Биты, байты, четверные слова и двоичная система счисления

    Настало время углубиться в изучение процессора вашего компьютера - узнать об арифметических действиях, выполняемых процессором над двоичными числами. Процессор x64, при всей его мощности, слегка глуп. Он знает только две цифры: 0 и 1, так что любое число, которое он использует, должно быть сформировано из длинной строки нулей и единиц. Это и есть двоичная система счисления.

    Когда Windbg выводит на число в шестнадцатеричной форме, то при этом он переводит двоичные числа, обрабатываемые процессором, в шестнадцатеричную форму представления. Позже мы научимся это делать сами, но сначала нам надо побольше узнать собственно о двоичных числах.

    Давайте возьмем двоичное число 1011b ("b", сокращение от "binary" - двоичный, признак двоичного числа). Это число соответствует десятичному 11 и шестнадцатеричному Bh. Чтобы увидеть, почему это так, умножим цифры числа 1011b на основу системы счисления, 2.

    Степени числа 2:
    Код (Text):
    1. 2^3   = 8
    2. 2^2   = 4
    3. 2^1   = 2
    4. 2^0   = 1
    Поэтому:
    Код (Text):
    1. 1    * 8 =  8
    2. 0   * 4 =  0
    3.   1  * 2 =  2
    4.    1 * 1 =  1
    5. ------------------
    6. 1011b    = 11 или Bh
    Аналогично, 1111b это Fh, или 15. И 1111b является наибольшим беззнаковым четырехзначным двоичным числом, которое мы можем записать, в то время как 0000b - наименьшее. Таким образом, с помощью четырех двоичных цифр мы можем записать 16 различных чисел. Имеется также 16 шестнадцатеричных цифр, так что мы можем писать одну шестнадцатеричную цифру вместо каждых четырех двоичных цифр.

    Двузначное шестнадцатеричное число, такое как 4Сh, может быть записано как 0100 1100b. Оно состоит из восьми цифр, которые мы разделили на группы по четыре для простоты чтения. Каждая из этих двоичных цифр называется бит, как что число 0100 1100b, или 4Ch, имеет длину восемь бит.

    Часто бывает удобно нумеровать каждый из битов длинной строки, начиная с самого крайнего справа бита, который имеет номер 0. Так, например, в числе 10b бит, в котором записана 1, имеет номер 1; а крайний слева бит в числе 1011b - номер 3. Нумерация битов таким способом упрощает разговор о каждом конкретном бите.
    Код (Text):
    1. Binary  Decimal  Hexadecimal
    2. 0000      0          0
    3. 0001      1          1
    4. 0010      2          2
    5. 0011      3          3
    6. 0100      4          4
    7. 0101      5          5
    8. 0110      6          6
    9. 0111      7          7
    10. 1000      8          8
    11. 1001      9          9
    12. 1010     10          A
    13. 1011     11          B
    14. 1100     12          C
    15. 1101     13          D
    16. 1110     14          E
    17. 1111     15          F
    Двоичные, десятичные и шестнадцатеричные числа от 0 до F

    Одна двоичная цифра это бит, а группа из восьми двоичных цифр называется байт. Мы будем часто использовать эти термины, так как биты и байты являются фундаментальными понятиями для любого процессора.

    upload_2022-12-16_21-48-53.png
    Биты и байты

    В программировании группа из 16 двоичных цифр (битов), или 2 байта, называется WORD (слово), 32 двоичных цифры, то есть 4 байта, это DWORD ("double word", двойное слово), а 64 двоичных цифры (бита) составляют QWORD ("quad word", или четверное слово).

    Как вы вероятно уже догадались, современные процессоры называются 64-разрядными, или же 64-битными потому, что единицей обработки и хранения для них является четверное слово, то есть 64 бита (64 разряда двоичного числа).

    Теперь мы видим, почему шестнадцатеричная система счисления удобна; две шестнадцатеричные цифры помещаются точно в один байт (четыре бита на одну цифру), а байты составляют более крупные единицы информации. Мы не можем сказать то же самое о десятичных числах. Если мы попробуем поместить два десятичных числа в один байт, мы не сможем записать числа, большие чем 99, так что мы потеряем значения от 100 до 255 - более чем половину чисел, которые может содержать байт. А если мы будем использовать для этой же цели три десятичных цифры, то нам придется игнорировать более половины трехзначных десятичных чисел, так как числа от 256 до 999 не могут поместиться в один байт.

     
    GRAFik, DrochNaNoch и M0rg0t нравится это.
  2. q2e74

    q2e74 Active Member

    Публикаций:
    0
    Регистрация:
    18 окт 2018
    Сообщения:
    867
    я бы пошел другим путём. Разница между программой (сорс-кодом) и исполняемым файлом бы на пальцах объяснил. Потом связь заголовка и тела. И сделал бы большой файл из нопов. Потом открыл бы чем-то типа ольги, и вписывал бы команды там, объясняя по ходу дела, что мы можем увидеть.Потом бы структуры си и прыжки по адресам структуры массива стуктур. Потом бы загрузчики разные и файловая система. Куему+гидра(где дебаг а где статика решал бы по ситуации). И всё было бы наглядно. А с модулярно арифметики начинать, сперва пусть просто байты увидят, а потом спросят: "а это че ваще?". Тогда и ответ зайдет. А так сразу имхо не в коня корм.
     
  3. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    3.466
    M0rg0t нравится это.
  4. ormoulu

    ormoulu Well-Known Member

    Публикаций:
    0
    Регистрация:
    24 янв 2011
    Сообщения:
    1.170
    Ну хитрый план был единственный и неповторимый - переписать первые главы "Ассемблер для IBM PC". Оно же в принципе идет за оглавление.

    Вот с названием надо подумать. Что-нибудь типа "ассемблер с нуля для юных кулхацкеров вообще не напрягаясь. 10 бесплатных шагов с иллюстрациями". Хотя кулхацкер это что-то на старперском. "успешных этичных хакеров", как-то так.
     
  5. ormoulu

    ormoulu Well-Known Member

    Публикаций:
    0
    Регистрация:
    24 янв 2011
    Сообщения:
    1.170
    Дос на виндовс 64, дебаг на виндбг, вывод на экран через прерывания на формирование строки в памяти, про сами прерывания/сискол как обращение к ос рассказать в теории + отладочное прерывание на практике. Винапи после вызова процедур, до этого все смотреть в отладчике.
     
  6. ormoulu

    ormoulu Well-Known Member

    Публикаций:
    0
    Регистрация:
    24 янв 2011
    Сообщения:
    1.170
    Не думаю что можно заранее точно определить число глав и не думаю что это важно.
    Примерный охват - где взять и как запустить отладчик, арифметика, регистры, строки, процедуры, стэк, адресное пространство, атрибуты секций, изоляция процесса - то что в большинстве туториалов по x64 сразу "подразумевается".

    Помощь только если с вёрсткой потом потребуется. Главный вопрос есть ли смысл вообще.
     
  7. ormoulu

    ormoulu Well-Known Member

    Публикаций:
    0
    Регистрация:
    24 янв 2011
    Сообщения:
    1.170
    Ну, я все мнения читаю и учитываю. Пока вроде бы в основном было "никому не надо" и "я бы сделал по-другому".
     
  8. M0rg0t

    M0rg0t Well-Known Member

    Публикаций:
    0
    Регистрация:
    18 окт 2010
    Сообщения:
    1.550
    Ваши статьи много кому пригодились. Очень хорошие туториалы, например про IPC. Что мало коментов - ну люди тут не могли регится, многие просто читают, да и что писать "круто, +5".
    мне лично все супер.
     
    DrochNaNoch, q2e74 и Mikl___ нравится это.
  9. q2e74

    q2e74 Active Member

    Публикаций:
    0
    Регистрация:
    18 окт 2018
    Сообщения:
    867
    Mikl___, у Вас действительно хорошие тексты, и их очень приятно и полезно читать.
     
    Mikl___ нравится это.
  10. DrochNaNoch

    DrochNaNoch New Member

    Публикаций:
    0
    Регистрация:
    11 ноя 2022
    Сообщения:
    4
    Пишите дальше, хорошо получается. Картинок много и ссылки рабочие.
    Предполагаемый учебник посвящен Win64 и было бы отлично, если выводилось простенькое окошко с результатом. Объяснять все инструкции с выводом графики в первых главах конечно же никому не нужно. Школоло, включая меня, точно понравится, что можно без лишней нервотрепки вывести "окошко" и посмотреть в отладчике, как оно все внутри.

    Далее, добавлять потихоньку инструкции процессора.

    З.Ы.:
    Шикарный термин "обезнасекомливание")
     
    ormoulu нравится это.
  11. ormoulu

    ormoulu Well-Known Member

    Публикаций:
    0
    Регистрация:
    24 янв 2011
    Сообщения:
    1.170
    Большая проблема изучения ассемблера в Windows в том, что для самого простенького окошка нужно изучить и понять гораздо больше чем в DOSе. Это скорее всего основная причина почему асм до сих пор учат на допотопных инструментах. Поэтому, увы, первые n глав будут в отладчике.
    --- Сообщение объединено, 15 дек 2022 ---
    Можно было бы предположить, что первый пост вы не прочитали, но с учетом вашего реноме я думаю, что "найти самый правильный компиллятор для MASMx64" вашей целью и не являлось.
     
    DrochNaNoch нравится это.
  12. GRAFik

    GRAFik Active Member

    Публикаций:
    0
    Регистрация:
    14 мар 2020
    Сообщения:
    261
    Ладно, ormoulu, не буду я с вами спорить - делайте как хотите. Можете хоть с луны MASMx64(ML64) ставить, но для нормальных людей, я бы вам посоветовал дать ссылку от Mikl___'а ( https://wasm.in/threads/masm-64-sborka.32766/ ) и не вводить людей в заблуждение. Без установки студии - ни о каком ML64 даже и не мечтайте, а VS будет устанавливаться часа 2-3 если повезет, ну и сколько она "сожрет" места на HD вы и без меня скорее всего слышали и знаете. Начинаюшие школьники только и мечтают, чтобы ради ассемблера ML64 - 2 или 3 часа сидеть с установкой VS.

    Поэтому, я вам и посоветовал давайте придем к какому-то общему знаменателю и может сделать что-то подобное, как у этого преподавателя из Украины ( http://blogs.kpi.kharkov.ua/v2/asm/soft/ ).

    P.S. И прежде чем рассуждать о реноме другого человека, нужно о своем реноме подумать. Вы же все-таки не Билл Гейтс не КК и не Ильфак. Скромнее нужно быть, ormoulu, и школьники к вам потянутся.
     
  13. ormoulu

    ormoulu Well-Known Member

    Публикаций:
    0
    Регистрация:
    24 янв 2011
    Сообщения:
    1.170
    FYI, установка Build Tools for Visual Studio/MSVC занимает четыре минуты с гигабитным интернетом. Жрёт оно конечно аж почти три гига места, но надеюсь что те для кого это проблема, смогут эту проблему решить одним из многочисленных методов решения.
     
  14. GRAFik

    GRAFik Active Member

    Публикаций:
    0
    Регистрация:
    14 мар 2020
    Сообщения:
    261
    ormoulu, а что если Mikl___'а попросить выложить свой MASMx64 на какой-нибудь файлообменник и у людей будет выбор. Кому нужна VS будут ее себе ставить, а кому студия не к спеху, у того будет вариант быстрой и компактной установки MASMx64. Батничек быстренько запустил и вуаля - ASM превратился в EXE. Мы ведь ничего продавать не будем, а чисто для обучения студентов и школьников. Неужели нас за какой-то MASMx64 в тюрьму посадит Билл Гейтс? Это ведь, даже не студия, а какая-то жалкая "пылинка" от нее. :) По-моему, никто не обратит на это внимания.
     
  15. ormoulu

    ormoulu Well-Known Member

    Публикаций:
    0
    Регистрация:
    24 янв 2011
    Сообщения:
    1.170

    Дополнительный код - особый тип отрицательного числа


    Теперь мы готовы к более глубокому изучению отрицательных чисел. Мы говорили, что в том случае, если мы игнорируем переполнение, то все числа с 80000000`00000000h по FFFFFFFF`FFFFFFFFh ведут себя как отрицательные. Проще всего опознать отрицательные числа, записав их в двоичном виде:
    Положительные числа:
    Код (Text):
    1.   00000000`00000000h    0000 0000 ... 0000 0000b
    2.    *                     *
    3.    *                     *
    4.    *                     *
    5.   7FFFFFFF`FFFFFFFFh    0111 1111 ... 1111 1111b
    Отрицательные числа:
    Код (Text):
    1.   80000000`00000000h    1000 0000 ... 0000 0000b
    2.    *                     *
    3.    *                     *
    4.    *                     *
    5.   FFFFFFFF`FFFFFFFFh    1111 1111 ... 1111 1111b
    В двоичной форме записи у всех положительных чисел крайний левый бит (бит номер 63) всегда равен 0, а для отрицательных 1. Эта разница и является тем признаком, по которому процессор распознает отрицательные или положительные числа: при обработке чисел, он учитывает для каждого числа бит с максимальным порядковым номером. Этот бит также называется "старшим" или "знаковым". Если мы используем в нашей программе инструкции для чисел без знака, то процессор будет игнорировать знаковый бит.

    Отрицательные числа в таком представлении известны как дополнительный код (или двоичное дополнение) положительных чисел. Почему дополнение? Потому, что переход от положительного числа, например такого как 3C8h, к его дополнительному коду - это процесс из двух этапов, первый из которых - переход от числа к его дополнению.

    Мы почти не будем применять отрицательные числа, но произведем этот переход для того, чтобы вы увидели, как процессор делает числа отрицательными. Метод перевода может показаться вам немного странным, но давайте посмотрим, как это делается.

    Чтобы найти дополнительный код любого числа, надо сначала записать число в двоичной форме, игнорируя знак. Например, 4Ch становится 0000 0000 0000 0000 ... 0000 0000 0100 1100b.

    Чтобы сделать это число отрицательным, сначала инвертируем (переворачиваем) все нули и единицы. Этот процесс инвертирования называется дополнением, и взяв дополнение от 4Ch, мы найдем, что:
    Код (Text):
    1. 0000 0000 0000 0000 ... 0000 0000 0100 1100
    становится:
    Код (Text):
    1. 1111 1111 1111 1111 ... 1111 1111 1011 0011
    на втором этапе преобразования к дополнению добавляется 1b:
    Код (Text):
    1.   1111 1111 1111 1111 ... 1111 1111 1011 0011
    2.  +                                          1
    3. ----------------------------------------------
    4.   1111 1111 1111 1111 ... 1111 1111 1011 0100
    5.  
    6.            -4Ch = FFFFFFFF`FFFFFFB4h
    Результат, который мы получили, соответствует вычитанию 4Ch из 0h.

    При желании вы можете сложить FFFFFFFF`FFFFFFB4h и 4Ch вручную, и удостовериться, что ответ равен 1`00000000`00000000h. Из нашего более раннего обсуждения вы знаете, что эту единицу необходимо игнорировать, чтобы получить 0 (4Ch + (-4Ch) = 0), при выполнении сложения в дополнительном коде.

    Итог

    Эта статья явилась довольно энергичным вступлением в мир шестнадцатеричных и двоичных чисел. В дальнейшем мы медленно и осторожно двинемся дальше, а теперь давайте вдохнем глоток свежего воздуха и еще раз осмыслим то, что мы узнали.

    Мы начали со встречи с программой Windbg. Продолжив изучать ассемблер, мы с Windbg станем близкими друзьями. Windbg станет нашим проводником в мир машинных кодов процессора, а для того чтобы лучше понимать процессор, мы начали нашу дружбу с изучения новой системы счисления - шестнадцатеричной.

    Изучая шестнадцатеричные числа, вы также узнали, как переводить десятичные числа в шестнадцатеричные и обратно. После того как мы освоили основные понятия шестнадцатеричной системы, мы смогли обратить свой взор на биты, байты, четверные слова, с важными свойствами которых вы скоро столкнетесь при исследовании работы микропроцессора и программирования на языке ассемблера.

    Затем мы занялись изучением отрицательных шестнадцатеричных чисел - дополнительного кода чисел. Они привели нас к числам со знаком и без знака, где мы столкнулись с переполнением двух типов: когда переполнение дает правильный ответ (сложение двух чисел со знаком); и когда переполнение приводит к неправильному ответу (сложение двух чисел без знака).

    Пользу от этой учебы вы в полной мере прочувствуете в дальнейшем, в которых Windbg будет действовать как интерпретатор между нами и процессором. Следующая глава будет посвящена изучению самого процессора. Мы опять положимся на Windbg, и будем при общении с процессором использовать шестнадцатеричные числа, предпочитая их двоичным. Мы также узнаем о регистрах процессора - устройствах, в которых он хранит числа, и через какое-то время будем готовы к тому, чтобы написать настоящую программу. Мы также узнаем о том, как процессор выполняет свои математические операции; позже мы сможем написать программу, которая будет переводить двоичные числа в десятичные.
     
    sniper, DrochNaNoch и Mikl___ нравится это.
  16. R81...

    R81... Member

    Публикаций:
    0
    Регистрация:
    1 фев 2020
    Сообщения:
    87
  17. ormoulu

    ormoulu Well-Known Member

    Публикаций:
    0
    Регистрация:
    24 янв 2011
    Сообщения:
    1.170
    Думаю при описании каждой новой инструкции есть смысл давать ссылку на документацию по опкоду, чего в книге по понятным причинам сделать было нельзя.

    Внимани, вопрос: что из интернет-ресурсов есть наиболее авторитетный и долгоиграющий источник по опкодам x64? В том плане чтобы ссылка в ближайшее время не оказалась дохлой, и был минимальный шанс фактических ошибок.
     
  18. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    3.466
    ormoulu,
    "AMD64 Architecture Programmer’s Manual Volumes 1–5" в ресурсах форума для вас уже не достаточно авторитетный источник? Или ссылка "битая"? :crazy:
     
  19. ormoulu

    ormoulu Well-Known Member

    Публикаций:
    0
    Регистрация:
    24 янв 2011
    Сообщения:
    1.170
    Ну я во-первых даже не в курсе что оно там есть, список ресурсов наизусть не знаю и вообще в основном пофлудить в хипе захожу :grin:
    Во-вторых, незалогиненому пользователю ресурсы не все видны. Т.е. надо ссылаться на сферический справочник AMD в вакууме pdf, указывая номер раздела который может еще и не статичный. А хотелось бы для конкретной инструкции давать ссылку на страницу вида
    Код (Text):
    1. 88  /r   MOV r/m8,r8       2/2           Move byte register to r/m byte
    2. 89  /r   MOV r/m16,r16     2/2           Move word register to r/m word
    3. 89  /r   MOV r/m32,r32     2/2           Move dword register to r/m dword
    4. 8A  /r   MOV r8,r/m8       2/4           Move r/m byte to byte register
    5. 8B  /r   MOV r16,r/m16     2/4           Move r/m word to word register
    6. 8B  /r   MOV r32,r/m32     2/4           Move r/m dword to dword register
    7. blablabla...
    В третьих, почему именно AMD а не Intel например?
     
  20. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    3.466
    ormoulu,
    за некоторые ресурсы можно и получить по хитрой рыжей морде потому и не видны :)
     
    q2e74 нравится это.