4字节的汇编指令如何编码4字节的内存地址?
How can an assembly instruction of 4 byte encode a 4 byte memory address?
我没有特定的机器设置,但总的来说我用 C++ 编写了以下内容:
int* x;
x = 0xFFFFFFFF;
int* y;
y = 0x00000000;
*y = *x
我可以想出一种在汇编中执行此操作的方法:
// find &x (on the stack frame) using the frame register + an offset
// load value of x into register 0
load *(register 0) -> register 1 // load value of *x
load y -> register 2
store register 1 register 2
但是上面的none条指令都编码了内存地址(4GB内存是32位),只编码了一个寄存器的地址(如果我们有32个寄存器,就需要5位在说明中)
TL;DR
我的问题是像 "branch" (函数调用)这样的指令,它需要一个函数地址(或链接器给出的符号),它实际上是一个 32 位内存地址......它怎么可能(假设每个汇编指令也是 4 个字节大)?如果 "branch" 也使用临时寄存器来存储地址(就像我举的例子),那是否意味着 "branch" 不是原子操作?
在许多体系结构中,控制传输使用范围小于 32 位的相对编码。在其他体系结构上,指令不固定为 32 位。您还可以通过寄存器或内存获得间接跳转。加载寄存器和跳转可能不是原子的,但您通常不关心,尤其是如果您编写 C 代码。
My question is for instructions like "branch" (function call), it
takes a function address (or a symbol given by linker) which is in
fact a 32 bits memory address...how can it be(assuming each assembly
instruction is also 4 bytes big)? if "branch" also use temporary
registers to store the address(like the example I gave), does that
mean "branch" is not an atomic operation?
可以通过多种方式完成:
通过使用PC相对寻址:目标地址不是编码为绝对地址,而是编码为相对于PC当前值的有符号偏移量。这利用了相关函数彼此接近的优势,因此它们之间的距离可以编码为 16 位有符号整数。
通过使用 32 位寄存器作为操作数,而不是使用中间操作数。因此,一个 32 位寄存器预先加载了 CALL 或 JUMP 指令的目标地址,然后 CALL/JUMP 被设置为该寄存器指向的地址。这将在 32 位指令中具有 32 位值的问题转移到 LOAD/STORE 指令,这些指令通常分两个阶段执行此操作,使用 LOADHI 和 LOADLOW 指令加载 32 位寄存器的一半,或者具有只有 LOADLOW 指令和使用 SHIFTLEFT 指令。
我没有特定的机器设置,但总的来说我用 C++ 编写了以下内容:
int* x;
x = 0xFFFFFFFF;
int* y;
y = 0x00000000;
*y = *x
我可以想出一种在汇编中执行此操作的方法:
// find &x (on the stack frame) using the frame register + an offset
// load value of x into register 0
load *(register 0) -> register 1 // load value of *x
load y -> register 2
store register 1 register 2
但是上面的none条指令都编码了内存地址(4GB内存是32位),只编码了一个寄存器的地址(如果我们有32个寄存器,就需要5位在说明中)
TL;DR 我的问题是像 "branch" (函数调用)这样的指令,它需要一个函数地址(或链接器给出的符号),它实际上是一个 32 位内存地址......它怎么可能(假设每个汇编指令也是 4 个字节大)?如果 "branch" 也使用临时寄存器来存储地址(就像我举的例子),那是否意味着 "branch" 不是原子操作?
在许多体系结构中,控制传输使用范围小于 32 位的相对编码。在其他体系结构上,指令不固定为 32 位。您还可以通过寄存器或内存获得间接跳转。加载寄存器和跳转可能不是原子的,但您通常不关心,尤其是如果您编写 C 代码。
My question is for instructions like "branch" (function call), it takes a function address (or a symbol given by linker) which is in fact a 32 bits memory address...how can it be(assuming each assembly instruction is also 4 bytes big)? if "branch" also use temporary registers to store the address(like the example I gave), does that mean "branch" is not an atomic operation?
可以通过多种方式完成:
通过使用PC相对寻址:目标地址不是编码为绝对地址,而是编码为相对于PC当前值的有符号偏移量。这利用了相关函数彼此接近的优势,因此它们之间的距离可以编码为 16 位有符号整数。
通过使用 32 位寄存器作为操作数,而不是使用中间操作数。因此,一个 32 位寄存器预先加载了 CALL 或 JUMP 指令的目标地址,然后 CALL/JUMP 被设置为该寄存器指向的地址。这将在 32 位指令中具有 32 位值的问题转移到 LOAD/STORE 指令,这些指令通常分两个阶段执行此操作,使用 LOADHI 和 LOADLOW 指令加载 32 位寄存器的一半,或者具有只有 LOADLOW 指令和使用 SHIFTLEFT 指令。