【问题标题】:what does size of registers and stack really mean in assembly x86 [closed]寄存器和堆栈的大小在汇编 x86 中的真正含义是什么 [关闭]
【发布时间】:2016-08-20 15:39:44
【问题描述】:

我是汇编新手,我真的很困惑,我读了几篇文章和书籍,但我不明白这是什么意思

在汇编 x86 中,我们有不同的寄存器,每个寄存器都有特定的大小,例如

EAX : 32 位

Q1- 那么 32 位的真正含义是什么?这是否意味着,我只能存储 32 位大小的值?

如果是的话

Q2 - 如果我的字符串很长,我如何将这个字符串移动到我的寄存器中?

Q3 - 我想知道何时应该从堆栈中推送和弹出?

Q4 我可以在没有堆栈的情况下将我的值存储在我的寄存器中,为什么我们有一个堆栈?解决哪个问题?

如果我们在这里举个例子是我的 C 代码:

#include<stdio.h>

main() 
{
    printf("Hello World");

}

在这里,我们将 Hello world 传递给 printf 函数,无论大小我都可以传递任何东西,如果我将此代码转换为汇编,首先我必须将系统调用 args 移动到寄存器,然后调用系统调用然后是 int 0x80 。如果 instate of hello world 我有一个段落呢?

Q5 - 当我将任何数据移动到寄存器时,我如何选择应该将数据移动到哪个寄存器?

谢谢。

【问题讨论】:

  • 阅读更多内容,您会明白的。您所问的大部分内容都是“无法回答的”,只是太混乱或基于不正确的前提而无法做任何事情。但是,是的,eax 确实总是 32 位。字符串通常通过其起始地址引用。
  • 第一季度。是的。 第二季度。如果您更改它,请逐个更改,如果您传递它,则作为指针。 第三季度。当你需要它的时候。例如。你想使用一个必须在最后恢复的寄存器:推送它,使用它,弹出它。 第四季度。是的。我们需要存储 ubound 数量的项目,始终与最后一个交互。函数调用。段落字符 (?) 与“H”字符没有什么不同。 Q5 猜一猜,使用想到的第一个寄存器。随着您进一步开发代码,优化该选择以最小化您的目标指标(速度、溢出/填充、大小、复杂性)。
  • stackoverflow.com/questions/1773249/assembly-and-system-calls/… 的可能重复项:通过指针传递字符串。我知道在一个问题中问 5 件事很诱人,但它们甚至都不是相关的。例如Q5与其他无关。有关大量信息,请参阅x86 tag wiki。
  • 我不同意“过于宽泛”的密切记录。这些都是非常明智的问题,只有高级语言经验的人在第一次看到汇编时经常会问这些问题,尤其是它通常在 Internet 资源中呈现的碎片化方式。我不会关闭这个问题。有一些简短的答案可以让新的汇编程序员克服困难并继续前进。 @JohnBurger 做得很好。
  • 除了您确实需要写一本书来解决所有困惑之外,这里还有五个不同的问题。规则是每个问题一个问题。这是“太宽泛”的教科书案例(请原谅双关语)。

标签: assembly x86


【解决方案1】:

注册商店号码。就是这样。这就是他们所做的一切。作为程序员,这就是您使用和解释这些数字的方式,从而使程序正常运行。

  • 每个寄存器的大小为 8、16、32 或 64 位。它们可以存储 signed 或 unsigned 数字 - 也就是说,无论它们的最高位被解释为符号位,还是仅作为数字的一部分。请注意,这些数字可能是内存中变量的地址 - 符号性不是一个因素。

  • 您可以对数字进行加法、减法或其他许多操作。
    将一个放入一个寄存器,另一个放入另一个寄存器,使用ADD 或SUB 指令,您会得到一个结果:

            MOV  EAX, 0x12345678
            MOV  EBX, 0x12345677
            SUB  EAX, EBX        ; EAX now holds the value 1
    
  • 您可以指向内存中的值。将变量的地址存储在寄存器中,您可以读取和写入这些值:

            .DATA
    xValue  DD   42       ; Save xValue here
    
            .CODE
            MOV  EAX, [xValue]         ; Get the current xValue into EAX
            INC  EAX                   ; Add one to it
            MOV  [xValue], EAX         ; Save it back
    
            INC  [xValue]              ; One line to do the above three
    
            MOV  EBX, OFFSET xValue    ; Point to xValue with EBX
            MOV  EAX, [EBX]            ; Get the current value
            INC  EAX                   ; Add one to it
            MOV  [EBX], EAX            ; Save it back
    
            INC DWORD PTR [EBX]        ; One line to do the above three
    
  • 如何传递字符串?
    你没有。你传入字符串的内存地址,接收函数只知道寄存器中的值就是字符串在内存中的地址。

  • 你为什么要从堆栈中 PUSH 和 POP?

    • 只有有限数量的寄存器,因此要执行具有许多不同值的进程,您需要将一些值存储在内存中,并在寄存器中交换值以处理它们。
    • 您可以为每个变量使用保留的内存区域;或者您可以将值临时保存到堆栈中,而不是在内存中为它们保留特定位置。
    • 请注意,如果您有递归函数,则保留内存区域将不起作用 - 每次通过递归时,您都需要新的内存用于下一次迭代。堆栈非常适合这种情况。
    • 某些函数希望将其参数存储在堆栈中,而不是存储在全局变量中。
  • 你怎么知道要使用哪个寄存器?
    这取决于:

    • 如果你正在编写代码,你可以使用任何你喜欢的寄存器——除了SP/ESP/RSP,它是为指向堆栈而保留的!
      • 有一些架构约定:
        • 如果要使用REP或LOOP指令,则需要使用CX/ECX/RCX来保持计数;
        • 如果你要使用LODS、STOS、CMPS和MOVS指令,那么你需要使用AL/AX/EAX/RAX,@ 987654343@/ESI/RSI和/或DI/EDI/RDI。
      • 有一些历史惯例,但在 32 位和 64 位编程中不再需要这些惯例:
        • BX、SI、DI 和 BP 是唯一可以索引内存的寄存器,所以这就是它们的用途;
    • 如果您调用的代码不是您编写的,那么它应该指定(或使用通用标准)哪些寄存器保存哪些参数,以及将哪些寄存器用于返回值。

【讨论】:

  • 你真的很棒,谢谢。现在我的画面变得清晰了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-15
  • 1970-01-01
  • 1970-01-01
  • 2010-09-08
  • 2012-05-18
相关资源
最近更新 更多