简体   繁体   English

汇编中的跳转指令如何与多个进程一起工作?

[英]How does the jump instruction in assembly work with multiple processes?

So, I am confused about how jump instructions work in an operating system. 所以,我对跳转指令在操作系统中的工作原理感到困惑。 I thought that the jump instruction set the value in the processor's program counter. 我认为跳转指令设置处理器程序计数器中的值。 But programs can be run in various locations in memory. 但程序可以在内存中的不同位置运行。 I see that in x86, there's the JMP EAX instruction, but my C++ code doesn't seem to use this. 我在x86中看到,有JMP EAX指令,但我的C ++代码似乎没有使用它。 I compiled some C++ code in VC++: 我在VC ++中编译了一些C ++代码:

int main()
{
    int i = 0;
    while (i < 10)
    {
        ++i;
        if (i == 7)
        {
            i += 1;
            continue;
        }
    }
}

This translates to: 这意味着:

    int main()
    {
00411370  push        ebp  
00411371  mov         ebp,esp 
00411373  sub         esp,0CCh 
00411379  push        ebx  
0041137A  push        esi  
0041137B  push        edi  
0041137C  lea         edi,[ebp-0CCh] 
00411382  mov         ecx,33h 
00411387  mov         eax,0CCCCCCCCh 
0041138C  rep stos    dword ptr es:[edi] 
        int i = 0;
0041138E  mov         dword ptr [i],0 
        while (i < 10)
00411395  cmp         dword ptr [i],0Ah 
00411399  jge         main+47h (4113B7h) 
        {
            ++i;
0041139B  mov         eax,dword ptr [i] 
0041139E  add         eax,1 
004113A1  mov         dword ptr [i],eax 
            if (i == 7)
004113A4  cmp         dword ptr [i],7 
004113A8  jne         main+45h (4113B5h) 
            {
                i += 1;
004113AA  mov         eax,dword ptr [i] 
004113AD  add         eax,1 
004113B0  mov         dword ptr [i],eax 
                continue;
004113B3  jmp         main+25h (411395h) 
            }
        }
004113B5  jmp         main+25h (411395h) 
    }
004113B7  xor         eax,eax 
004113B9  pop         edi  
004113BA  pop         esi  
004113BB  pop         ebx  
004113BC  mov         esp,ebp 
004113BE  pop         ebp  
004113BF  ret              

So I'm confused, for the command jmp 411395h , does this imply the program is always loaded in the same spot in memory? 所以我很困惑,对于命令jmp 411395h ,这是否意味着程序总是被加载到内存中的相同位置? Because that seems illogical. 因为那似乎不合逻辑。

No, there are two things possibly at play here - you don't specify an OS so I'm going to give a general answer. 不,这里有两件事情可以发挥 - 你没有指定操作系统所以我会给出一般答案。

The first is that an executable file is rarely in the final format. 首先,可执行文件很少采用最终格式。 As a simplification, compilation turns source into object files and linking combines object files into an executable. 作为简化,编译将源转换为目标文件,并且链接将对象文件组合成可执行文件。

But the executable has to be loaded into memory and, at that stage, there can be even more modifications done. 但是必须将可执行文件加载到内存中,在那个阶段,可以进行更多修改。 One of these modifications may be to fix up memory references within the executable to point to memory that has been loaded at different locations. 这些修改之一可以是修复可执行文件中的内存引用以指向已在不同位置加载的内存。

This can be acheived by the executable file containing a list of addresses within itself that need to be fixed up at run time. 这可以通过包含本身内部地址列表的可执行文件来实现,该列表需要在运行时修复。

There is also a disconnect between virtual memory and physical memory in many modern operating systems. 在许多现代操作系统中,虚拟内存和物理内存之间也存在脱节。

When your process starts, you get your own (4G for Windows 32bit, I believe) address space into which your process is loaded. 当您的流程开始时,您将获得自己的(用于Windows 32位的4G,我相信)加载进程的地址空间。 The addresses within this address space have little relationship to your actual physical memory addresses and the translation between the two is done by a memory management unit (MMU). 此地址空间中的地址与您的实际物理内存地址几乎没有关系,两者之间的转换由内存管理单元(MMU)完成。

In fact, your process could be flying all over the physical address space as it's paged out and in. The virtual addresses will not change however. 实际上,您的进程可能会遍布物理地址空间,因为它已被分页并进入。但虚拟地址不会改变。

As other people wrote, there are relative jump and relative call instructions which essentially add a fixed value to eip and therefore do not depend on the program's location in memory; 正如其他人所写的那样,有相对跳转和相对调用指令基本上为eip添加一个固定值,因此不依赖于程序在内存中的位置; compilers prefer to use these whenever possible. 编译器喜欢尽可能使用这些。 You can look at the code bytes to see what exact instructions your compiler used. 您可以查看代码字节以查看编译器使用的确切指令。 However, I assume you are asking about jumps/calls to absolute addresses. 但是,我假设你在询问跳转/调用绝对地址。

When the linker generates an executable, it generates absolute addresses supposing a particular base address ; 当链接器生成可执行文件时,它会生成假定特定基址的绝对地址 ; Microsoft linker usually uses 400000h . Microsoft链接器通常使用400000h When OS loads an executable or a dll, it "fixes up" all absolute addresses by adding the difference between the address at which the executable was actually loaded and the address at which the linker based it. 当OS加载可执行文件或dll时,它通过添加实际加载可执行文件的地址与链接器基于它的地址之间的差异来“修复”所有绝对地址。 All executable formats except .com specify some sort of fixup table, which lists all locations in the executable which have to be patched up in this way. .com之外的所有可执行格式都指定了某种类型的修正表,其中列出了必须以这种方式修补的可执行文件中的所有位置。 Therefore, after the OS loads your executable into memory at base address, say, 1500000h , your jump will look like jmp 1511395h . 因此,在OS将您的可执行文件加载到基本地址(例如1500000h ,您的跳转将看起来像jmp 1511395h You can check this by looking at actual code bytes with a debugger. 您可以通过使用调试器查看实际代码字节来检查这一点。

Older Windows systems preferred to load executables at the base address used by the linker; 较旧的Windows系统倾向于在链接器使用的基址处加载可执行文件; this created a security risk, because an attacker would know in advance what is where in memory. 这造成了安全风险,因为攻击者会提前知道内存中的内容。 This is why newer systems use base address randomization. 这就是为什么较新的系统使用基地址随机化的原因。

The memory locations are relative to the process. 内存位置与进程有关。 main is always at the same spot in memory, relative to the beginning of the program. 相对于程序的开头, main始终位于内存中的相同位置。

No. On x86 (and other architectures, too), most jump instructions are IP-relative : the binary machine codes for the instructions represent an offset from the current instruction pointer. 在x86(以及其他体系结构)上,大多数跳转指令都是IP相关的 :指令的二进制机器代码表示与当前指令指针的偏移量。 So, no matter what virtual address the code gets loaded at, the jump instructions function correctly. 因此,无论代码加载到哪个虚拟地址,跳转指令都能正常工作。

Relative jumps take the address of the current machine instruction (called instruction pointer) and add an offset to compute the address to be jumped to. 相对跳转采用当前机器指令的地址(称为指令指针)并添加偏移量来计算要跳转到的地址。

If you look at your code 如果你看看你的代码

004113B3  jmp         main+25h (411395h) 
004113B5  jmp         main+25h (411395h) 
004113B7  xor         eax,eax 

you'll note that the jmp instruction is 2 bytes long (1 byte for jmp, 1 byte for offset), and cannot possibly store an absolute 4-byte address. 你会注意到jmp指令长2个字节(jmp为1个字节,偏移为1个字节),并且不能存储绝对的4字节地址。

Relative jumps are basic functionality of CPUs (from what I know about 65xx, Z80, 8086, 68000), and are not related to such advanced features as virtual memory, memory mapping or address space randomization. 相对跳转是CPU的基本功能(据我所知65xx,Z80,8086,68000),与虚拟内存,内存映射或地址空间随机化等高级功能无关。

大多数芯片具有相对跳跃(相对于当前位置)和虚拟寻址。

int main()
    {
00411370  push        ebp  
00411371  mov         ebp,esp 
00411373  sub         esp,0CCh 
00411379  push        ebx  
0041137A  push        esi  
0041137B  push        edi  
0041137C  lea         edi,[ebp-0CCh] 
00411382  mov         ecx,33h 
00411387  mov         eax,0CCCCCCCCh 
0041138C  rep stos    dword ptr es:[edi] 
        int i = 0,int j=0;
0041138E  mov         dword ptr [i][j],0
        while (i < 10)
00411395  cmp         dword ptr [i][j[,0Bh 
00411399  jge         main+47h (4113B7h) 
        {
            ++i;
0041139B  mov         eax,dword ptr [i][j] 
0041139E  add         eax,1 
004113A1  mov         dword ptr [i][j],eax '
            if (i == 7)
004113A4  cmp         dword ptr [i][j],7 
004113A8  jne         main+45h (4113B5h) 
            {
                i += 1;
004113AA  mov         eax,ebx,dword ptr [i][j] 
004113AD  add         eax,1 
004113B0  mov         dword ptr [i][j],ebx 
                continue;
004113B3  jmp         main+25h (411395h) 
            }
        }
004113B5  jmp         main+25h (411395h) 
    }
004113B7  xor         eax,ebx 
004113B9  pop         edi  
004113BA  pop         esi  
004113BB  pop         ecx  
004113BC  mov         esp,ebp 
004113BE  pop         ebp  
004113BF  ret

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM