асм, дизасм, принцип работы процов на определенном уровне.

Discussion in '"Железо"' started by Cthulchu, 5 Jan 2009.

  1. Cthulchu

    Cthulchu Elder - Старейшина

    Joined:
    22 Nov 2007
    Messages:
    405
    Likes Received:
    722
    Reputations:
    85
    Машинный код

    Машинный код (также употребляются термины собственные коды, или платформенно-ориентированные коды, или родной код, или “нативный” код — от англ. native code) — система команд (язык) конкретной вычислительной машины (машинный язык), который интерпретируется непосредственно микропроцессором или микропрограммами данной вычислительной машины.

    Каждая модель процессора имеет свой собственный машинный язык, хотя во многих моделях эти наборы команд сильно перекрываются. Говорят, что процессор A совместим с процессором B, если процессор A полностью «понимает» машинный код процессора B. Если процессор A знает несколько команд, которых не понимает процессор B, то B несовместим с A.

    «Слова» машинного языка называются машинными инструкциями. Каждая из них описывает элементарное действие, выполняемое процессором, такое как «переслать байт из памяти в регистр». Программа — это просто длинный список инструкций, выполняемых процессором. Раньше процессоры просто выполняли инструкции одну за другой, но новые суперскалярные процессоры способны выполнять несколько инструкций за раз. Прямой поток выполнения команд может быть изменён инструкцией перехода, которая переносит выполнение на инструкцию с заданным адресом. Инструкция перехода может быть условной, выполняющей переход только при соблюдении некоторого условия.

    АСМ

    Ассемблер (от англ. assembler — рабочий-сборщик) — компьютерная программа, компилятор исходного текста программы написанной на языке ассемблера, в программу на машинном коде.

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

    Ассемблирование может быть не первым и не последним этапом на пути получения исполняемого модуля программы. Так многие (да почти-почти все) компиляторы с языков программирования высокого уровня выдают результат в виде программы на языке ассемблера, которую в дальнейшем обрабатывает ассемблер. Так же, результатом ассемблирования может быть не исполняемый, а объектный модуль, содержащий разрозненные и непривязанные друг к другу кусочки машинного кода и данных программы, из которого в дальнейшем может быть скомпонован исполняемый модуль, с помощью программы-компоновщика (или «линкера»).

    Ассемблирование и компилирование

    Процесс трансляции программы на языке ассемблера в объектный код принято называть ассемблированием. В отличие от компилирования, ассемблирование — более или менее однозначный и обратимый процесс. В языке ассемблера каждой мнемонике соответветствует одна машинная инструкция, в то время как в языках программирования высокого уровня за каждым выражением может скрываться большое количество различных инструкций {Собственно, отседова очевиден принцип селекции языков на низкие и высокие уровни}. В принципе, это деление достаточно условно, поэтому иногда трансляцию ассемблерных программ также называют компиляцией.

    Дизассемблер — транслятор, преобразующий машинный код в текст программы на языке ассемблера.

    По режиму работы с пользователем делятся на
    Автоматические
    Интерактивные

    Примером автоматических дизассемблеров может служить Sourcer. Такие дизассемблеры генерируют готовый листинг, который можно затем править в текстовом редакторе. Пример интерактивного — IDA. Он позволяет изменять правила дизассемблирования, весьма удобный инструмент для исследования программ.

    Чаще всего дизассемблер используют для анализа программы (или ее части), исходный текст которой неизвестен — с целью модификации, копирования или взлома. Реже — для поиска ошибок (багов) в программах и компиляторах, а также для анализа оптимизации создаваемых компилятором машинного кода.
    {Да, дизассемблируя прогу, можно понять принцип работы этой проги и переписать ее, но это требует досконального знания ргистров процессоров и, к тому же, это на столько трудоемко и рутинно, что этим только ваши трояны и разгребать, к примеру, экзешник, который будет загружать себя в память и выгружать, после чего закрываться - будет в дизассемблере занимать несколько страничек кода асма, тогда как в оригинале он может занимать около страницы кода на асме и пару строк на Си}

    Обычно используется параллельно с отладчиком.


    Регистр процессора — сверхбыстрая память внутри процессора, предназначенная прежде всего для хранения промежуточных результатов вычисления (регистр общего назначения/регистр данных) или содержащая данные, необходимые для работы процессора — смещения базовых таблиц, уровни доступа и т. д. (специальные регистры).

    {регистры хранятся в кешэ первого лэвела}

    Доступ к значениям, хранящимся в регистрах, как правило, в несколько раз быстрее, чем доступ к ячейкам оперативной памяти (даже если кеш-память содержит нужные данные), но объём оперативной памяти намного превосходит суммарный объём регистров (объём среднего модуля оперативной памяти сегодня составляет 1 Гб — 4 Гб, суммарная «ёмкость» регистров общего назначения/данных для процессора Intel 80x86 16 битов * 4 = 64 бита (8 байт)).

    Шины


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

    На материнской плате шина может также состоять из множества параллельно идущих через всех потребителей данных проводников (например в архитектуре IBM PC).

    Основной характеристикой шины данных является её ширина в битах. Ширина шины данных определяет количество информации, которое можно передать за один такт.

    Шина адреса — шина, используемая центральным процессором или устройствами, способными инициировать сеансы DMA, для указания физического адреса слова ОЗУ (или начала блока слов), к которому устройство желает обратиться для проведения операции чтения или записи.

    Основной характеристикой шины адреса является её ширина в битах. Ширина шины адреса определяет объём адресуемой памяти. Например, если ширина адресной шины составляет 16 бит, и размер слова памяти равен одному байту (минимальный адресуемый объём данных), то объём памяти, который можно адресовать, составляет 216 = 65536 байтов (64 КБ).

    Если рассматривать структурную схему микро-ЭВМ, то адресная шина активизирует работу всех внешних устройств по команде, которая поступает с микропроцессора.

    По шине адреса передается адрес участвующих в обмене элементов памяти (поскольку данные передаются машинными словами, а один ЭП (Элемент Памяти) может воспринять только один бит информации, блок элементов памяти состоит из n матриц ЭП, где n - количество разрядов в машинном слове). Максимальная емкость памяти определяется количеством линий в шине адреса системной магистрали: если количество линий обозначить от, то емкость памяти (т.е. количество элементов памяти, имеющих уникальные адреса) определяется как 2m. Так, в IBM PC XT шина адреса СМ содержит 20 линий (20-битная адресация). Поэтому максимальный объем ОП в этих машинах равен 220 = 1 Мбайт. В IBM PC AT (с микропроцессором i80286) СМ содержит 24 линии (24-битная адресация), поэтому объем ОП может быть увеличен до 16 Мбайт. Начиная с МП i80386, шина адреса содержит 32 линии. Максимальный объем ОП увеличился до 2^32= 4Гб (32х битная адресация). Как было сказано в какой-то из античатовских статей, - при 64-битной адресации кол-во ОЗУ (ОП) будет 2^64.
    {Естественно, максимальной оперативка на практике у вас не будет, так как часть адресной шины идет на адресацию PCI порты, BIOS, видео память и прочие «мелочи». Заметьте, что адресация графической памяти идет аналогично адресации оперативки, из чего следует, что зная, сколько у человека памяти «не показывается» из-за проблем с адресной шиной, - можно сказать сколько у него видео памяти.}
    {Ядро оси проводит синхронизацию с адресной шиной и шиной данных, именно по этому, при использовании 64-битной адрессации на шине адреса, оптимальным действием есть установка 64-битной оси. В принципе, это не обязательно, но могут возникнуть некритические но неприятные траблы, о которых все уже догадались.}

    Прямой доступ к памяти (англ. Direct Memory Access, DMA) — режим обмена данными между устройствами или же между устройством и основной памятью (RAM), без участия Центрального Процессора. В результате скорость передачи увеличивается, так как данные не пересылаются в ЦП и обратно.

    Кроме того, данные пересылаются сразу для многих слов, расположенных по подряд идущим адресам, что позволяет использование т.н. "взрывного" (burst) режима работы шины - 1 цикл адреса и следующие за ним многочисленные циклы данных. Аналогичная оптимизация работы ЦП с памятью крайне затруднена.

    В оригинальной архитектуре IBM PC был возможен лишь при наличии аппаратного DMA-контроллера (обнозначаемого номером 8237).

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

    ЦП программирует контроллер DMA, устанавливая его регистры. Затем процессор даёт команду устройству (например, диску) прочитать данные во внутренний буфер. DMA-контроллер начинает работу, посылая устройству запрос чтения (при этом устройство даже не знает, пришёл ли запрос от процессора или от контроллера DMA). Адрес памяти уже находится на адресной шине, так что устройство знает, куда следует переслать следующее слово из своего внутреннего буфера. Когда запись закончена, устройство посылает сигнал подтверждения контроллеру DMA. Затем контроллер увеличивает используемый адрес памяти и уменьшает значение своего счётчика байтов. После чего запрос чтения повторяется, пока значение счётчика не станет равно нулю. По завершении цикла копирования устройство инициирует прерывание процессора, означающее завершение переноса данных. Контроллер может быть многоканальным, способным параллельно выполнять несколько операций.

    Многозадачность

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

    Свойства многозадачной среды

    Примитивные многозадачные среды обеспечивают чистое «разделение ресурсов», когда за каждой задачей закрепляется определённый участок памяти, и задача активизируется в строго определённые интервалы времени.

    Более развитые многозадачные системы проводят распределение ресурсов динамически, когда задача стартует в памяти или покидает память в зависимости от её приоритета и от стратегии системы. Такая многозадачная среда обладает следующими особенностями:
    Каждая задача имеет свой приоритет, в соответствии с которым получает процессорное время и память
    Система организует очереди задач так, чтобы все задачи получили ресурсы, в зависимости от приоритетов и стратегии системы
    Cистема организует обработку прерываний, по которым задачи могут активироваться, деактивироваться и удаляться
    По окончании положенного кванта времени ядро временно переводит задачу из состояния выполнения в состояние готовности, отдавая ресурсы другим задачам. При нехватке памяти страницы невыполняющихся задач могут быть вытеснены на диск (своппинг), а потом через определённое системой время, восстанавливаться в памяти
    Система обеспечивает защиту адресного пространства задачи от несанкционированного вмешательства других задач
    Система обеспечивает защиту адресного пространства своего ядра от несанкционированного вмешательства задач
    Система распознаёт сбои и зависания отдельных задач и прекращает их
    Система решает конфликты доступа к ресурсам и устройствам, не допуская тупиковых ситуаций общего зависания от ожидания заблокированных ресурсов
    Система гарантирует каждой задаче, что рано или поздно она будет активирована
    Система обрабатывает запросы реального времени
    Система обеспечивает коммуникацию между процессами


    Трудности реализации многозадачной среды

    Основной трудностью реализации многозадачной среды является её надёжность, выраженная в защите памяти, обработке сбоев и прерываний, предохранении от зависаний и тупиковых ситуаций. {должен заметить, что таких вот проблем - намного больше, чем кажется, это каждый поток нужно изолировать, на что тратится лишняя производительность проца при значительных нагрузках (когда озу заполняется, начинает кушаться своп а потом, если не эррор, то очень жуткие тормоза) и все это ради юзабельности интерфейсов.}

    Кроме надёжности, многозадачная среда должна быть эффективной. Затраты ресурсов на её поддержание не должны: мешать процессам проходить, замедлять их работу, резко ограничивать память.
    {ну, вот, собственно...}

    Типы псевдопараллельной многозадачности

    Невытесняющая многозадачность

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

    Cовместная или кооперативная многозадачность


    Тип многозадачности, при котором следующая задача выполняется только после того, как текущая задача явно объявит себя готовой отдать процессорное время другим задачам. Как частный случай, такое объявление подразумевается при попытке захвата уже занятого объекта mutex (ядро Linux), а также при ожидании поступления следующего сообщения от подсистемы пользовательского интерфейса (Windows версий до 3.x включительно, а также 16битные приложения в Windows 95/98/Me).
    {по сути, выполняем только текущую, пока она не начнет наглеть ;)}

    Кооперативную многозадачность можно назвать многозадачностью “второй ступени” поскольку она использует более передовые методы, чем простое переключение задач, реализованное многими известными программами (например, МS-DOS shell из МS-DOS 5.0 при простом переключении активная программа получает все процессорное время, а фоновые приложения полностью замораживаются. При кооперативной многозадачности приложение может захватить фактически столько процессорного времени, сколько оно считает нужным. Все приложения делят процессорное время, периодически передавая управление следующей задаче.
    {сложность состоит только в алгоритме определения момента, когда текущая задача начинает борзеть ;)}

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

    Недостатки: неспособность всех приложений работать в случае ошибки в одном из них, приводящей к отсутствию вызова операции "отдать процессорное время". Крайне затрудненная возможность реализации многозадачной архитектуры ввода-вывода в ядре ОС, позволяющей процессору исполнять одну задачу в то время, как другая задача инициировала операцию ввода-вывода и ждет ее завершения.
    {ну да, а если у нас 100% процессорного времени жрут не борзые программулины))}

    Реализована в пользовательском режиме ОС Windows версий до 3.х включительно, Mac OS версий до Mac OS X, а также внутри ядер многих UNIX-подобных ОС, таких, как FreeBSD, а в течение долгого времени - и Linux.

    Вытесняющая или приоритетная многозадачность (режим реального времени)

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

    Преимущества: возможность полной реализации многозадачного ввода-вывода в ядре ОС, когда ожидание завершения ввода-вывода одной программой позволяет процессору тем временем исполнять другую программу. Сильное повышение надежности системы в целом, в сочетании с использованием защиты памяти - идеал в виде "ни одна программа пользовательского режима не может нарушить работу ОС в целом" становится достижимым хотя бы теоретически, вне вытесняющей многозадачности он не достижим даже в теории. Возможность полного использования многопроцессорных и многоядерных систем.

    Недостатки: необходимость особой дисциплины при написании кода, особые требования к его реентрантности, к защите всех разделяемых и глобальных данных объектами типа критических секций и mutexов.

    Реализована в таких ОС, как:
    VMS
    в пользовательском режиме (а часто и в режиме ядра) всех UNIX-подобных ОС, включая версии Mac OS от OS X и старше, iPod OS и iPhone OS
    в режиме ядра ОС Windows 3.x - только при исполнении на процессоре 386 или старше, "задачами" являются только все Windows-приложения вместе взятые и каждая отдельная виртуальная машина ДОС, между приложениями Windows вытесняющая многозадачность не использовалась
    Windows 95/98/Me - без полноценной защиты памяти, что служило причиной крайне низкой, на одном уровне с MS-DOS, Windows 3.x и Mac OS версий до X - надежности этих ОС
    Windows NT/2000/XP/Vista/2008 и в режиме ядра, и в пользовательском режиме.

    Проблемные ситуации в многозадачных системах

    Голодание (starvation)

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

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

    Создает узкое место в системе, и не дает выжать из нее максимальную производительность, ограничиваемую только аппаратно обусловленными узкими местами.

    Любое голодание вне 100% загрузки процессора может быть устранено повышением приоритета голодающей нити, возможно - временным.

    Как правило для предотвращения голодания, ОС автоматически вызывает на исполнение готовые к исполнению низкоприоритетные потоки даже при наличии высокоприоритетных, при условии, что поток не исполнялся долгое время (~10 секунд).


    Гонка (race condition)

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

    Устраняется добавлением необходимых блокировок и примитивов синхронизации. Обычно является легким к устранению дефектом (забытая блокировка).

    {этот обьект уже используется}

    Инверсия приоритета

    Поток L имеет низкий приоритет, поток M - средний, поток H - высокий. Поток L захватывает mutex, и, выполняясь с удержанием mutexа, преемптивно прерывается потоком M, который пробудился по какой-то причине, и имеет более высокий приоритет. Поток H пытается захватить mutex.

    В полученной ситуации поток H ожидает завершения текущей работы потоком M, ибо, пока поток M исполняется, низкоприоритетный поток L не получает управления и не может освободить mutex.

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


    (с) Вики, гугл, мои конспекты).

    ЗЫ

    Давно статей не писал... Вот и захотелось написать статейку на эту тему, зачитался литературкой в последнее время и решил для себя красивенько выложить. Авось кму-то тоже понравятся эти все "веселые истории").
    ззы
    прямых линков не даю, ибо много чего много откедова. Модерам просьба оставить темку в железе, ибо тут ей и место.
    Пока писал статью, наметил еще две достойные темы, но, увы, забыл, надо записывать.
    ---
    статья составлена из простого к более сложному, но углубляться я не стал. Возможно, в будующем. Если вам не интересно - пусть гугл кэширует, ему полезно и мы не против ;)
     
    #1 Cthulchu, 5 Jan 2009
    Last edited: 5 Jan 2009
    2 people like this.