Должны ли эти декларации быть в глобальном масштабе? Если это так, в статическом хранилище для переменных C будут метки asm. Если нет (локально внутри функции), они будут в стеке и IDK, как они ожидают, что вы будете знать, в каком смещении от BP они будут.
В любом случае, это 32-битные сегменты seg: off (с прямым порядком байтов, поэтому смещены в младшие 16 бит) дальние указатели, поэтому копирование одного в другое - это просто 4-байтовая копия, которую вы можете сделать с 2 целочисленными загрузками + магазины.
Переменные-указатели (когда они не оптимизируются вне или в регистр) сохраняют само значение указателя в памяти , как int
или long
. В C, когда вы делаете *pty
, компилятор должен загрузить значение указателя в регистры, затем выполнить другую загрузку указанной памяти.
Я собираюсь предположить, что DS
относится к сегменту данных, где сами значения указателя хранятся в памяти. И это sizeof(int)=2
, потому что это кажется вероятным для 16-битной реализации языка Си.
Для разыменования и загрузки памяти, на которую указывает pty
, то есть *pty
, вам необходимо загрузить сегментную часть указателя детали в регистр сегмента, а смещенную часть - в SI, DI или BX ( регистры, которые можно использовать как часть режима адресации). В x86 есть соответствующие инструкции, например, les
/ lds
.
Поскольку мы, вероятно, не хотим изменять DS
, я просто буду использовать ES
. (Различные ассемблеры используют разный синтаксис для переопределения сегментов, например [es: di]
для NASM, но я думаю, может быть es:[di]
для TASM.)
;; *ptx = *pty
;; clobbers: ES, DI, and AX
; load *pty
les di, [pty] ; load pty from [DS:pty] into ES:DI
mov ax, es:[di] ; load *pty into AX
; store *ptx
les di, [ptx] ; load ptx from [DS:ptx] into ES:DI
stosw ; store to *ptx from AX
STOSW сохраняет AX в ES: DI и увеличивает или уменьшает DI в соответствии с флагом направления, DF. Нас не волнует значение DI после выполнения этой инструкции, но стандартное соглашение о вызовах для Turbo C ++ (и современные соглашения x86) гласит DF=0
(увеличение вверх) при входе / выходе функции.
Используйте обычный mov
с переопределением другого сегмента, если вы еще не узнали о строковых инструкциях.
(@ MichaelPetch говорит, что DS обычно сохраняется в 16-разрядных соглашениях о вызовах в реальном режиме, но ES можно свободно перемещать, не сохраняя и не восстанавливая его, так что, очевидно, я догадался.)
Или, если вы можете заткнуть DS и ES, вы можете использовать MOVSW . Использование push / pop ds
для сохранения / восстановления было бы большим количеством инструкций. (Но все же меньший размер кода)
;; assuming DS is correct for referencing static data like [pty]
les di, [pty] ; load pty from [DS:pty] into ES:DI
lds si, [ptx] ; load ptx from [DS:ptx] into DS:SI
movsw ; copy a word from [DS:SI] to [ES:DI]
Обратите внимание, что я использовал lds
секунду , потому что я предполагаю, что оба глобала в статическом хранилище доступны через входящее значение DS
, а не то, какое значение сегмента является частью другого дальнего указателя .
Если бы у вас была «огромная» или «большая» модель памяти (или другая модель, где известно, что не все статические данные помещаются в один сегмент размером 64 КБ), это было бы более сложно, но ваш вопрос ничего не показал о где ptx
и pty
действительно хранятся.
Кроме того, я предполагаю, что вы не должны оптимизировать их, основываясь на том, как они недавно были назначены , хотя вопрос показывает, на что они указывают.
Если вы знаете ptx = &x
, то вам не нужно загружать ptx
из памяти, вы можете просто mov [x], ax
(опять-таки, предполагая модель кода, в которой статические данные, такие как x
, доступны через DS).
Кроме того, нет смысла читать из *pty
, когда он указывает на только что malloc
хранилище, потому что оно не инициализировано. Другой способ будет иметь смысл. Я, вероятно, слишком анализирую это.