Таким образом, этим утром я отправил запутанный вопрос о блоке, и я получил некоторую большую подлинную справку, которую я действительно ценю.
И теперь я начинаю входить в блок и начинаю понимать, как он работает.
Вещи я чувствую, что понимаю хорошо, включают стек, прерывания, двоичный файл/шестнадцатеричное число, и в целом что делает большинство основных операций (jmp, продвиньте, mov, и т.д.).
Понятия, которые я изо всех сил пытаюсь понять и хотел бы справку с, ниже - это была бы огромная справка, если Вы могли бы обратиться к какому-либо следующему:
Некоторая информация: я использую masm32 с WinAsm как IDE, и я работаю над Windows 7. У меня есть большое предшествующее программирование опыта на высокоуровневых языках, таких как c ++/java.
править: Спасибо за справку все, чрезвычайно информативные, как обычно! Большой материал! Одна последняя вещь, хотя - я задаюсь вопросом, что различие между Указателем вершины стека, и Указателем базы, или ESP и EBP. Кто-то может выручить меня?
править: Я думаю, что получаю его теперь... ESP всегда указывает на вершину стека. Однако можно указать на EBP на то, что Вы хотите. ESP автоматически обрабатывается, но можно сделать то, что Вы хотите с EBP. Например:
push 6
push 5
push 4
mov EBP, ESP
push 3
push 2
В этом сценарии EBP теперь указывает на адрес, содержащий 4, но ESP теперь указывает на адрес, содержащий 2.
В реальном приложении 6, 5, и 4, возможно, были аргументы функции, тогда как 3 и 2 могли быть локальные переменные в той функции.
Давайте попробуем ответить по порядку!
Раздел данных содержит все, что вы хотите, чтобы система автоматически инициализировала перед вызовом точки входа вашей программы. Вы правы, обычно здесь оказываются глобальные переменные. Данные с нулевой инициализацией обычно не включаются в исполняемый файл, поскольку нет причин для этого - пара директив для загрузчика программы - это все, что нужно для создания этого пространства. После запуска вашей программы ZI и области данных, как правило, взаимозаменяемы. В Википедии гораздо больше информации.
Переменные на самом деле не существуют при программировании на ассемблере, по крайней мере, в том смысле, в котором они существуют, когда вы пишете код на C. Все, что у вас есть, - это принятые вами решения о том, как расположить свою память. Переменные могут быть в стеке, где-то в памяти или просто жить только в регистрах.
Регистры - это внутреннее хранилище данных процессора. Как правило, вы можете выполнять операции только со значениями в регистрах процессора. Вы можете загружать и сохранять их содержимое в памяти и из памяти, что является основной операцией работы вашего компьютера. Вот небольшой пример.Этот код C:
int a = 5;
int b = 6;
int * d = (int *) 0x12345678; // предполагаем, что 0x12345678 - допустимый указатель памяти
* d = a + b;
Может быть преобразован в некоторую (упрощенную) сборку в следующих строках:
load r1, 5
загрузить r2, 6
загрузить r4, 0x1234568
добавить r3, r1, r2
сохранить r4, r3
В этом случае вы можете рассматривать регистры как переменные, но в целом необязательно, чтобы какая-либо одна переменная всегда оставалась в одном и том же регистре; в зависимости от того, насколько сложен ваш распорядок дня, это может быть даже невозможно. Вам нужно будет поместить некоторые данные в стек, удалить другие данные и так далее. «Переменная» - это логическая часть данных, а не то место, где она находится в памяти или регистрах и т. Д.
Массив - это просто непрерывный блок памяти - для локального массива вы можете просто уменьшить указатель стека соответствующим образом. Для глобального массива вы можете объявить этот блок в разделе данных.
Существует множество соглашений о регистрах - проверьте ABI вашей платформы или документ соглашения о вызовах, чтобы узнать, как их правильно использовать. Ваша документация по ассемблеру также может содержать информацию. Посмотрите статью ABI в Википедии .
Ваша ассемблерная программа может выполнять те же системные вызовы, что и любая программа на C, поэтому вы можете просто вызвать malloc ()
, чтобы получить память из кучи.
Я хотел бы добавить к этому. Программы на компьютере обычно делятся на три части, хотя существуют и другие.
Сегмент кода - .code, .text : http://en.wikipedia.org/wiki/Code_segment
В вычислительной технике сегмент кода, также известный как сегмент текста или просто как сегмент текста. известный как сегмент текста или просто как текст, - это фраза, используемая для обозначения часть памяти или объектного файла который содержит исполняемые инструкции. Он имеет фиксированный размер и обычно только для чтения. Если текстовый раздел не является только для чтения, то конкретная архитектура позволяет самомодифицирующийся код. Код, доступный только для чтения, является реентерабельным, если он может выполняться более чем одним процессом одновременно. Как область памяти область, сегмент кода располагается в нижней части памяти или в самом ее нижней части памяти, чтобы предотвратить переполнение кучи и переполнения стека от его перезаписи.
Сегмент данных - .data : http://en.wikipedia.org/wiki/Data_segment
Сегмент данных - это один из разделов программы в объектном файле или в памяти, который содержит глобальные переменные и статические переменные, которые инициализируются программистом. Он имеет фиксированный размер, поскольку все данные в этой секции устанавливаются программистом до того, как программа будет загружается. Однако он не доступен только для чтения, поскольку значения переменных могут быть изменены во время выполнения программы. Это отличие от секции Rodata (константа, данные только для чтения), а также сегмент кода (также известный как текстовый сегмент).
BSS : http://en.wikipedia.org/wiki/.bss
В компьютерном программировании, .bss или bss (что первоначально означало Block Started by Symbol) используется многими компиляторами и компоновщиками как название части сегмента данных, содержащего статические переменные и глобальные переменные которые заполнены исключительно данными с нулевым значением изначально (т.е, когда начинается выполнение). Ее часто называют "секцией bss" или "сегмент bss". Загрузчик программы инициализирует память, выделенную для секции bss при загрузке программу.
Регистры - это, как описано другими, средства центрального процессора для хранения данных или адреса памяти. Над регистрами выполняются такие операции, как add eax, ebx
, и в зависимости от диалекта ассемблера это означает разные вещи. В данном случае это означает добавить содержимое ebx к eax и сохранить его в eax (синтаксис NASM). Эквивалент в GNU AS (AT&T) следующий: movl $ebx, $eax
. Разные диалекты ассемблера имеют разные правила и операторы. По этой причине я не являюсь поклонником MASM - он сильно отличается от NASM, YASM и GNU AS.
Взаимодействия с C в целом не существует. ABI определяют, как это происходит; например, на x86 (unix) вы увидите, что аргументы метода выталкиваются в стек, тогда как в x86-64 на Unix первые несколько аргументов будут размещены в регистрах. Оба ABI ожидают, что результат функции будет храниться в регистре eax/rax.
Вот 32-битная рутина сложения, которая ассемблируется как для Windows, так и для Linux.
_Add
push ebp ; create stack frame
mov ebp, esp
mov eax, [ebp+8] ; grab the first argument
mov ecx, [ebp+12] ; grab the second argument
add eax, ecx ; sum the arguments
pop ebp ; restore the base pointer
ret
Здесь вы можете увидеть, что я имею в виду. Возвращаемое значение находится в eax. В отличие от этого, версия для x64 будет выглядеть так:
_Add
push rbp ; create stack frame
mov rbp, rsp
mov eax, edi ; grab the first argument
mov ecx, esi ; grab the second argument
add eax, ecx ; sum the arguments
pop rbp ; restore the base pointer
ret
Существуют документы, определяющие подобные вещи. Вот UNIX x64 ABI: http://www.x86-64.org/documentation/abi-0.99.pdf. Я уверен, что вы могли бы найти ABI для любого процессора, платформы и т.д., которые вам нужны.
Как оперировать с массивом на ассемблере? Арифметика указателей. Учитывая базовый адрес eax
, следующее хранимое целое число будет находиться по адресу [eax+4]
, если целое число имеет размер 4 байта. Вы можете создать это пространство, используя вызовы malloc/calloc, или вызвать системный вызов распределения памяти, каким бы он ни был в вашей системе.
Что такое "куча"? Согласно Википедии, это область памяти, зарезервированная для динамического распределения памяти. Вы не видите ее в своей ассемблерной программе, пока не вызовете calloc, malloc или системный вызов распределения памяти, но она там есть.
Извините за сочинение.