Блок - .data, .code, и регистры …?

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

И теперь я начинаю входить в блок и начинаю понимать, как он работает.

Вещи я чувствую, что понимаю хорошо, включают стек, прерывания, двоичный файл/шестнадцатеричное число, и в целом что делает большинство основных операций (jmp, продвиньте, mov, и т.д.).

Понятия, которые я изо всех сил пытаюсь понять и хотел бы справку с, ниже - это была бы огромная справка, если Вы могли бы обратиться к какому-либо следующему:

  1. Что точно происходит в разделе .data? Те переменные, мы объявляем?
  2. Если так, мы можем объявить переменные позже в секции кода? В противном случае, почему нет? Если так, как, и почему мы используем раздел данных затем?
  3. Что такое регистр? Как это выдерживает сравнение с переменной? Я подразумеваю, что знаю, что это - местоположение, которое хранит маленькую информацию..., но это точно походит на переменную мне.
  4. Как я делаю массив? Я знаю, что это кажется довольно случайным, но мне любопытно относительно того, как я пошел бы о выполнении чего-то вроде этого.
  5. Существует ли список где-нибудь общих методов для того, для чего должен использоваться каждый регистр? Я все еще не получаю их полностью, но заметил некоторых людей, говорящих, например, что определенный регистр должен использоваться для хранения 'возвращаемых значений' из процедур - существует ли всесторонний или по крайней мере информативный список таких методов?
  6. Одна из причин, я изучаю блок, состоит в том, чтобы лучше понять то, что продолжается позади моего кода высокого уровня. С этим в памяти - когда я программирую в C++, я часто думаю о стеке и "куче". В блоке я знаю то, что стек - где '"куча"'?

Некоторая информация: я использую 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 могли быть локальные переменные в той функции.

28
задан Cam 1 March 2010 в 07:01
поделиться

2 ответа

Давайте попробуем ответить по порядку!

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

  2. Переменные на самом деле не существуют при программировании на ассемблере, по крайней мере, в том смысле, в котором они существуют, когда вы пишете код на C. Все, что у вас есть, - это принятые вами решения о том, как расположить свою память. Переменные могут быть в стеке, где-то в памяти или просто жить только в регистрах.

  3. Регистры - это внутреннее хранилище данных процессора. Как правило, вы можете выполнять операции только со значениями в регистрах процессора. Вы можете загружать и сохранять их содержимое в памяти и из памяти, что является основной операцией работы вашего компьютера. Вот небольшой пример.Этот код 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 
     

    В этом случае вы можете рассматривать регистры как переменные, но в целом необязательно, чтобы какая-либо одна переменная всегда оставалась в одном и том же регистре; в зависимости от того, насколько сложен ваш распорядок дня, это может быть даже невозможно. Вам нужно будет поместить некоторые данные в стек, удалить другие данные и так далее. «Переменная» - это логическая часть данных, а не то место, где она находится в памяти или регистрах и т. Д.

  4. Массив - это просто непрерывный блок памяти - для локального массива вы можете просто уменьшить указатель стека соответствующим образом. Для глобального массива вы можете объявить этот блок в разделе данных.

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

  6. Ваша ассемблерная программа может выполнять те же системные вызовы, что и любая программа на C, поэтому вы можете просто вызвать malloc () , чтобы получить память из кучи.

32
ответ дан 28 November 2019 в 03:15
поделиться

Я хотел бы добавить к этому. Программы на компьютере обычно делятся на три части, хотя существуют и другие.

Сегмент кода - .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 или системный вызов распределения памяти, но она там есть.

Извините за сочинение.

18
ответ дан 28 November 2019 в 03:15
поделиться