Как инструкция перехода в сборке работает с несколькими процессами?

Итак, я не понимаю, как работают инструкции перехода в операционной системе. Я думал, что инструкция перехода устанавливает значение в программном счетчике процессора. Но программы могут быть запущены в разных местах памяти. Я вижу, что в x86 есть JMP EAXинструкция, но мой код на C ++, похоже, не использует это. Я скомпилировал немного кода C ++ в VC ++:

int main()
{
    int i = 0;
    while (i < 10)
    {
        ++i;
        if (i == 7)
        {
            i += 1;
            continue;
        }
    }
}

Это переводится как:

    int main()
    {
00411370  push        ebp  
00411371  mov         ebp,esp 
00411373  sub         esp,0CCh 
00411379  push        ebx  
0041137A  push        esi  
0041137B  push        edi  
0041137C  lea         edi,[ebp-0CCh] 
00411382  mov         ecx,33h 
00411387  mov         eax,0CCCCCCCCh 
0041138C  rep stos    dword ptr es:[edi] 
        int i = 0;
0041138E  mov         dword ptr [i],0 
        while (i < 10)
00411395  cmp         dword ptr [i],0Ah 
00411399  jge         main+47h (4113B7h) 
        {
            ++i;
0041139B  mov         eax,dword ptr [i] 
0041139E  add         eax,1 
004113A1  mov         dword ptr [i],eax 
            if (i == 7)
004113A4  cmp         dword ptr [i],7 
004113A8  jne         main+45h (4113B5h) 
            {
                i += 1;
004113AA  mov         eax,dword ptr [i] 
004113AD  add         eax,1 
004113B0  mov         dword ptr [i],eax 
                continue;
004113B3  jmp         main+25h (411395h) 
            }
        }
004113B5  jmp         main+25h (411395h) 
    }
004113B7  xor         eax,eax 
004113B9  pop         edi  
004113BA  pop         esi  
004113BB  pop         ebx  
004113BC  mov         esp,ebp 
004113BE  pop         ebp  
004113BF  ret              

Так что я запутался, для команды jmp 411395h, означает ли это, что программа всегда загружается в одно и то же место в памяти? Потому что это кажется нелогичным.

13.10.2009 02:00:26
Помните, что современные процессоры, как правило, поддерживают виртуальную память, то есть каждая программа имеет свое адресное пространство. Таким образом, байт в 0x12345678 в одном процессе может быть другой точкой в ​​реальной памяти, чем байт в 0x12345678 в другом процессе.
Joey Adams 13.10.2009 02:11:02
7 ОТВЕТОВ
РЕШЕНИЕ

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

Когда компоновщик генерирует исполняемый файл, он генерирует абсолютные адреса, предполагая конкретный базовый адрес ; Компоновщик Microsoft обычно использует 400000h. Когда ОС загружает исполняемый файл или dll, она «исправляет» все абсолютные адреса, добавляя разницу между адресом, по которому исполняемый файл был фактически загружен, и адресом, на котором его основал компоновщик. Все форматы исполняемых файлов, за исключением .comопределенной таблицы исправлений, в которой перечислены все местоположения в исполняемом файле, которые должны быть исправлены таким образом. Следовательно, после того, как ОС загрузит ваш исполняемый файл в память по базовому адресу, скажем 1500000h, ваш переход будет выглядеть следующим образом jmp 1511395h. Вы можете проверить это, посмотрев фактические байты кода с помощью отладчика.

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

6
13.10.2009 18:47:40
Инструкции jmp на 004113B3 и ... B5 должны быть относительными скачками. По адресным меткам мы можем сказать, что эти инструкции jmp кодируются как двухбайтовые инструкции. Следовательно, они являются относительными инструкциями jmp. Двухбайтовые инструкции jmp приводят к перезагрузке EIP с помощью EIP +/- 127. Значение +/- 127 является вторым байтом двухбайтового кода операции. Первый байт этого кода операции jmp - EB. Существуют версии jmp (например, не относительная адресация), которые начинаются с E9, EA, FF - поэтому важно понимать, что есть несколько различных кодов операций, все с мнемоническим «jmp» на ассемблере.
Heath Hunnicutt 14.10.2009 04:04:24

Большинство чипов имеют относительные переходы (относительно текущего местоположения) и виртуальную адресацию.

2
13.10.2009 02:03:33
Что-то не так с ответом? Пожалуйста, оставьте комментарий. Спасибо!
user181548 13.10.2009 04:26:13

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

3
13.10.2009 04:24:28
Это не совсем верно - некоторые ОС используют рандомизацию макета адресного пространства для загрузки программы по разному адресу каждый раз, когда она запускается, для лучшей защиты от угроз безопасности.
Adam Rosenfield 13.10.2009 02:08:49
@ Adam, не имеет значения, куда он загружен, программа видит одно и то же адресное пространство независимо от того, что делает ОС. В противном случае хаос застраховал бы.
Byron Whitlock 13.10.2009 02:14:15
@Byron - exes могут быть загружены по разным адресам. Исполняемый файл содержит информацию о перемещении, так что загрузчик может настроить абсолютные адреса в exe, если он не загружен по своему предпочтительному адресу. С exes это не так часто, это чаще происходит с загрузкой DLL.
Michael 13.10.2009 02:55:48
@ Байрон - нет; В этом весь смысл ASLR. Каждый процесс видит свою схему, поэтому атаки, которые работают с переполнением буфера, не будут работать от запуска к запуску (если вам повезет). Это требует, чтобы весь код был перемещаемым, и он требует, чтобы динамический загрузчик тщательно исправлял адреса, и после загрузки адрес не меняется, но компоненты программ могут находиться по разным адресам в разных запусках одного и того же исполняемого файла.
Jonathan Leffler 13.10.2009 02:58:52

Нет. На x86 (и других архитектурах) большинство инструкций перехода являются IP-относительными : двоичные машинные коды для команд представляют смещение от текущего указателя инструкции. Таким образом, независимо от того, по какому виртуальному адресу загружается код, инструкции перехода работают правильно.

3
13.10.2009 02:05:13

Нет, здесь могут быть две вещи - вы не указываете ОС, поэтому я собираюсь дать общий ответ.

Во-первых, исполняемый файл редко находится в окончательном формате. Для упрощения компиляция превращает исходный код в объектные файлы, а компоновка объединяет объектные файлы в исполняемый файл.

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

Это может быть достигнуто с помощью исполняемого файла, содержащего список адресов внутри себя, которые должны быть исправлены во время выполнения.

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

Когда ваш процесс запускается, вы получаете свое собственное (4G для Windows 32bit, я полагаю) адресное пространство, в которое загружен ваш процесс. Адреса в этом адресном пространстве мало связаны с вашими фактическими адресами физической памяти, и преобразование между ними осуществляется блоком управления памятью (MMU).

Фактически, ваш процесс может летать по всему физическому адресному пространству, когда он выгружается и разворачивается. Однако виртуальные адреса не изменятся.

6
13.10.2009 02:08:48
«Вы не указываете ОС» На скольких операционных системах работает Visual C ++?
user181548 13.10.2009 02:22:20
Ну, он сказал: «Я вижу, что в x86» и «Я скомпилировал некоторый код C ++ в VC ++», но я взял это просто в качестве примера, поскольку (1) нет специфичных для ОС тегов; и (2) вопрос носит весьма общий характер: «в сборе», «операционная система».
paxdiablo 13.10.2009 02:31:21

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

Если вы посмотрите на свой код

004113B3  jmp         main+25h (411395h) 
004113B5  jmp         main+25h (411395h) 
004113B7  xor         eax,eax 

вы заметите, что инструкция jmp имеет длину 2 байта (1 байт для jmp, 1 байт для смещения) и не может хранить абсолютный 4-байтовый адрес.

Относительные скачки являются основной функциональностью процессоров (из того, что я знаю о 65xx, Z80, 8086, 68000) и не связаны с такими расширенными функциями, как виртуальная память, отображение памяти или рандомизация адресного пространства.

3
13.10.2009 04:42:49
int main()
    {
00411370  push        ebp  
00411371  mov         ebp,esp 
00411373  sub         esp,0CCh 
00411379  push        ebx  
0041137A  push        esi  
0041137B  push        edi  
0041137C  lea         edi,[ebp-0CCh] 
00411382  mov         ecx,33h 
00411387  mov         eax,0CCCCCCCCh 
0041138C  rep stos    dword ptr es:[edi] 
        int i = 0,int j=0;
0041138E  mov         dword ptr [i][j],0
        while (i < 10)
00411395  cmp         dword ptr [i][j[,0Bh 
00411399  jge         main+47h (4113B7h) 
        {
            ++i;
0041139B  mov         eax,dword ptr [i][j] 
0041139E  add         eax,1 
004113A1  mov         dword ptr [i][j],eax '
            if (i == 7)
004113A4  cmp         dword ptr [i][j],7 
004113A8  jne         main+45h (4113B5h) 
            {
                i += 1;
004113AA  mov         eax,ebx,dword ptr [i][j] 
004113AD  add         eax,1 
004113B0  mov         dword ptr [i][j],ebx 
                continue;
004113B3  jmp         main+25h (411395h) 
            }
        }
004113B5  jmp         main+25h (411395h) 
    }
004113B7  xor         eax,ebx 
004113B9  pop         edi  
004113BA  pop         esi  
004113BB  pop         ecx  
004113BC  mov         esp,ebp 
004113BE  pop         ebp  
004113BF  ret
0
12.04.2015 18:52:32