Почему загрузка EAX из массива байтов не соответствует ожидаемому мной литералу?

Я новичок в сборке и пытался работать с массивом. Однако меня поймали при попытке сравнить значение массива с константой, хранящейся в регистре.

Судя по следующему коду, я ожидал, что программа перейдет после сравнения, поскольку значение в массиве, похоже, соответствует литералу в esi. Мой код выглядит следующим образом.

global _start
section .data
         yay: db "It Worked!",0xA
         array1: db 1, 2, 3, 4
 section .bss

section .text
         _start:
                  mov eax, [array1 + 1]
                  mov esi, 2
                  cmp eax, esi
                  je .equal
                  jmp _done
 
          .equal:
                  mov eax, 4
                  mov ebx, 0
                  mov ecx, yay
                  mov edx, 11
                  int 0x80
                  jmp _done
 
          _done:
                  mov eax, 1
                  mov ebx, 0
                  int 0x80

Буду очень признателен за любые советы относительно ошибок в моем коде!

db представляет собой массив байтов, как и адресация + 1. Итак, mov eax, [array1 + 1] неверен, поскольку загружает двойное слово (4 байта). Либо переключитесь на dd и mov eax, [array1 + 4], либо используйте movzx eax, byte [array1 + 1].
ecm 18.07.2024 07:01

Или сравните 0x00040302, который вы видите с помощью отладчика, — это значение, которое вы загрузили в EAX. Обратите внимание, что младший байт — это 2, старшие байты — это более поздние элементы массива (поскольку x86 имеет прямой порядок байтов). Я предполагаю, что компоновщик заполнен хотя бы одним 0 после окончания .data.

Peter Cordes 18.07.2024 07:11

Не связано с ошибкой: не знаю насчет насма, но для масма после : не должно быть array1.

rcgldr 18.07.2024 13:09

@rcgldr NASM всегда принимает двоеточие после метки.

ecm 18.07.2024 14:28

@ecm Использует ли mov eax, [array + 1] dword из-за размера eax или что-то еще?

Jeremy 18.07.2024 14:53

@Jeremy Да, eax — это 32-битный регистр, поэтому, когда он соединен с операндом памяти, этот операнд памяти также является 32-битным (что равно dword). За исключением movzx и movsx, которые предназначены для расширения грузов. Вы можете написать свою инструкцию как mov eax, dword [array + 1], чтобы указать размер в NASM явно, если вы хотите получить доступ к dword.

ecm 18.07.2024 15:28

@ecm — является ли двоеточие после метки данных необязательным в nasm? В masm без двоеточия вы получаете тип и размер массива, с двоеточием — это просто смещение без типа и размера.

rcgldr 18.07.2024 18:20

@rcgldr Двоеточие необязательно. NASM не различает метки «данные» и метки «код». Этикетки в NASM никогда не имеют типа или размера. Метка без двоеточия и другого текста (без комментариев) в строке вызывает предупреждение orphan-label: nasm.us/xdoc/2.16.03/html/nasmdoca.html Я пытался добавить более общее label-no-colon предупреждение, но оно еще не объединено: bugzilla.nasm.us/show_bug.cgi?id=3392632

ecm 19.07.2024 06:59
Структурированный массив Numpy
Структурированный массив Numpy
Однако в реальных проектах я чаще всего имею дело со списками, состоящими из нескольких типов данных. Как мы можем использовать массивы numpy, чтобы...
T - 1Bits: Генерация последовательного массива
T - 1Bits: Генерация последовательного массива
По мере того, как мы пишем все больше кода, мы привыкаем к определенным способам действий. То тут, то там мы находим код, который заставляет нас...
Что такое деструктуризация массива в JavaScript?
Что такое деструктуризация массива в JavaScript?
Деструктуризация позволяет распаковывать значения из массивов и добавлять их в отдельные переменные.
0
8
89
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Причина, по которой ваш код неправильно загружает значение, расположенное по первому индексу вашего массива, в EAX, заключается в том, что массив находится в сборке. В ассемблере, когда вы определяете «массив», вы просто помещаете данные в память. Хотя это может показаться очевидным, это также означает, что между элементами НЕТ разделителя («строка» также является массивом). Это означает, что когда вы выполняете MOV EAX, [ARRAY1 + 1] без указания размера операции, nasm просматривает контекст инструкции, чтобы определить размер. Поскольку вы используете 32-битный регистр, размер по умолчанию равен DWORD. Это означает, что инструкция загрузит 32 бита (4 байта) из вашего массива, начиная с [ARRAY1 + 1]. Чтобы предотвратить это, вам нужно указать размер вашей операции в байтах, выполнив MOVZX EAX, BYTE [ARRAY1 + 1]. Вам нужно использовать MOVZX, чтобы заполнить остальную часть регистра нулями.

Общие советы

Первое, что мне бросается в глаза в вашем коде, это использование JMP прямо перед меткой, по которой вы переходите. В этом нет необходимости, поскольку выполнение продолжится до метки. Это связано с тем, что метки — это не «функции», а просто маркеры, представляющие адреса памяти. В собранной программе их нет. Во-вторых, хотя это и не важно, вместо MOV EAX, 0 это выполняется немного быстрее XOR EAX, EAX. Наконец, у вас есть пустой раздел BSS, он не нужен компоновщику и его можно просто оставить (по крайней мере, для ld).

«размер по умолчанию равен WORD». Неверно, на 386 из-за происхождения 8086 word — это то, что мы называем 16-битной величиной, и, следовательно, double word или dword — это 32-битная величина. Регистр eax имеет размер dword.

ecm 23.07.2024 17:49

Да, спасибо, что отметили это

M VR 24.07.2024 01:10

Другие вопросы по теме