【问题标题】:Assembly - How to handle registers装配 - 如何处理寄存器
【发布时间】:2018-03-27 10:10:33
【问题描述】:

所以我正在尝试学习汇编(NASM)。问题是组装的资源非常基础 - 理论和稀有,我无法理解非常基础的东西。我知道汇编寄存器被用作处理器“内存”上的“变量”。但问题是,例如在这个“hello world”类型的程序中:

section .text
   global _start     ;must be declared for linker (gcc)
    
_start:          ;tell linker entry point
   mov  edx,len  ;message length
   mov  ecx,msg  ;message to write
   mov  ebx,1    ;file descriptor (stdout)
   mov  eax,4    ;system call number (sys_write)
   int  0x80     ;call kernel
    
   mov  eax,1    ;system call number (sys_exit)
   int  0x80     ;call kernel
    
section .data
msg db 'Hello from assembly!',0xa ;a message
len equ $ - msg  ;length of message

我不明白为什么我们保存edx 上的消息长度和ecx 上写入的消息,例如here 在tutorialspoint 中说:

所以在这里我假设由于ECX应该有循环计数器,在一个类似C的程序中:

for(int i = 0; i < 5; i++) 
{
      printf("Hey!\n");
}

ECX 寄存器应包含i。但是在上面的程序中,我们将消息保存在ECX

同样,当我们想从程序集中调用 C 函数时,我对保存参数的位置感到困惑,但我认为由于这是更高级的,如果我了解我保存在哪些寄存器中,我会逐渐了解会发生什么如果我想调用 C 函数。

谢谢!

【问题讨论】:

  • int 0x80 的文档告诉您需要使用哪些寄存器。
  • 想象一下int 0x80 功能背后有很多代码,打印消息并不是魔法。并且这段代码已经以某种方式编译,期望字符串内存地址在ecx,所以你必须在调用系统服务之前调整你的代码以在期望的寄存器中有期望的参数。服务代码没有机会猜测您确实将哪个参数放入了哪个寄存器,它必须是固定的,因为您不能用它确实持有什么样的值来“标记”寄存器。如果你放入ecx内存地址,或者整数,或者浮点数,它只是32位,没有区别或一些“类型”。
  • 寄存器是一种稀疏资源,所以你应该经常三思你的算法,设计使用合理数量的寄存器的代码,例如重新调整你的算法以使用它并不少见与计数器和数组索引相同的值(例如从 -5 计数到 0)等。如果您有 ecx 空闲,则将其用作计数器是有意义的,但在您的示例中,如果您想打印消息5 次,使用一些免费寄存器作为计数器会更有意义,例如 ebp/esi/edi
  • 你们太棒了!我对你们所有人都投了赞成票,我希望我能接受多个答案。我选择接受来自@kristjank 的那个,因为它是第一个回答的并且因为它很简单。
  • 在您的示例中,寄存器的唯一用途是用于将参数传递给系统调用。该程序没有变量。 (嗯,你可以调用msg 一个数组变量。你确实把它放在读/写数据部分,所以C 中的等价物是char msg[] = { 'H', 'e', ..., '\n' };,而不是const char msg[]...(而不是字符串文字初始化器,因为数组不以 0 字节结尾;它不是 C 隐式长度字符串。)

标签: assembly x86 nasm


【解决方案1】:

寄存器是独立的数据存储设备,因此您将数据存储在何处并不重要,除非函数或指令要求您这样做。

在这种情况下,Linux 系统调用要求将数据存储在特定的寄存器中。 在其他情况下,这些规则更像是良好做法:您应该遵循它们,但如果没有什么要求,您不一定必须这样做。

【讨论】:

  • 换一种说法,有些指令只能使用某些寄存器,但是如果你不使用它们,这些指令的存在并不意味着什么(在那个特定的代码块中) )。
【解决方案2】:

描述有点像反义词——试图追溯地解释寄存器命名。它可能会帮助您记住寄存器的其他特殊用途,否则这些用途是通用的。然而,这并不是真正寄存器名称的原因。

Intel 处理器系列从the 4004 开始,只有一个累加器,简称为寄存器 A。

当后来的模型增加了更多的寄存器时,A之后的下一个可能被称为A2或者B。所以它恰好变成了B。之后使用C和D作为另一对寄存器是“自然的”。现在我们在 8 位 CPU 上。

在将 8086 设计为 16 位设备时,旧的 8 位寄存器 A、B、C 和 D 被制成 16 位并命名为 AX、BX、CX 和 DX。同时,它们比 8080 更通用。

由于它们通用寄存器,它们可以用于其他用途,而不是它们的反义词名称所暗示的。例如,CX(或 ECX)可以很好地存储指向字符串的指针,而不是保存循环计数。

【讨论】:

    【解决方案3】:

    我曾经为此苦苦挣扎,但人们没有提供帮助。我只是被称为巨魔(srsly?)。

    什么是寄存器?

    寄存器是处理器拥有的一种简单的数据存储,非常小(通常为 16、32 或 64 位)但速度非常快。

    它们可用于将数据或地址存储到内存中。

    所有不同的寄存器有什么意义?

    1) 你不能使用一个寄存器来保存你的所有数据(除非你擅长混淆二进制的东西)。

    2) 指令使用不同的寄存器(例如LOOP指令使用计数寄存器,即CX)。

    内存或硬盘呢?

    数学之类的事情通常需要注册(也要吃蔬菜!)。内存比寄存器慢,你必须管理它。

    这个例子可能会让您感到困惑,但它就像黄金和金钱。黄金没有经济性,但它是有价值的和稀有的。您可以轻松获得资金,但它的运作方式更令人困惑。

    除非您需要访问文件,否则不应将硬盘驱动器用于任何使用 Assembly。

    【讨论】:

    • 要真正回答这个问题,再强调一点:如果您没有在该特定代码块中使用the slow loop instruction,那么ECX 只是您可以使用的另一个寄存器用于其他任何事情。即有些指令只能使用某些寄存器,但如果你不使用它们,这些指令的存在并没有任何意义。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-08-26
    • 1970-01-01
    • 2021-03-03
    • 2013-06-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多