Сборка x86 для новичков: проблема с добавлением и хранением чисел - PullRequest
0 голосов
/ 26 марта 2012

Здравствуйте, я новичок в сборке и пытаюсь заставить работать программу из двух частей. Я использую Visual Studio для этой сборки x86.

часть I) Моя первая цель - подсчитать до 13, добавив каждое значение по пути туда. Например, 0 + 1 + 2 + 3 ... + 13 = 91. Я хочу сохранить эту сумму в общей сложности.

часть 2) Во-вторых, я хочу подсчитать по степеням 2 от 2 ^ 0 до 2 ^ 6. Например, 0,1,2,4,8,32,64. Я думаю, что * я делаю это, но я не храню каждое значение на ходу. Я хочу хранить их в последовательных ячейках памяти.

Пока у меня есть,

.586
.MODEL FLAT

.STACK 4096

.DATA
num1 BYTE 13          ;Initialize number to count to
totall BYTE 0         ;Total of all counted numbers
temp BYTE 0           ;Temp for loop adding

shiftme BYTE 1        ;Start of counting 2^0 so I can reach 2^6

.CODE
main PROC
;code here

increment:            ;Increment label
inc temp              ;Increment temp by 1
mov eax, temp
add totall, eax       ;Add temp+totall and store in totall
cmp eax, num1         ;Compare for jump
jne increment         ;Jump if not equal

;this part should store each value 1,2,4,8,32.. in consecutive memory locat
shiftallthethings:    ;Shift label
shl shiftme, 1        ;Shifting bits to the left one
cmp shiftme, 64       ;Comparing for the jump
jne shiftallthethings ;Jump if not equal to

ret
main ENDP
END

Вопросы, которые помогут мне понять.

  • Как хранить значения в последовательных ячейках памяти?
  • Правильно ли я использую инструкции перехода и метки?
  • Нужно ли использовать определенные регистры, такие как eax, для решения этих проблем? Почему?

Любая помощь приветствуется, спасибо.

1 Ответ

2 голосов
/ 27 марта 2012

Прежде всего, в ответ на ваши вопросы:

Как хранить значения в последовательных ячейках памяти?

В MASM32 вы можете либо напрямую сделать mov, как mov sum_addr, eax (при условии, что типы данных имеют одинаковый размер), либо вы можете передавать указатели данных. В примере, который я написал, указатель на total передается функции. Затем функция записывает значение в память, на которую указывает этот указатель (то есть содержимое total). Не совсем уверен, что вы подразумеваете под последовательными ячейками памяти. Если вы имеете в виду арифметику указателей, я могу показать вам пример этого.

Правильно ли я использую инструкции перехода и метки?

Да, похоже, все в порядке. Альтернативой, которую я использую, являются анонимные ярлыки. Это уместно, когда метка тривиальна и довольно близка. Это личное предпочтение. Если вы считаете, что название метки более уместно, не стесняйтесь использовать его тоже.

Нужно ли использовать определенные регистры, такие как eax, для решения этих проблем? Почему?

MASM32 следует соглашению о вызовах Win32 (stdcall), так что это также хорошо для вас. С точки зрения сохранения регистров это означает, что ожидается, что все функции сохранят регистры, кроме eax, ecx и edx, которые считаются пересылаемыми. Возвращаемые значения сохраняются в eax или eax и edx, если требуется более 4 байтов.


С точки зрения написанного вами кода у вас есть несколько проблем, таких как попытка переместить типы данных разного размера друг в друга. Например, если вы переместите byte в dword, вы должны сначала расширить его до того же размера.

mov eax, temp

Это не скомпилируется, потому что temp имеет длину всего 1 байт, тогда как eax составляет 4 байта. Вы можете сделать вместо этого:

movzx eax, temp

Это ноль расширяется temp перед выполнением движения. Вот код, который я собрал вместе, который может научить вас нескольким вещам. Он использует макросы (не уверен, если вы хотите их изучить), но в противном случае демонстрирует идиоматическую передачу параметров MASM32 и возвращаемые значения.

include \masm32\include\masm32rt.inc

.DATA

total DWORD 0         ;Total of all counted numbers

.CODE

; takes in address of total and writes the value there
sum PROC sum_addr:DWORD

xor eax, eax
xor ecx, ecx

  @@:
inc ecx
add eax, ecx
cmp ecx, 13
jnz @b

mov edx, sum_addr
mov dword ptr ds:[edx], eax
print ustr$(eax), 13, 10

mov edx, sum_addr
mov eax, dword ptr ds:[edx]
ret

sum ENDP

start:

push offset total          ; pass address of total
call sum
print ustr$(eax), 13, 10   ; demonstrating how to use return values

print ustr$(total), 13, 10 ; testing result got stored properly
ret

end start
END

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

...