Пояснение кода сборки - PullRequest
2 голосов
/ 05 ноября 2010

Я начал изучать сборку. Я наткнулся на эти строки.

;*************************************************;
; Second Stage Loader Entry Point
;************************************************;

main:
   cli  ; clear interrupts
   push cs ; Insure DS=CS
   pop ds

Здесь, во второй строке кода, сегмент кода помещается в стек (я так думаю). Я видел это во многих кодах. Почему мы должны это делать и как это обеспечивает DS = CS? На третьей строке DS выскочил из стека (я так думаю). Почему это сделано? Это выпадение из стека означает, что он был передан в стек ранее. Для этого нет кода. Кто-нибудь может мне все это объяснить? Заранее спасибо.

Ответы [ 5 ]

4 голосов
/ 05 ноября 2010

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

Итак, что только что произошлобыло то, что вы скопировали cs в ds.

push - это инструкция, которая говорит: «положите это на вершину стека»

pop - это инструкция, которая говорит: «возьмите верхнее значение из стека»

Как только вы выполните pop, значение больше не будет сохранено в стеке.

4 голосов
/ 05 ноября 2010

Это гарантирует не push cs, а комбинация push cs; pop ds;.

Первая инструкция копирует текущее значение cs в стек, а вторая извлекает это значение из стека и помещает его в регистр ds.


В ответ на ваш запрос о дополнительной информации давайте начнем со следующего стека и регистров:

stack=[1,2,3], cs=7, ds=6

После push cs, который помещает значение регистра cs в стек:

stack=[1,2,3,7], cs=7, ds=6

После pop ds, который извлекает значение из стека и помещает его в регистр ds:

stack=[1,2,3], cs=7, ds=7

И это в основном все.


Я не могу вспомнить, как можно было перевести между сегментными регистрами инструкцию mov (я не думаю, что это было так, но я могу ошибаться, и это потребовало бы толчка / поп последовательность). Эта ссылка , кажется, подтверждает, что: нет опции mov с сегментным регистром в качестве источника и адресата.

Но даже если бы это было так, ассемблерные кодеры часто выбирали более подходящие инструкции, либо для скорости, либо для компактного кода (или обоих), например, для использования xor ax, ax вместо mov ax, 0.

1 голос
/ 05 ноября 2010

«Выгрузить этот регистр в стек, вставить стек в этот регистр» иногда можно сделать с помощью команд MOV, таких как MOV ax, dx. Но некоторые инструкции MOV для регистрации в регистре недоступны в наборе команд, а IIRC MOV ds, cs недоступна. Это может быть причиной для помещения его в память (ну, кеш, на самом деле) и чтения его обратно.

0 голосов
/ 05 ноября 2010

Как и в написанном комментарии, push cs, а затем pop ds гарантирует, что ds=cs?.push cs помещает значение cs на вершину стека, а затем pop ds удаляет значение из стека и сохраняет его в ds.

0 голосов
/ 05 ноября 2010

Отправляя значение CS в стек и вставляя его в DS, вы гарантируете, что DS имеет то же значение, что и CS.

Я некоторое время не программировал на ассемблере, но я подумалпрямого перехода из одного сегмента в другой не было.

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

Это происходит при выполнении кода.

1) исходная ситуация

CS has value X
DS has value Y
Stack has ....

2) push CS

CS has value X
DS has value Y
Stack has ...., X

3) pop DS

CS has value X
DS has value X
Stack has ....

Но что такое сегментные регистры.В старые времена у 8086 были 16-битные регистры адресов, но 20-битное адресное пространство.Таким образом, они использовали регистры сегментов для объединения обоих в 20-битное пространство путем умножения регистра сегментов на 16 и добавления области памяти.Для экономии места у нас были ближние указатели (без сегмента для перехода в пределах сегмента) и дальние указатели (с сегментом).

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

...