Относительная и абсолютная JMP в сборке - PullRequest
8 голосов
/ 15 января 2011

Меня интересовало следующее. При написании ассемблера я заметил, что IA32 спроектирован таким образом, чтобы стимулировать использование относительных переходов, то есть переход на величину смещения байтов по сравнению с использованием абсолютных переходов, то есть изменение eip на определенный адрес в памяти. Какая логика стоит за этим?

Ответы [ 2 ]

14 голосов
/ 15 января 2011

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

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

9 голосов
/ 15 января 2011

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

Стоит потратить время на написание некоторого кода на языке высокого уровня, таком как C, чтобы компилятор генерировал код сборки(отметьте опцию -S для gcc), а затем прочитайте вывод сборки.Обратите особое внимание на условия и циклы, такие как if, for и while, и вы увидите, что все они генерируют относительные переходы.

Вот надуманный пример с использованием вымышленных инструкций по сборке:

// Sample C code         Address  Assembly Code       Comments

if (x < 10) {            0000     CMP x,#10           ; Compare x to 10
   do_true_stuff();      0003     JGE +7              ; Skip 7 bytes to 000A if x>=10
} else {                 0005     SUB do_true_stuff   ; x<10
   do_false_stuff();     0008     JMP +5              ; Skip 5 bytes to 000D
}                        000A     SUB do_false_stuff  ; else-branch (x>=10)
do_more_stuff();         000D     SUB do_more_stuff   ; Finished if/else

Здесь компилятор генерирует относительные переходы (JGE и JMP), чтобы пропустить невыполненную ветвь блока if-else.Эти переходы будут работать независимо от того, где в памяти компоновщик поместит код.Если бы это были абсолютные переходы, компоновщику нужно было бы пересчитывать адреса каждый раз, когда он связывал код.

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

Надеюсь, это поможет!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...