Lesson 1 第 1 课
Hello, world! 世界您好!
First, some background 首先,一些背景
Assembly language is bare-bones. The only interface a programmer has above the actual hardware is the kernel itself. In order to build useful programs in assembly we need to use the linux system calls provided by the kernel. These system calls are a library built into the operating system to provide functions such as reading input from a keyboard and writing output to the screen.
汇编语言是基本的。程序员在实际硬件之上的唯一接口是内核本身。为了在汇编中构建有用的程序,我们需要使用内核提供的 linux 系统调用。这些系统调用是操作系统中内置的库,用于提供从键盘读取输入和将输出写入屏幕等功能。
When you invoke a system call the kernel will immediately suspend execution of your program. It will then contact the necessary drivers needed to perform the task you requested on the hardware and then return control back to your program.
当您调用系统调用时,内核将立即暂停程序的执行。然后,它将联系在硬件上执行您请求的任务所需的必要驱动程序,然后将控制权交还给您的程序。
Note:
Drivers are called drivers because the kernel literally uses them to drive the hardware.
注意:驱动程序之所以被称为驱动程序,是因为内核实际上使用它们来驱动硬件。
We can accomplish this all in assembly by loading EAX with the function number (operation code OPCODE) we want to execute and filling the remaining registers with the arguments we want to pass to the system call. A software interrupt is requested with the INT instruction and the kernel takes over and calls the function from the library with our arguments. Simple.
我们可以在汇编中完成这一切,方法是用我们想要执行的函数号(操作代码 OPCODE)加载 EAX,并用我们想要传递给系统调用的参数填充剩余的寄存器。使用 INT 指令请求软件中断,内核接管并使用我们的参数从库中调用函数。简单。
For example requesting an interrupt when EAX=1 will call sys_exit and requesting an interrupt when EAX=4 will call sys_write instead. EBX, ECX & EDX will be passed as arguments if the function requires them. Click here to view an example of a Linux System Call Table and its corresponding OPCODES.
例如,当 EAX=1 将调用 sys_exit 时请求中断,而当 EAX=4 将调用 sys_write 时请求中断。如果函数需要,EBX、ECX和EDX将作为参数传递。单击此处查看 Linux 系统调用表及其相应 OPCODES 的示例。
Writing our program 编写我们的程序
Firstly we create a variable 'msg' in our .data section and assign it the string we want to output in this case 'Hello, world!'. In our .text section we tell the kernel where to begin execution by providing it with a global label _start: to denote the programs entry point.
首先,我们在 .data 部分创建一个变量 'msg',并为其分配我们想要输出的字符串,在本例中为 'Hello, world!'。在我们的 .text 部分中,我们通过为内核提供一个全局标签 _start: 来表示程序入口点,从而告诉内核从哪里开始执行。
We will be using the system call sys_write to output our message to the console window. This function is assigned OPCODE 4 in the Linux System Call Table. The function also takes 3 arguments which are sequentially loaded into EDX, ECX and EBX before requesting a software interrupt which will perform the task.
我们将使用 system 调用 sys_write将我们的消息输出到控制台窗口。此函数在 Linux 系统调用表中被分配为 OPCODE 4。该函数还接受 3 个参数,这些参数在请求执行任务的软件中断之前按顺序加载到 EDX、ECX 和 EBX 中。
The arguments passed are as follows:
传递的参数如下:
- EDX will be loaded with the length (in bytes) of the string.
EDX 将加载字符串的长度(以字节为单位)。 - ECX will be loaded with the address of our variable created in the .data section.
ECX 将加载在 .data 部分中创建的变量的地址。 - EBX will be loaded with the file we want to write to – in this case STDOUT.
EBX 将加载我们想要写入的文件 – 在本例中为 STDOUT。
传递的参数的数据类型和含义可以在函数的定义中找到。
We compile, link and run the program using the commands below.
我们使用以下命令编译、链接和运行程序。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | ; Hello World Program - asmtutor.com ; Compile with: nasm -f elf helloworld.asm ; Link with (64 bit systems require elf_i386 option): ld -m elf_i386 helloworld.o -o helloworld ; Run with: ./helloworld SECTION .data msg db 'Hello World!' , 0Ah ; assign msg variable with your message string SECTION .text global _start _start: mov edx , 13 ; number of bytes to write - one for each letter plus 0Ah (line feed character) mov ecx , msg ; move the memory address of our message string into ecx mov ebx , 1 ; write to the STDOUT file mov eax , 4 ; invoke SYS_WRITE (kernel opcode 4) int 80h |
Error:
Segmentation fault
错误:分段错误