如果我有一个CPU并且我编写了一个程序并且我想存储一个值(将一个值从寄存器复制到内存(RAM))那么我会在CPU的指令集中使用一个指令(假设这是一个x86 CPU)这样做?
第二个问题,x86指令集中的指令是否在RAM中的特定地址设置一个名为MOV
的值?
第三个问题。 BIOS,UEFI,内核和引导加载程序都使用x86指令集中的MOV
指令(将值(如10
)分配给RAM中的特定地址)对吗?
第四个问题。在OS(具有内核(如Linux))环境中运行的程序在请求它时不使用MOV
指令来获取分配的一块内存,而是要求内核代表它们执行此操作?
第五个问题。我在第四个问题中描述的是一个系统调用(当一个在OS环境中运行的程序要求内核代表它做某事时(在这种情况下给它一些内存))?
答案 0 :(得分:0)
0.
我认为你对汇编语言知之甚少,甚至没有提出一个合理的问题,这个问题确实填补了你所遗漏的任何差距,但我试图回答你的问题。我真的不确定你真正想知道什么。
也许请查看Matt Godbolt的CppCon2017演讲:“What Has My Compiler Done for Me Lately? Unbolting the Compiler's Lid”,了解x86 asm的初学者介绍。
但我认为你错过了一些关于堆栈/堆/静态存储位置的概念。见Stack, Static, and Heap in C++
是
是的,最常见的x86存储指令是mov
。例如mov dword [rdi], 10
。或者在指令中使用绝对地址编码,mov dword [my_static_32_bit_location], 10
奇怪的具体。您可以编写一个没有任何静态数据的引导加载程序。所有的mov-immediate指令都将使用寄存器目的地。
mov
不会分配或保留内存。在OS下运行的程序可以具有静态数据。例如考虑这个C函数:
unsigned LCG_rand() {
static unsigned seed = 0x1234;
seed = seed * 0x5677 + 0x7723; // Linear Congruential Generator with badly chosen coefficients I just made up
return seed; // mod type-width is implicit
}
gcc7.2定位x86-64 Linux将其编译为(Godbolt compiler explorer):
LCG_rand:
imul eax, DWORD PTR seed.2294[rip], 22135 # eax = load(seed) * 22135
add eax, 30499 # eax += 30499
mov DWORD PTR seed.2294[rip], eax # store the old value back to memory.
ret
.data # static read-write data goes in the .data section
.align 4
seed.2294: # label which the compiler uses to refer to it.
.long 4660
.data
部分包含具有非零初始值设定项的静态读写数据。初始值按字面存储在可执行文件中。它链接到可执行文件的数据段。运行它时,可执行文件的数据段将映射到进程的内存空间,具有读/写权限,写时复制(私有)。 (因此,将数据写入内存不会更新磁盘上的数据,就像使用mmap
MAP_SHARED一样。)
这些地址是链接时常量,因此程序可以直接使用它。 (在上面的代码中,该函数使用PC相对寻址,但也支持绝对。You may have to use -no-pie
on some gcc setups, though.)
完全相同的机器代码在裸机环境中可以正常工作,即使禁用了分页,因此您使用的地址是物理地址,而不是通常的虚拟地址,它们允许每个进程有自己的记忆观。 (呃,但你可能不得不处于16位或32位模式,我忘了如果x86-64长模式甚至可以禁用分页。)
是肯定的。有关 用户空间进程如何进行系统调用的详细信息,请参阅What are the calling conventions for UNIX & Linux system calls on i386 and x86-64。