MOV для регистрации из памяти не работает с битами 32 в NASM - PullRequest
0 голосов
/ 03 февраля 2019

Я только начинаю с сборки x86 и пробовал некоторые основы с инструкцией MOV.(код ниже)

BITS 32

SECTION .data                   
    somedata: db "Hello world",10

SECTION .text                   
    global _start                   
_start: 
    mov eax, somedata
    mov al, [eax]
    mov edx, [somedata]

Кажется, я не понимаю, почему nasm использует RIP относительную адресацию , когда указано BITS 32 в сборке (я думал относительная адресация только в 64-битном режиме).Более того, он использует RAX в 32-битном режиме .Если я ничего не указываю, то, похоже, не использует относительную адресацию и использует EAX.

Код с битами 32

Disassembly of section .text:

00000000004000b0 <_start>:
  4000b0:   b8 c0 00 60 00          mov    eax,0x6000c0
  4000b5:   8a 00                   mov    al,BYTE PTR [rax]
  4000b7:   8b 15 c0 00 60 00       mov    edx,DWORD PTR [rip+0x6000c0]        # a0017d <_end+0x4000ad>

Код без битов 32

Disassembly of section .text:

00000000004000b0 <_start>:
  4000b0:   b8 c0 00 60 00          mov    eax,0x6000c0
  4000b5:   67 8a 00                mov    al,BYTE PTR [eax]
  4000b8:   8b 14 25 c0 00 60 00    mov    edx,DWORD PTR ds:0x6000c0

Я знаю, что это не ассемблер, это я.Что я делаю не так?

PS:

  • Используя nasm и 64-битный компьютер с Linux.

  • Сборка с использованием nasm -f elf64 -F stabs -g sandbox.asm -o sandbox.o

  • Разборка с использованием objdump -M intel -d sandbox

Я также попробовал следующие флаги ассемблера и компоновщика:

nasm -f elf32 -F stabs -g sandbox.asm -o sandbox.o
ld -oformat=elf32-i386 -o sandbox sandbox.o

но это не работает, говоря ld: i386 architecture of input file `sandbox.o' is incompatible with i386:x86-64 output

Ответы [ 2 ]

0 голосов
/ 04 февраля 2019

TL: DR: Никогда не используйте директиву BITS, если это не необходимо .

Директива BITS не изменяет тип выходного файла, выбранный с помощью -felf64 или -felf32.(-felf является синонимом -felf32, если вы когда-либо видели, что используется в примерах.)

Для создания 32-разрядных статических исполняемых файлов я использую сценарий оболочки asm-link, который в итоге делает это:

nasm -felf32 -g -Fdwarf foo.asm   &&
ld -melf_i386 -o foo foo.o

Формат отладки stabs устарел, хотя, пока ваш отладчик поддерживает его, он, вероятно, подходит для отображения строк исходного кода asm в инструкции asm.В любом случае, -Fstabs является значением по умолчанию, если вы используете -g.(Я не читал все это, но https://www.ibm.com/developerworks/library/os-debugging/index.html имеет некоторую информацию о STAB против DWARF.)


В большинстве случаев директива BITS в лучшем случае бесполезнав худшем случае активно вредно. Вместо такой полезной ошибки, как push ebx, которая не кодируется, если вы пытаетесь встроить 32-битный код в 64-битный объектный файл, он позволяет таким вещам происходить.(Хотя это не спасло бы вас здесь, потому что весь этот код собирался обоими способами.)

Единственное время, когда BITS полезно, это когда вы хотите использовать nasm -fbinи создайте плоский двоичный файл, который вы можете передать ndisasm или использовать в качестве шелл-кода, или сами определите ELF или любые другие заголовки метаданных с помощью db ( Учебное пособие по вихревому созданию действительно исполняемых ELF-исполняемых файлов для Linux ).nasm не предоставляет параметр командной строки для изменения режима BITS 16 по умолчанию для -fbin.

Или, если вы действительно хотите смешать 16, 32 и 64-битный кодв файле, который загружается в 16-битном режиме и переключается в 64-битный режим: это основной вариант использования для BITS. или для включения некоторого BITS 32 или BITS 16 машинного кода в качестве данных в вашем 64-битном исполняемом файле.


Не вставляйте строку BITS 32 в верхней части файла как часть шаблона, это не поможет или не поможет. Используйте комментарий типа ;;; 32-bit x86 Linux code, NASM syntax, если хотите описать, что находится в этом исходном файле и как его можно построить / запустить.

Вы можете и должны использовать DEFAULT REL хотя, поэтому, если вы создаете 64-битный код, вы получите относительные к RIP режимы адресации для операндов памяти, таких как [somedata] (имя символа без регистров GP).Это на один байт короче, чем 32-разрядные режимы абсолютной адресации, и будет работать в исполняемом файле PIE.

Интересный факт: 32-разрядный режим имеет 2 избыточных способа кодирования [disp32] режимов абсолютной адресации.x86-64 переназначил более короткий (без байта SIB) как RIP-относительный. Именно поэтому ваша 64-битная разборка 32-битного машинного кода имеет DWORD PTR [rip+0x6000c0], где rel32 - абсолютный адрес символа.

0 голосов
/ 03 февраля 2019
nasm -f elf64 -F stabs -g sandbox.asm -o sandbox.o

Это всегда приводит к выполнению 64-битного исполняемого файла ELF, независимо от того, что вы помещаете в него 32-битный код.Это приводит к тому, что дизассемблер декодирует ваш 32-битный машинный код, как если бы он был 64-битным кодом, отсюда и странные результаты.Тот факт, что дизассемблирование напоминает исходный код, является просто совпадением, вытекающим из того факта, что кодирование команд в 64-битном режиме очень похоже или даже совпадает (возможно, изменяя размер регистра по умолчанию) с 32-битным эквивалентом.

Используйте -f elf32, чтобы получить 32-битный исполняемый файл ELF.

...