2016-03-01 8 views
0

Мой первоначальный вопрос назначения заключается в следующем:Big Endian в Little Endian

Write a program that uses the variables below and MOV instructions to copy the value from bigEndian to littleEndian, reversing the order of the bytes. The number's 32 - bit value is understood to be 12345678 hexadecimal.

.data 
bigEndian BYTE 12h, 34h, 56h, 78h 
littleEndian DWORD? 

Я думаю, что мой код правильный, но я не могу понять, почему я получаю эту ошибку. Вот мой код и ошибка:

.386 
.model flat, stdcall 
.stack 4096 
ExitProcess PROTO, dwExitCode:DWORD 

.data 
bigEndian BYTE 12h, 34h, 56h, 78h 
littleEndian DWORD ? 
.code 
main PROC 
mov eax, DWORD PTR bigEndian; eax = 87654321h 
mov littleEndian, eax 

invoke ExitProcess, 0 
main ENDP 
END main 

1>------ Build started: Project: BigEndianLittleEndian, Configuration: Debug Win32 ------

1> Assembling BigEndiantoLittleEndian.asm...

1>BigEndiantoLittleEndian.asm(20): error A2008: syntax error

1>C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\V140\BuildCustomizations\masm.targets(50,5): error MSB3721: The command "ml.exe /c /nologo /Zi /Fo"Debug\BigEndiantoLittleEndian.obj" /W3 /errorReport:prompt /TaBigEndiantoLittleEndian.asm" exited with code 1.

========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

Как я могу исправить эту ошибку?

Here is updated code:

.386 
.model flat, stdcall 
.stack 4096 
ExitProcess PROTO, dwExitCode:DWORD 

.data 
bigEndian BYTE 12h, 34h, 56h, 78h 
littleEndian DWORD ? 


.code 
main PROC 

mov ah, byte ptr bigEndian+0 
mov al, byte ptr bigEndian+1 
mov word ptr littleEndian+2,ax;here I want to move my now full register into  the 32bit register eax. 
mov ah, byte ptr bigEndian+2 
mov al, byte ptr bigEndian+3 
mov word ptr littleEndian+2,ax here I want to move my now full register into the 32bit register eax which results in the order being reversed. 


invoke ExitProcess, 0 
main ENDP 
END main 

Я получаю ошибку

1>------ Build started: Project: BigEndianLittleEndian, Configuration: Debug Win32 ------

1> Assembling BigEndiantoLittleEndian.asm...

1>C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\V140\Microsoft.CppCommon.targets(708,9): error MSB4030: "main" is an invalid value for the "NoEntryPoint" parameter of the "Link" task. The "NoEntryPoint" parameter is of type "System.Boolean".

========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

+1

Я не вижу код для обратного байтов.Я предполагаю, что ваша ошибка ASM исходит из первого выражения mov. – user3344003

+1

'mov eax, DWORD PTR bigEndian, eax = 87654321h' будет проблемой. 'mov' принимает 2 операнда. Не 3. Не знаете, что такое ', eax = 87654321h'. –

+0

Вы посмотрели на строку, которая выдает ошибку? –

ответ

2

Вы должны фактически поменять байты в eax перед записью на память:

mov eax,DWORD PTR bigEndian 
bswap eax 
mov littleEndian,eax 

Используя исключительно mov инструкции это может быть например:

mov al,DWORD PTR bigEndian+0 
mov ah,DWORD PTR bigEndian+1 
mov bl,DWORD PTR bigEndian+2 
mov bh,DWORD PTR bigEndian+3 

mov littleEndian+0,bh 
mov littleEndian+1,bl 
mov littleEndian+2,ah 
mov littleEndian+3,al 
+0

Вопрос заключается в использовании команд 'MOV'. Я думаю, что исключает 'BSWAP' –

+0

Он не говорит, что не использует никаких других инструкций :) – lvd

+0

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

1

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

; Description: Copy value from bigEndian to littleEndian, reversing order of bytes 
; Assignment: A06B 4.10 Programming Exercise 
; Date: 3/17/2016 

INCLUDE Irvine32.inc 

.data 
bigEndian  BYTE   12h, 34h, 56h, 78h 
littleEndian DWORD   ? 

.code 
main   PROC 
       mov  al, [bigEndian+3]  ;swap 78h and 12h 
       mov  ah, [bigEndian]  
       mov  [bigEndian], al 
       mov  [bigEndian+3], ah 

       mov  al, [bigEndian+2]  ;swap 56h and 34h 
       mov  ah, [bigEndian+1] 
       mov  [bigEndian+1], al 
       mov  [bigEndian+2], ah 

       mov  eax, DWORD PTR bigEndian ;move reverse ordered bytes to eax 
       mov  littleEndian, eax  ;move reverse ordered byted to littleEndian 
       invoke ExitProcess, 0 
main   ENDP 
END main 
+0

Вы меняете -place в 'bigEndian', уничтожая его первоначальное значение, а затем справляясь с этим с« littleEndian », что странно. Что касается эффективности, то для 32 и 64-битных операндов 'bswap r32' или' bswap r64' делает это и быстро. Для 16-битных операндов 'rol r16, 8' делает это более эффективно, чем' xchg al, ah'. Для Atom и Haswell «movbe» делает это «на лету» как часть нагрузки или магазина. –

+0

Без bswap оптимальным способом может быть что-то вроде загрузки первого 16b, перевернуть его с помощью 'rol ax, 8', поместить его в верхний 16 с помощью' shl eax, 16', затем загрузить и перевернуть высокий 16b источника , Тем не менее, это повлечет за собой неполный учет. Или загрузите 32b, 'rol ax, 8' /' rol eax, 16'/'rol ax, 8' делает то же самое только с одной загрузкой, но с более длинной цепочкой зависимостей. Если вам не нужен результат в 32-битном регистре, то, вероятно, лучше всего две пары load/'rol ax, 8'/store. –

+1

@PeterCordes: Первоначальный вопрос сказал, что они должны были использовать инструкции MOV. –

1

Я пришел с тем, что кажется лучшим способом решить проблему. Он по-прежнему придерживается ограничений только с использованием команд MOV, но он не разрушает исходное значение массива.

INCLUDE Irvine32.inc 

.data 
bigEndian  BYTE 12h, 34h, 56h, 78h 
littleEndian DWORD ? 

.code 
main   PROC 
    mov esi, OFFSET bigEndian 
    mov eax, 0 
    mov al, [esi+3]  ;Isolate 5678h 
    mov ah, [esi+2] 
    mov ebx, 0 
    mov bl, [esi+1]  ;Isolate 1234h 
    mov bh, [esi] 

    mov esi, OFFSET littleEndian 
    mov [esi], eax  ;Move 5678h into lower 16bits of littleEndian 
    mov [esi+2], ebx ;Move 1234h into higher 16bits of littleEndian  
    invoke ExitProcess, 0 
main  ENDP 
END main 
+0

'mov [esi + 2], ebx' - это хранилище dword, которое записывается в конце' littleEndian'.Я думаю, вы хотите 'mov [esi + 2], bx'. Кроме того, 'mov eax, 0' [должен быть' xor eax, eax'] (https://stackoverflow.com/questions/33666617/what-is-the-best-way-to-set-a-register-to -zero-in-x86-assembly-xor-mov-or-and), или его следует опустить полностью, поскольку все, что он делает, это разбить зависимость от старого значения. Это все еще не предотвращает слияние парных регистров на P3/Core2/Nehalem для чтения более широкого регистра после записи небольших частей отдельно, но это хорошо для других процессоров. –

0

У меня на самом деле было это одно и то же задание, подумал, что я отправлю свой ответ здесь. Существует способ поменять байты, используя указатели и команду OFFSET. LittleEndian применяется только при записи байтов в память. Это означает, что при запуске следующего кода eax будет удерживать обратные байты bigEndian.

< LittleEndian => BigEndian

mov ebx,OFFSET bigEndian 
mov eax, [ebx] 

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

Вы можете получить доступ к каждому байту bigEndian отдельно, используя смещения bigEndian + 0 -> bigEndian + 3, но, учитывая, что мы объявили littleEndian после bigEndian, память была выделена для littleEndian сразу после bigEndian. Это означает, что если мы смещаем смещения bigEndian + 4 -> bigEndian + 7, мы можем напрямую обращаться к littleEndian, используя небольшие 8-битные приращения. Я воспользовался этим и использовал его в своем коде.

EDIT: Вот конечный результат

.386 
.model flat,stdcall 
.stack 4096 
ExitProcess proto,dwExitCode:dword 
INCLUDE Irvine32.inc 
.data 

    bigEndian BYTE 12h, 34h, 56h, 78h 
    littleEndian DWORD ? 

.code 
main proc 

    ; You can swap them by taking advantage of when littleEndian is applied to variables in memory. 
    ; Since we are limited to only mov operators, we cannot use this code. But it's nice to have for the future. 
    ; mov ebx,OFFSET bigEndian 
    ; mov eax, [ebx] 

    ; Display bigEndian 
    mov ebx, 1 ;set to write eax al 8 hex digits using WriteHexB 
    mov al, bigEndian+0 
    call WriteHexB 
    mov al, bigEndian+1 
    call WriteHexB 
    mov al, bigEndian+2 
    call WriteHexB 
    mov al, bigEndian+3 
    call WriteHexB 
    call CrlF 

    ; Since bigEndian was declared before littleEndian, bigEndian only goes as far as bigEndian+3 
    ; However, since littleEndian was declared after, we can traverse littleEndian using bigEndian+4 -> bigEndian+7. 
    ; Considering we cannot move data from memory to memory, we have to use an 8-bit register as a buffer. 
    ; We will use al register. 

    ; bigEndian = 12345678h, littleEndian = 00000000h 

    mov al, bigEndian+0 
    mov bigEndian+4, al 

    ; bigEndian = 12345678h, littleEndian = 00000012h 

    mov al, bigEndian+1 
    mov bigEndian+5, al 

    ; bigEndian = 12345678h, littleEndian = 00003412h 

    mov al, bigEndian+2 
    mov bigEndian+6, al 

    ; bigEndian = 12345678h, littleEndian = 00563412h 

    mov al, bigEndian+3 
    mov bigEndian+7, al 

    ; bigEndian = 12345678h, littleEndian = 78563412h 



    ; Write littleEndian to eax to display on screen 
    mov eax, littleEndian 

    ; Display littleEndian 
    call WriteHex 
    call CrlF 

    ; Display 'Press [enter] to continue...' 
    call WaitMsg 

    invoke ExitProcess,0 
main endp 
end main  
+0

Нет, это не то, как работает MOV, и стеки не имеют к этому никакого отношения. Ваш 'mov littleEndian, eax' хранит большие данные в' littleEndian', потому что вы не сделали ничего, чтобы преобразовать его после загрузки в 'eax'. Парочка «mov» load/store не перетасовывает данные, а просто копирует. Вы загрузили все по одному байту за раз (перед его печатью), но вы выбросили его, не сохраняя его. –

+0

Чтобы «надавить» байты в регистр, вы будете «movzx eax, byte ptr [bigendian]'/'shl eax, 1' /' mov al, [bigEndian + 1] '/ ... Тогда у вас будет родные данные в регистре, чтобы вы могли «mov [littleEndian], eax' –

+0

Тогда почему это работает? Я был уверен, что сначала был прав (был выстрел в темноте), но если бы я напечатал bigEndian в целом, я бы получил 12345678h, но после mov ebx, OFFSET bigEndian и mov eax, [ebx] он находится в обратном порядке заказ. Я могу буквально распечатать eax, и это будет 78563412h. Единственный способ, которым я мог это объяснить, это то, что он действует как стек, и я просто выскакивал стек. –