首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >对非常量TSS段使用jmp指令。

对非常量TSS段使用jmp指令。
EN

Stack Overflow用户
提问于 2016-11-09 16:11:54
回答 3查看 1.3K关注 0票数 2

JMP指令参考。

根据文档,我们可以对一个恒定的远段执行jmp

代码语言:javascript
复制
jmp 0x18:00

在这里,0x18是GDT全局描述符表中有效的段选择器。

jmp可以与包含有效GDT条目(即代码/数据段描述符)的段寄存器一起使用:

代码语言:javascript
复制
mov es, 0x18
jmp es:0x0

在这里,0x18是一个TSS (任务状态段)描述符,当跳转到它时,CPU执行一个任务切换,它自动将其状态保存到当前的TSS中,然后用保存在新TSS中的状态填充。

但是,TSS是一个系统段描述符,因此不能加载到任何段寄存器中(如Intel文档所建议的)。那么,如何在运行时使用动态分配的TSS跳转到任务呢?

我能想到的唯一方法是使用iret指令,但我觉得它像黑客一样,因为我需要修改链接字段,然后在EFLAGS中设置NT位来执行反向链接任务切换。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2016-11-09 21:23:25

不仅不能用TSS选择器加载ES,指令jmp es:0x0也是无效的。没有指令将段寄存器移动到另一个段寄存器(例如。E至CS)。也没有指令可以从普通寄存器中加载CS。正如Margaret Bloom的回答所显示的那样,您需要用JMP指令加载CS,该JMP指令需要一个内存操作数,特别是一个以far指针作为内存操作数的JMP指令,因此您将得到一个设置CS的远跳指令。

就实现这一点而言,在任务结构、放置任务的TSS和其他任务特定信息的结构中放置这个far指针是有意义的。例如,要切换任务,可以使用如下代码:

代码语言:javascript
复制
struct task {
    struct {
        unsigned offset;
        unsigned short selector;
    } far_jmp_ptr;
    struct tss tss;
    // ...
};

void
switch_tasks(struct task *new_task) {
    asm("jmp FAR PTR %0" : : "m" (new_task->far_jmp_ptr));
}

该代码假设具有一个远指针的“任务结构”,其中包含为该任务分配的TSS选择器(忽略偏移部分)。

从技术上讲,您还可以使用LTR指令和JMP指令跳转到任务。这将在不执行任务切换的情况下更改任务,因此不会影响寄存器(除了TR、CS:EIP和您显式更改的任何其他寄存器)。例如:

代码语言:javascript
复制
mov  esi, [new_task]
ltr  [esi + TASK_FAR_JMP_PTR + 4]
jmp  [esi + TASK_TSS + TSS_EIP]

只有当新任务在0环上运行,或者刚刚开始,或者在不需要恢复寄存器的已知点停止时,这才是实用的。特别是,这就是如何启动初始内核任务(或单个TSS操作系统中的唯一任务)。

请注意,大多数操作系统只对所有任务使用一个TSS,因此不要使用CPU提供的任务切换机制。对于64位操作系统来说,这是必需的,因为在长模式下不支持任务切换.

票数 4
EN

Stack Overflow用户

发布于 2016-11-09 18:44:37

代码语言:javascript
复制
push WORD <TSS_selector>
push DWORD 0
jmp FAR [esp]

假设32位代码和一个可用的堆栈。

这将使堆栈在调用线程中保持不平衡和未对齐,您可能需要使用专用内存位置:

代码语言:javascript
复制
mov WORD [tss_pointer + 4], <TSS_selector>
jmp FAR [tss_pointer]

tss_pointer dd 0, dw 0
票数 6
EN

Stack Overflow用户

发布于 2016-11-10 08:18:42

这里建议的答案是正确的,但是缺少一部分:建议的语法不会产生跳远。我照玛格丽特·布鲁姆的建议做了,但没有用。我的代码一定有问题,因为我知道她给了我正确的答案,因为其他人也提出了同样的建议。查看GDB时,我应用了上述语法:

代码语言:javascript
复制
asm("pushw 0xa0");
asm("pushd 0x0");
asm("jmp  far [esp]");

(以上语法为内联组装,GCC风格)

查看GDB,jmp far生成为:

代码语言:javascript
复制
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的输出

代码语言:javascript
复制
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指令。看一看英特尔的手册,这个操作码就差一点跳起来了:

  • 0xff代表jmp指令。
  • 0xa4是用于[--][--] + disp32有效地址esp的ModR/M字节。这意味着,需要一个SiB字节,即偏移量。(参见:表2-2。使用ModR/M Byte的32位寻址形式)
  • 0x24是ESP的SiB字节,但是没有任何缩放(值是none),实际上,保持它不变。(参见:表2-3。32位寻址形式与SIB字节)。

上面生成的jmp对应于FF /4操作码(引用:jmp指令),这意味着一个近跳,因为生成的ModR/M字节是0xa4。跳远的正确操作码是FF /5

显然,我必须为汇编程序做些什么来产生跳远。因此,很容易使用ljmp指令来修复,而不是像这样使用jmp far语法:

代码语言:javascript
复制
ljmp [esp]

之后,我们得到了正确生成的代码:

代码语言:javascript
复制
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汇编程序)用于生成FF /5操作码的一种特殊语法。
  • 0x2c[--][--]的ModR/M字节(没有移位),但在表2-2中的列5。这意味着,这个操作码是真正的FF /5
  • 0x24对于近跳也是一样的,这意味着没有缩放。

这是GDB看到的实际代码:

代码语言:javascript
复制
0x308b <task1_start+3>  pushw  0xa0           
0x308f <task1_start+7>  push   0x0            
0x3091 <task1_start+9>  jmp    FWORD PTR [esp]

现在,FWORD是新的东西,但至少它不再增加随机位移。事实上,任务被正确地切换到0xa0

谢谢你们的建议,各位。如果没有它,我就不可能调查这件事。

票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/40511390

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档