2017-01-14 2 views
1

В моей программе Linux Assembly для процессоров IA-32 у меня есть два хранилища.Как вы определяете размер хранилища 3 байта в инструкции XOR в Assembly?

inbuf: resb 3 
outbuf: resb 4 

inbuf действительно нужно только 3 байта, и я не люблю тратить память. Теперь, скажем, я хочу, чтобы заменить их нулями, как это:

xor [inbuf], inbuf 
xor [outbuf], outbuf 

NASM говорит, что мне нужно указать размер операции, что и понятно. Теперь outbuf это не проблема, потому что я могу написать

xor dword [outbuf], outbuf 

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

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

mov eax, inbuf 

без получения ошибки «размер не указанной».

+3

Действительно, размер операции не равен 3 байтам, вам нужно будет синтезировать его с 2 + 1 байт, например. Даже если бы это было так, ваш код не будет делать то, что вы хотите, вы xoring с адресом, а не значением (которое вы не можете сделать напрямую). Просто придерживайтесь двух степеней эффективности. PS: 'mov eax, inbuf' не вызывает ошибку« размер не указанной », так как размер« eax »известен и неявно определяет размер операции. – Jester

+0

@Jester Использование полномочий 2 будет немного неудовлетворительным. Что вы имеете в виду с добавлением 2 и 1 байт вместе? Могу ли я сделать что-то вроде 'xor byte + word [inbuf], inbuf' или это синтаксически неверно? –

+3

Я имею в виду, используйте 2 инструкции. Кроме того, как я уже сказал, вы не можете использовать 'xor mem, mem' в ноль (он не принимает 2 операнда памяти). 'mov word [inbuf], 0; mov byte [inbuf + 2], 0' будет работать. – Jester

ответ

5

Я добавлю правильный ответ Джесса в комментарии.

Если вы настаиваете на «xor-ing» памяти (не имеет смысла для обнуления, но может стоить для других значений), то «xor 3B [inbuf], 3B [inbuf]» может быть выполнено в x86 сборки, как это:

mov eax,[inbuf] ; loads value from inbuf + 1B undef 
xor [inbuf],ax ; word 
shr eax,16  ; al = b16..b23 of value @inbuf 
xor [inbuf+2],al ; byte 

двойного слова вариант 4B:

mov eax,[outbuf] 
xor [outbuf],eax 

И все это ужасно для обнуления, для обнуления это лучше:

mov word [inbuf],0 
mov byte [inbuf+2],0 
mov dword [outbuf],0 

Или в конце концов, если у вас есть уже ноль в некоторых 32b регистре:

xor eax,eax 
mov [inbuf],ax 
mov [inbuf+2],al 
mov [outbuf],eax 

Вы можете получить доступ к памяти только для питания из-двух размеров, и только некоторые из них, в 32б режиме: 1, 2 и 4 с целочисленной арифметикой общего назначения.

И 8 или 10 с FPU. О да, 10 - это не сила двух, я знаю, это особенный только для некоторых вещей FP.

И тогда есть различные инструкции SIMD, которые могут получить доступ даже к 128/256/512 битам (16,32 и 64 байта).

Тогда неарифметические специальные инструкции могут иногда использовать дополнительные дополнительные размеры, например 5 или 6, возможно (я даже не уверен) с некоторыми прыжками и т. Д. ... Вообще-то я бы не считал их даже как исключение, так как все декодирование команд x86 использует подход с переменной байтовой суммой, а номинальный размер равен 1B, поэтому он не имеет степеней двух в этой части.

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

Иногда люди растягивают его до сих пор, что даже видеокамера, состоящая из данных RGB, выровнена на 32 бита на пиксель, теряя каждый четвертый байт за «ничего», только как дополнение (25% VRAM потрачено впустую, и он вернулся во время, когда оперативная память была дорогой).

(Ранние режимы SVGA VESA имели также 24-битные режимы работы с памятью, но поскольку адресация на пиксель составляет * 3, это было очень неприятно для использования в коде или даже ускорителями HW ... в настоящее время это помогает большая часть использования видеопамяти для текстур, где 4-ый байт может хранить альфа- или другую дополнительную информацию для пиксельных шейдеров, так что это не более впустую память, но размер 32 бит)


И как загрузить 3B значение из памяти:

Для общей нагрузки 3B, которая должна работать все время:

movzx eax,byte [inbuf+2] 
shl eax,16 
mov ax,[inbuf] 

И когда вы знаете, что значение 3B не в конце страницы памяти с последующим ограниченной страницей памяти (так что значение либо по адресу выровненного по 4, или всегда есть другая правовая страница памяти после него):

mov eax,[inbuf]  ; loads desired 3B + 1B garbage 
and eax,0x00FFFFFF ; truncate it to 3B only 

(это может привести к сбою на границе страницы с последующей памятью, когда следующая страница памяти ограничена, например, если «inbuf» - это адрес 4093, а адрес 4096 ограничен этим процессом => сбои в доступе к нелегальной памяти, но это обычно не где вы бы определили «inbuf», поэтому этот более короткий вариант обычно показан как правильное решение, без этого глупого длинного объяснения, когда оно фактически может).

+0

+1 для решения проблемы с шестнадцатеричным размером. 'mov word [inbuf], 0 mov byte [inbuf + 2], 0' кажется хорошим решением. –

+0

@JoeCocker: произвольный непрерывный блок памяти также может быть обнулен символом 'rep stos [b/w/d]', например, чтобы очистить 312B от «outblock»: 'mov edi, outblock | xor eax, eax | mov ecx, 312/4 | rep stosd' .. если адреса выровнены, а размер нетривиальный, это может быть самым быстрым способом. Для фиксированных размеров, таких как 3 или 64, либо несколько «mov byte/word/dword [aligned_address], 0' лучше для более коротких размеров, так как дольше, чем 64B, может быть какой-то SIMD-вариант. Обычно для более крупных учетных записей «rep stosd» находится на одном уровне с оптимизированными решениями SIMD, поскольку он будет внутренне перекомпилирован в ~ оптимальную подпрограмму uops. – Ped7g

+3

BTW обратите внимание на повторяющуюся тему выравнивания адреса и размеры, делящиеся по силе двух (не менее 4 или более). Это имеет большие последствия для производительности, когда это разумно, делает ваши данные наземными границами 4/8/16 байт и имеет такой размер, так что, например, 3B inbuf будет 4B inbuf почти все время, и только там, где размер 3B действительно (например, сохранение байтов в файл или отправка его на некоторое периферийное устройство), будет использоваться 3B. В противном случае 4-й байт-мусор будет использоваться вместе, когда это возможно, чтобы «набить» его размером до 4B. – Ped7g

Смежные вопросы