Как преобразовать 32-битную встроенную сборку Linux в 64-битный код?
Я пытаюсь преобразовать RR0D Rasta Ring 0 Debugger из 32-битного режима в 64-битный режим (длинный режим) в Linux, используя gcc. Я знаком с 32-битной сборкой x86 (в среде MS-DOS), но я новичок в 64-битной сборке x86 и в программировании на ассемблере Linux в целом.
Этот проект предназначен для производственного использования (мне нужен работающий не исходный отладчик), но я также пытаюсь научиться выполнять преобразование 32-разрядных в 64-разрядные. Если возможно, я пытаюсь найти универсальный способ сделать 32-битное в 64-битное преобразование, которое можно было бы сделать в любой 32-битной программе с использованием регулярных выражений (чтобы его можно было автоматизировать). Я знаю, что не существует общего решения (64-битный код может занимать больше места, чем 32-битный код и т. Д. И потреблять больше стека и т. Д.), Но даже в этом случае автоматически преобразованный код будет служить отправной точкой.
Идея состоит в том, чтобы сохранить 8-битные и 16-битные операнды как есть, и заменить 32-битные операнды 64-битными операндами. Этот подход, естественно, потерпит неудачу, если pushw %ax; pushw %bx; popl %ecx
заменяется на pushw %ax; pushw %bx; popq %rcx
, но программы с хорошим поведением обычно не push
два 16-битных операнда, а затем pop
один 32-битный операнд, или они?
Это преобразования на данный момент:
Редактировать: Исправить: pusha
/ pushad
можно заменить последовательным push
потому что pusha
/ pushad
Команды выдвигают значение sp
/ esp
до фактического толчка sp
, а также push sp
работает аналогично в 286+, но по-разному в 8088/8086 базе данных языка ассемблера. Эта разница не проблема здесь (для кода 386+). pusha
а также pushad
Таким образом, может быть заменен последовательным push
команды.
Альтернатива похожа на OpenSolaris privregs.h
код
Редактировать: Исправить: использовать 64-битную адресацию памяти для всех команд.
pusha
->push %ax; push %cx; push %dx; push %bx; push %sp; push %bp; push %si; push %di
,Редактировать: Исправить: допустимая альтернатива (используя
lea
Обратите внимание, что процессоры x86 имеют младший порядок:pusha
->movq %rax, -8(%rsp); lea -8(%rsp), %rax; mov %ax, -10(%rsp); movq -8(%rsp), %rax; movw %cx, -4(%rsp); movw %dx, -6(%rsp); movw %bx, -8(%rsp); movw %bp, -12(%rsp); movw %si, -14(%rsp); movw %di, -16(%rsp); lea -16(%rsp), %rsp
,pushad
->push %rax; push %rcx; push %rdx; push %rbx; push %rsp; push %rbp; push %rsi; push %rdi
,Редактировать: Исправить: допустимая альтернатива (используя
lea
):pushad
->movq %rax, -8(%rsp); movq %rcx, -16(%rsp); movq %rdx, -24(%rsp); movq %rbx, -32(%rsp); lea -32(%rsp), %rax; movq %rax, -40(%rsp); movq -8(%rsp), %rax; movq %rbp, -48(%rsp); movq %rsi, -56(%rsp); movq %rdi, -64(%rsp); lea -64(%rsp), %rsp
,Редактировать: Исправить:
popa
а такжеpopad
поп значениеsp
/esp
но откажитесь ( набор инструкций Intel - popa / popad). Давайтеpop
это вbx
/rbx
,popa
->popw %di; popw %si; popw %bp; popw %bx; popw %bx; popw %dx; popw %cx; popw %ax
,popad
->popq %rdi; popq %rsi; popq %rbp; popq %rbx; popq %rbx; popq %rdx; popq %rcx; popq %rax
,pushfd
->pushfq
,popfd
->popfq
,Редактировать:
push
сегментных регистров, например.pushw %ds
->pushw %ax; pushw %ax; movw %ds, %ax; movw %ax, 2(%rsp); popw %ax
,Редактировать:
pop
сегментных регистров, например.popw %ds
->pushw %ax; movw 2(%rsp), %ax; movw %ax, %ds; popw %ax
,Редактировать:
inc %reg16
->add $1, %reg16
напримерinc %ax
->add $1, %ax
,Редактировать:
dec %reg16
->sub $1, %reg16
напримерdec %ax
->sub $1, %ax
,Редактировать:
inc %reg32
->add $1, %reg64
напримерinc %eax
->add $1, %rax
,Редактировать:
dec %reg32
->sub $1, %reg64
напримерdec %eax
->sub $1, %rax
,Редактировать:
aaa
->?Редактировать:
aad
->?Редактировать:
aam
->?Редактировать:
aas
->?Редактировать:
arpl
->?Редактировать:
bound
->?Редактировать:
daa
->?Редактировать:
das
->?Редактировать:
lahf
->?Редактировать:
sahf
->?Исправление редактирования: любая команда с прямым операндом, которая не соответствует размеру 32-битного операнда в 64-битном режиме, например.
pushl $0xDEADBEEF
->pushq %rax; pushq %rax; movq $0xDEADBEEF, %rax; movq %rax, 8(%rsp); popq %rax
,ret
с непосредственным операндом: я думаю, что в этом случае исходный код должен быть возвращен, чтобы увидеть размеры последнегоpush
операнды и действуют соответственно, например.pushl %eax; ret 4
->pushq %rax; ret 8
,Редактировать:: syscalls:
int $0x80
->pushq %rdi; movq %rbp, %r9; movq %rdi, %r8; movq %rbx, %rdi; xchgq %rcx, %rsi; -- replace %rax value using a substitution list --; syscall; popq %rdi; xchgq %rcx, %rsi
(примечание: 32-разрядные системные вызовы могут иметь более 6 параметров, 6 в регистрах и остальные в стеке, 64-разрядные системные вызовы могут никогда не иметь более 6 параметров).
Редактировать: Что еще следует учитывать? Какие другие преобразования потребуются для преобразования 32-битного кода в 64-битный код (для запуска в длинном режиме)?