assembly 如何使用内存寄存器来保存不同的类型?

svujldwt  于 2022-11-13  发布在  其他
关注(0)|答案(2)|浏览(156)

我的印象是,如果程序为变量类型整数(大小为8字节)保留内存,则保留的内存将是8个不同的寄存器,它们在内存中顺序出现。
我的问题如下:
1.假设答案各不相同,我上面的陈述是否很好地概括了不同类型的变量所需的每个字节都等同于使用内存中1个寄存器的变量?(即1个字节需要内存中的1个寄存器)
1.如果这是真的,内存中的每个寄存器保存多少位?或者如果我买了一台32位的计算机,这是否意味着内存中的每个寄存器保存32位?
1.如果整数类型需要8个不同的寄存器来满足其8字节的大小,那么每个不同的寄存器中包含什么?
1.我也试着去理解类型的概念。我知道如果你有32位来工作,你可以表示从0到4294967295的无符号整数值。然而,如果我把无符号整数4294967295存储在一个32位的存储单元中-位CPU如何知道该存储单元中的二进制表示需要解码为无符号整数格式?即,是为某个类型预留的内存指定了该类型还是指针指定了该类型或者完全不同的类型?
我对二进制算术、汇编语言、引用、指针以及变量和数组在内存堆中的存储方式都有一定的了解(所以我可以使用这些上下文来理解任何答案)。而且我可以用C、C++和Java编程。感谢您的帮助。

vfhzx4xs

vfhzx4xs1#

1、2、3:不要将存储器称为寄存器;虽然我以前见过这样做,但这很令人困惑。64位处理器有8字节宽的寄存器,32位处理器有4字节宽的寄存器,但当这些寄存器被复制到RAM中时,内存中就只有字节了。整数的哪一部分存储在哪个字节中取决于处理器的字节序:小端序系统将在8个字节的第一个(最低)地址中的0x 1中存储1位,而大端序系统将在最后一个地址中存储1位。
4:CPU不知道也不关心;“types”是一个高级语言结构,对于CPU来说,所有内容都是一个数字:“abcd”是一个数字,就像0xf 0 f0 f0 f0是一个数字一样。你必须根据你想让它做什么给予它指令,例如,对于x86,如果你想让它把这个数字当作有符号的,就用IDIV代替DIV。

zzwlnbp8

zzwlnbp82#

类型在很大程度上是为了编程语言的利益而虚构的。对于处理器来说,位就是位,它们没有任何意义,除非有时在单个指令的执行过程中短暂地存在,当指令结束时,它们就失去了意义。
Dijkstra:“计算机科学与计算机无关,就像天文学与望远镜无关一样。”
您需要指定您对问题感兴趣的处理器,或者您对一般的处理器感兴趣。目前常见的处理器组合从带有8位寄存器的处理器到带有64位或更高寄存器的处理器,其中包括8位、16位、32位、64位基于寄存器的处理器。
另外,不要对寄存器中的所有内容感到困惑,一些处理器有很多寄存器,您的高级代码中的许多项会在寄存器中停留一段时间,而其他的处理器没有很多寄存器,而且你的大多数变量都在ram中,而不是寄存器中。更常见的是,即使寄存器长时间保存你的变量,也会有一些ram。优化器确实会破坏这种平衡,所以很难做出一般性的陈述。
你说你懂汇编语言,以这个汇编语言伪代码为例:

mov r1,#0x20000000
shl r2,r0,5
add r1,r2
ldr r0,[r1]

这就像你看到的,如果你有一个32字节的结构体数组,你想得到第一个元素,假设它是一个单精度浮点数,你想从寄存器r0中的数组中的元素号得到这个浮点数,我们不关心元素号是多少,代码对它进行操作。

struct 
{
  float f;
  stuff...32 bits total
} mystruct[MYSTRUCTSIZE];
...
unsigned int i;
...
something=mystruct[i].f
...

上面的汇编伪代码计算mystruct[i].f地址,并从内存中将其加载到something代码中或由something代码使用。
我们可能碰巧知道的位0x20000000是这个结构体数组所在的内存中的某个地址,但现在,对于mov指令,它只是位,一个立即数,我们正在加载到一个寄存器中。2通常mov指令不影响标志位,所以除了一些位进入寄存器外,它对cpu没有任何意义。假设此伪代码具有32位寄存器和地址空间
如前所述,r0保存了结构体数组的索引,所以我们乘以32,左移指令并不关心这是一个索引,也不关心移位5与结构体有什么关系,它只是将位送入alu,使位移出一侧,零移入另一侧.一些cpu将最后移出的位移入进位位,不是作为进位位,而是作为级联移位的保持器,同样,如果你认为这是一个二进制补码(移位后),或者想在编程中使用一些快捷方式,可以计算zflag和n flag(符号位)。但这些只是cpu的位,没有任何意义。
此时,作为人类,我们认为r2在内存中的位置是结构体数组索引的偏移量,但对于cpu来说,它只是位。我们执行加法。我们认为一个操作数是地址,另一个操作数是偏移量,但对于cpu来说,它们只是被操作的位。加法通常不关心有符号还是无符号。二进制补码的美妙之处在于,您可以将无符号和有符号输入到同一个加法器逻辑中,该逻辑通常计算进位输出标志(无符号溢出)和v标志(有符号溢出)加上z标志、零和n标志的负结果,所有这些都是一次性的,如果它们对加法有任何意义,则没有,只是像结果一样计算,以防你想用标志来做什么。在这种情况下,cpu没有办法知道我们正在计算地址。
现在我们将寄存器中的位定义为地址,并执行加载,但CPU只将其视为一条指令的地址,在某个时刻,该寄存器在某个时刻之前,是加法运算的结果。
我们从内存中阅读的是什么?更多的位,不是浮点值,只有32位。现在有些CPU可能有直接的方法从内存直接加载到浮点寄存器,有些CPU没有浮点,它都是用通用寄存器合成的。即使是有浮点的CPU也可能使用gprs来加载浮点值,例如上面的代码是这样做的:

mystruct[j].f=mystruct[i].f;

如果可以的话,你可能不想烧一个fpu寄存器,你可能会像我下面那样使用一个gpr。如果在这个代码附近没有实际的浮点数学,它只是从一个地方移动到另一个地方,没有理由让fpu参与进来。
上面的代码行可能看起来像这样:

ldr r1,mystruct_base
shl r2,r0,#5
add r2,r2,r1
ldr r0,[r2]
shl r2,r3,#5
add r2,r2,r1
str r0,[r2]

其中,当输入此代码时,r0是i,r3是j。cpu不知道也不关心这些位是什么,但有几个例外。对于ldr和str,r2表示指令时间段,被视为内存中某个对象的地址。除此之外,没有结构、浮点、有符号或无符号整数。什么都没有。只有位。

是的,通常当有人说32位计算机时,他们指的是32位寄存器。这是一个很好的概括,通常位的大小也是内存总线的地址大小,32位意味着理论上可以寻址32位内存,4GB。这有点模糊,尽管你可能从x86或其他产品中了解到。通常,esp与x86你会看到一个64位处理器运行在32位模式,基本上运行的代码/指令,期望32位寄存器而不是64位,与x86的“寄存器”有不同的方式来访问他们作为8,16,32,或63位,所以你可以玩这些游戏。
所有这些你问的问题和更多的问题都在处理器的汇编语言中得到了回答。现在不幸的是,mips已经不用它的方式来迷惑你了,x86也是如此,所以避免那些,先选择一些简单的东西,比如msp430或ARM或拇指模式下的ARM来学习。

相关问题