8086 - почему мы не можем переместить немедленные данные в регистр сегментов?

В программировании сборки 8086 мы можем загружать данные только в регистр сегментов, сначала загружая его в регистр общего назначения, а затем мы должны перенести его из этого общего регистра в регистр сегментов.

Почему мы не можем загрузить его напрямую? Есть ли какая-то особая причина для того, чтобы вас не разрешили?

В чем разница между mov ax,5000H и mov ax,[5000H]? Имеет ли [5000h] содержание в памяти 5000h?

Ответ 1

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

Итак, просто потому, что похоже, что вы могли написать mov DS, [5000h], и что концептуально не кажется, что есть причина, по которой вы не сможете это сделать, это действительно о "есть механизм, посредством которого процессор может загружать сегментный регистр из содержимого ячейки памяти?"

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


Почему? У меня есть несколько теорий, но нет авторитетных знаний.

Наиболее вероятная причина - просто упростить дизайн: для этого требуется дополнительная проводка и ворота, и это довольно необычная операция (это 70-е годы), что она не стоит недвижимости в чипе. Это неудивительно; 8086 уже вышел за борт, позволяя подключать любой из нормальных регистров к ALU (арифметическому логическому блоку), который позволяет использовать любой регистр в качестве аккумулятора. Я уверен, что это было не дешево. Большинство процессоров в то время позволяли использовать только один регистр (аккумулятор) для этой цели.

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


Что касается скобок, вы правы. Пусть говорят, что позиция памяти 5000h содержит номер 4321h. mov ax, 5000h ставит значение 5000h в ax, а mov ax, [5000h] загружает 4321h из памяти в топор. По существу, скобки действуют как оператор разыменования указателя * в C.

Просто чтобы подчеркнуть тот факт, что сборка является идеализированной абстракцией того, что может сделать машинный код, вы должны заметить, что два варианта - это не одна и та же команда с разными параметрами, а совершенно разные коды операций. Они могли бы использовать - say - MOV для первой и MVD (адресная память MoVe Direct) для второго кода операции, но они должны были решить, что синтаксис скобки легче запомнить программистам.

Ответ 2

Машинный код x86 имеет только один код операции для перехода к Sreg. Этот код операции
8E /r mov Sreg, r/m16 и разрешает регистр или источник памяти (но не сразу).

Вопреки некоторым утверждениям в других ответах, mov ds, [5000h] работает очень хорошо, предполагая, что 2 байта по адресу 5000h содержат полезное значение сегмента для режима, в котором вы находитесь. (В реальном режиме, где они используется непосредственно как числа против защищенных, где значения Sreg являются селекторами, которые индексируют LDT/GDT).

x86 всегда использует другой код операции для немедленной формы инструкции (с константой, закодированной как часть машинного кода), в отличие от версии регистра/источника памяти. например add eax, 123 собирается с кодом операции, отличным от add eax, ecx. Но add eax, [esi] - это тот же код операции add r, r/m32, что и add eax, ecx, просто другой байт ModR/M.


Список NASM из nasm sreg.asm -l/dev/stdout, сборка плоского двоичного файла в 16-битном режиме и создание списка.

Я отредактировал вручную, чтобы разделить байты в opcode modrm extra. Все это однобайтовые коды операций (без дополнительных битов кода операции, занимающих место в поле /r байта ModRM), поэтому просто посмотрите на первый байт, чтобы увидеть, что это за код операции, и обратите внимание, когда две инструкции используют один и тот же код операции.

   address    machine code         source           ;  comments
 1 00000000 BE 0050           mov si, 5000h     ; mov si, imm16
 2 00000003 A1 0050           mov ax, [5000h]   ; special encoding for AX, no modrm
 3 00000006 8B 36 0050        mov si, [5000h]   ; mov r16, r/m16 disp16
 4 0000000A 89 C6             mov si, ax        ; mov r/m16, r16
 5                                  
 6 0000000C 8E 1E 0050        mov ds, [5000h]   ; mov Sreg, r/m16
 7 00000010 8E D8             mov ds, ax        ; mov Sreg, r/m16
 8                                  
 9                            mov ds, 5000h
 9          ******************       error: invalid combination of opcode and operands

Для поддержки кодировки mov Sreg, imm16 потребуется отдельный код операции. Это потребовало бы дополнительных транзисторов для декодирования 8086, и это заняло бы больше места кодирования кода операции, оставляя меньше места для будущих расширений. Я не уверен, какой из них был сочтен более важным архитектором (ами) 8086 ISA.

Обратите внимание, что 8086 имеет специальные коды операций mov AL/AX, moffs, которые экономят 1 байт при загрузке аккумулятора с абсолютного адреса. Но он не мог избавить Срег от кода операции для mov -immediate? Это дизайнерское решение имеет смысл. Как часто вам нужно перезагрузить сегментный регистр? Очень редко, и в действительно больших программах это часто не было бы с константой (я думаю). Но в коде, использующем статические данные, вы можете загружать/хранить аккумулятор по фиксированному адресу внутри цикла. (8086 имел очень слабую выборку кода, поэтому большую часть времени размер кода = скорость).

Также имейте в виду, что вы можете использовать mov Sreg, r/m16 для констант времени сборки только с одной дополнительной инструкцией (например, mov ax, 4321h). Но если бы у нас был только mov Sreg, imm16, для значений сегментов переменных времени выполнения потребовался бы самоизменяющийся код. (Очевидно, что вы не пропустите исходную версию r/m16.) Я хочу сказать, что если у вас будет только одна версия, то она определенно будет исходной версией из регистра/памяти.

Ответ 3

О сегментах регистров

Регистры сегментов не являются одинаковыми (на аппаратном уровне) в качестве регистров общего назначения. Конечно, как сказал Майк У. в комментариях, точная причина, по которой вы не можете напрямую перемещать непосредственное значение в регистр сегментов, известна только разработчикам Intel. Но я полагаю, это потому, что дизайн прост именно так. Обратите внимание, что этот выбор не влияет на производительность процессора, потому что операции с регистром сегмента очень редки. Итак, одна инструкция больше, одна менее важна вообще.

О синтаксисе

Во всех разумных реализациях синтаксиса ассемблера x86 mov reg, something перемещает непосредственное число something в регистр reg. Например:

NamedConst = 1234h
SomeLabel:
    mov  edx, 1234h      ; moves the number 1234h to the register edx
    mov  eax, SomeLabel  ; moves the value (address) of SomeLabel to eax
    mov  ecx, NamedConst ; moves the value (1234h in this case) to ecx

Закрытие числа в квадратных скобках означает, что содержимое памяти с этим адресом перемещается в регистр:

SomeLabel dd 1234h, 5678h, 9abch

    mov  eax, [SomeLabel+4]  ; moves 5678h to eax
    mov  ebx, dword [100h]   ; moves double word memory content from the 
                             ; address 100h in the data segment (DS) to ebx.

Ответ 4

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

Загрузка регистров сегментов из ячейки памяти или константы связана с циклами памяти. Если выравнивание памяти испорчено, чтение 16-битного значения может занимать два цикла памяти. В промежутках между циклами значение регистра сегмента недействительно. Теперь представьте, что вы возитесь с регистром сегмента стека, и происходит прерывание: вот ваша ручная тележка; наслаждайтесь поездкой!