在 mac OS 的装配中一步步问好世界

step by step hello world in assembly for mac OS

我在为 mac os(x86_64 体系结构)进行汇编时遇到了很多困难。我想向您介绍一个 hello world 程序的解释,如果您能给我您的反馈以及建议和解释,我将不胜感激:话虽如此,让我们进入代码。

你好世界程序

以前从未感受过Hello world的痛苦。 所以,这是我从互联网上复制粘贴的代码:
global _main 
section .text

_main:
   mov rax, 0x2000004
   mov rdi, 1
   mov rsi, str
   mov rdi str.len
   syscall

   mov rax, 0x2000001
   xor rdi, rdi 
   syscall

section .data
str: “Hello world”, 
.len: equ $ - str

所以让我为难自己:

  1. global _main 基本上告诉链接器从哪里开始,如果我没记错的话

  2. .text 部分告诉 OS(我猜)这是实际程序的开始。

  3. _main 如果我没记错的话是一个函数,这似乎是函数的表示法

  4. mov rax, 0x2000004 : 我不明白这个东西是做什么的。我在网上查了一下系统调用是如何工作的,它基本上需要一个文件代码(我认为这是下一行的 1),一个指向缓冲区的指针(这个缓冲区到底在哪里,我认为指向的第一个字节我的字符串)和文本片段的字节长度(在本例中为 .len)。我的问题是当我需要写东西的时候,这个十六进制的业务是如何工作的,mov rax 指令的实际工作是什么。

  5. mov rdi, 1: 我还是不明白到底发生了什么。我们需要一个 1 来将输出设置为 stdout,但是这条指令的实际功能是什么,这个 1 去哪儿了,幕后发生了什么。

  6. 然后我们有这个str.len我不太明白,这个.len符号是什么?我知道这给出了字符串的大小,但是我们怎么写呢像这样?

  7. 系统调用:这个函数看起来像黑魔法,我知道 Os 在做一些卑鄙的把戏,但我对 OS 很无知,所以我看不懂这个东西在做什么。

  8. mov rax, 0x2000001: 现在我们需要退出程序,为什么我们需要将这个十六进制数加载到寄存器中(是的,我知道这是退出的命令,但又是什么实际上正在发生)。

  9. xor rdi, rdi:这可能是我得到的唯一位,我们通过异或相同的两个值将 rdi 寄存器的内容设置为 0。

  10. 系统调用:这是黑魔法

  11. str:“Hello World”:我明白了 :)

  12. .len: 我不明白这个.notation。我认为 $ 的意思是“这里的地址”或者至少这是我查过的东西,我认为它是正确的。

  1. 不,那只是导出符号。
  2. 不,它告诉汇编程序将以下内容放入哪个部分。 .text 是代码的默认部分。
  3. 不,那是一个标签。函数入口点通常由标签表示,但并非所有标签都是函数。
  4. 在 MacOS 上,值 0x2000004 是指定您想要 write 系统调用的代码。 OS 将查找 rax 以确定调用者想要什么。所有系统服务都有一个代码。你可以想象 OS 做类似 if (rax == 0x2000004) do_write(rdi, rsi, rdx);
  5. 的事情
  6. rdi是一个寄存器。你知道寄存器,对吧?与上面的第 4 点类似,OS 一旦确定您想要 write 将检查 rdi 以获取目标文件描述符。
  7. str.len 只是一种标签语法。该值在底部定义。不过,这应该加载到 rdx 而不是 rdi
  8. 它将控制转移到 OS。然后查看寄存器的内容并执行请求的操作。 OS 只是代码,尽管有特权。

至于(12),是的,$是当前位置,也就是字符串的结尾。所以减去字符串的开头会给你长度。前导点只是一个特殊标签,它指示汇编器在其前面加上最近的前一个非本地标签,在本例中为 str。所以这相当于写 str.len.