Lesson 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.
注意: 驱动(Drivers) 之所以被叫做drivers 是因为内核字面上地使用它们来“驱动”硬件设备。
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.
举例来说,请求sys_exit(程序退出)需要将EAX设置为1再触发中断;请求sys_write(写入)需要将EAX设置为4。这个链接指向了一份Linux系统调用表
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段我们通过global标签告诉内核_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.
我们将使用sys_write来输出文本到控制台窗口。sys_write在x86架构的Linux系统调用表中是4号。此外,在触发系统调用之前,我们需要将其他三个参数写入EDX,ECX和EBX.
The arguments passed are as follows:
- EDX will be loaded with the length (in bytes) of the string.
- ECX will be loaded with the address of our variable created in the .data section.
- EBX will be loaded with the file we want to write to – in this case STDOUT.
参数如下:
- EDX 存入字符串长度
- ECX 存入.data段字符串变量的地址
- EBX 存入写入文件句柄,传入1意味着写入到标准输出(STDOUT)
We compile, link and run the program using the commands below.
通过如下的命令编译、链接和运行我们的程序。
; Hello World Program - asmtutor.com ; 编译: nasm -f elf helloworld.asm ; 链接 (64位系统需要指定elf_i386): ld -m elf_i386 helloworld.o -o helloworld ; 运行: ./helloworld SECTION .data msg db 'Hello World!', 0Ah ; 声明msg变量来储存字符串 SECTION .text global _start _start: mov edx, 13 ; 要写入的字节数,每个字母加上0Ah(换行符) mov ecx, msg ; 将要写入的内容的地址传递到ECX mov ebx, 1 ; 写入到STDOUT mov eax, 4 ; 将SYS_WRITE的系统调用编号写入EAX int 80h
Error: Segmentation fault