Предлагаемые ответы здесь верны, но есть недостающая часть: предложенный синтаксис не создает длинный прыжок. Я сделал так, как Margaret Bloom предложил, но это не сработало. В моем коде должно быть что-то не так, так как я знаю, что она дала мне правильный ответ, так как другие также предлагают одно и то же. Глядя на GDB, когда я применил выше синтаксис:
asm("pushw 0xa0");
asm("pushd 0x0");
asm("jmp far [esp]");
(приведенный выше синтаксис встроенный ассемблер, GCC, стиль)
Глядя на GDB, jmp far
генерируется как:
0x30a9 <task1_start+1> mov ebp,esp
0x30ab <task1_start+3> pushw 0xa0
0x30af <task1_start+7> push 0x0
0x30b1 <task1_start+9> jmp DWORD PTR [esp+0xff06]
Очевидно, , [esp + 0xff06]
не выглядит очень далеко от меня. Это близкий прыжок со смещением от esp
. Более очевидно, с выходом objdump
:
000030a8 <task1_start>:
30a8: 55 push %ebp
30a9: 89 e5 mov %esp,%ebp
30ab: 66 68 a0 00 pushw $0xa0
30af: 6a 00 push $0x0
30b1: ff a4 24 06 ff 00 00 jmp *0xff06(%esp)
30b8: 90 nop
30b9: 5d pop %ebp
30ba: c3 ret
Обратите внимание на опкод в 0x30ab
, что соответствует jmp
инструкции. Глядя на руководство Intel, этот опкод для близкого перехода:
0xff
означает jmp
инструкции.
0xa4
- это ModR/M байт для [--][--] + disp32
эффективный адрес для esp
. Это означает, что требуется байт SiB, который является смещением. (ссылка: Таблица 2-2. 32-битные формы адресации с байтом ModR/M)
0x24
- это байтовые байты SiB
для ESP, но без какого-либо масштабирования (значение none
), эффективно, сохраняйте его. (ссылка: Таблица 2-3. 32-битные формы адресации с байтом SIB).
выше генерируется jmp
соответствует FF /4
опкода (ссылка: jmp instruction), что означает почти скачок, так как генерируется ModR/М байт 0xa4
. Правильный код операции для дальнего прыжка - FF /5
.
Очевидно, что я должен сделать что-то для ассемблера, чтобы генерировать длинный прыжок. Таким образом, оказалось, что это легко исправить с помощью ljmp
инструкции вместо jmp far
синтаксис как так:
ljmp [esp]
После этого мы получили правильно сгенерированный код:
00003088 <task1_start>:
3088: 55 push %ebp
3089: 89 e5 mov %esp,%ebp
308b: 66 68 a0 00 pushw $0xa0
308f: 6a 00 push $0x0
3091: ff 2c 24 ljmp *(%esp)
3094: 90 nop
3095: 5d pop %ebp
3096: c3 ret
В вышеприведенном ljmp
является сгенерировано:
0xff
- код операции для jmp
, то же самое. ljmp
- это просто особый синтаксис, используемый GAS (GNU Assembler) для генерации кода операции FF /5
.
0x2c
- это ModR/M байт для [--][--]
(без смещения), но в столбце 5
в таблице 2-2. Это означает, что этот код операции действительно FF /5
.
0x24
то же самое для прыжка в ближайшее время, что означает отсутствие масштабирования.
И это фактический код рассматривается GDB:
0x308b <task1_start+3> pushw 0xa0
0x308f <task1_start+7> push 0x0
0x3091 <task1_start+9> jmp FWORD PTR [esp]
Теперь FWORD
что-то новое, но по крайней мере это не добавляет случайное смещение больше. И действительно, задача правильно переключена на 0xa0
.
Спасибо за ваши предложения, всем. Без этого я бы никогда не исследовал это.
Но 'ltr' не вызывает переключатель задачи, то есть текущее состояние автоматически сохраняется. Но я думаю, что я попытаюсь переключиться на новую задачу (задача без прерывания, обработчики прерываний по мере того, как задачи уже работают), а затем обходите это ограничение позже. – Amumu
Я неправильно понял вопрос. –
Я не уверен, почему вы не можете использовать JMP для ссылки на память в качестве операнда. Операнд памяти будет указывать на адрес памяти, содержащий селектор/смещение. Этот адрес памяти может быть изменен во время выполнения –