当前位置:网站首页>哪个编程语言实现hello world最烦琐?
哪个编程语言实现hello world最烦琐?
2022-06-25 04:01:00 【大方老师讲单片机】
哪个编程语言实现hello world最烦琐?
说明:
·由于汇编是一种直接面向底层的语言,所以最简单的程序也会涉及到许多底层的细节从而显得晦涩(不像C直接一个printf搞定);
·本篇文章通过最简单的hello world程序,理解寄存器、内存、节、指令、系统调用,在程序的简单运作原理;
Talk is cheap, show me your code!
;源代码文件名:test.asm
;执行文件名:test
;编译方法:
;nasm -f elf64 -g -F dwarf test.asm -l test.lst
;gcc -o test test.o -no-pie
section .data;在.data节写入数据
msg: db "hello world",10;10对应的ascii是换行符
msgLen equ $-msg;equ是伪指令,这行代码的意思是msgLen指代着msg字符串的占位长度(字节)
section .text;在.text写入代码
global main;程序的代码入口标签为main(使程序执行的时候能够找到第一个指令)
main:;这个标签实质指代了.text节的第一个指令的内存地址
;屏幕打印
mov rax, 1;sys_write(x86-64)
mov rdi, 1;1是标准输出
mov rsi, msg
mov rdx, msgLen;字符串长度,不包括0
syscall;64位的int 0x80指令
;退出程序
mov rax, 60;exit(x86-64)
mov rdi, 0;参数0,与上条指令结合是exit(0)
section语句
要了解section语句的作用,首先我们要先初步大概了解一下程序的执行原理,如下,

·编译器在编译汇编代码的时候,会按照Linux的ELF(linux的可执行文件格式)进行编译(例如插入ELF header、program header、section header、got等);
·程序运行的时候,则把代码和一些已经初始化的数据装载按照格式装载到内存(分布到各个section);
·stack节,在程序运行的过程中会根据程序逻辑压入或者弹出数据(stack节一般情况下不存储代码);
·heap节,用于程序的最自由的数据存储的区域(例如当C的malloc函数申请内存时使用的就是这个区域);
·bss节,用于存储定义了但是没有初始化的数据(例如C的int i、char ch[10]),常用于程序的数据接收缓冲区;
·data节,用于存储已经定义了并且已经初始化的数据(类似于C的常量);
·text节,用于存储代码(函数的代码也是存储在这个区域,而不是存储在stack区域);
综上所述,section语句的作用是区分汇编代码的区域。
syscall和中断向量表
在介绍syscall指令之前,需要先介绍linux的几个关键的概念,如下,
·用户空间(用户空间的本质是指定的内存空间。这些空间用于运行用户的程序,例如nginx、apache);
·内核空间(内核空间的本质也是内存空间,内核空间用于运行操作系统的代码,用户空间的应用程序原则上不能访问内核空间,又或者说不能直接访问内核空间,于是引入下面的概念——中断向量表);
·中断向量表(中断向量表的本质是一个数组,数组的元素是内存地址,这些地址指向内核空间)
syscall指令和中断向量表的关系如下,
用户进程想要调用系统服务(例如输出到屏幕、打开文件),需要统一通过向第128个中断向量,根据既定的数据结构发送系统调用服务请求
·应用程序是不能随意访问内核空间,需要通过既定的规则来进行访问,所以设计出了中断向量表(这样设计有安全意义);
·因为中断向量表有“指示牌”的方向意义,所以叫做“向量”表;
综上所述,在终端(一般是屏幕)打印hello world,实质上是一次调用系统服务的过程。
linux系统调用(sys_write)
上文中提到,想要调用系统服务,需要按照这个服务的既定数据结构,然后组织这些数据,向第128号的中断向量发送服务调用请求,如下图,
把需要打印的内容组织好,通过syscall指令向第128号中断发送“标准输出”的服务调用请求
·寄存器rax的内容要设置成1。在系统调用的过程中,这个寄存器一般都是用于存储系统服务的调用编号。而打印的服务编号是“1”(要查看系统调用服务编号可查看文件/usr/include/x86_64-linux-gnu/asm/unistd_64.h)
·寄存器rdi(destination index),用于指定打印输出的文件描述符(屏幕的文件描述符是1);
·寄存器rsi(source index),用于指定输出内容的地址(字符串的存储地址);
·寄存器rdx,用于指定输出内容的长度(这个可以自定义,你想打印多长自己决定;上一篇文章提过,字符串在汇编的角度来看,只不过是连续的内存存储空间)
综上所述,通俗地描述打印hello world的过程(系统服务调用过程),如下,
·rax寄存器告诉操作系统,需要调用什么系统服务(1号服务是“标准输出”服务);
·rdi寄存器告诉操作系统,要在那里打印(一般打印在终端,也就是屏幕);
·rsi寄存器告诉操作系统,需要打印的内容在哪里可以找到;
·rdx寄存器告诉操作系统,需要打印的内容有多长(字节);
最后,打印服务调用完毕后,需要结束程序,相当于C的exit(0)函数,原理不再赘述,具体可参见上述提供的代码。
边栏推荐
- CTF_ Web:php weak type bypass and MD5 collision
- ThinkPHP is integrated with esaywechat. What's wrong with wechat payment callback without callback?
- Finereport displays and hides column data according to conditions
- Use of deferred environment variable in gbase 8s
- 515. find the maximum value / Sword finger offer II 095 in each tree row Longest common subsequence
- 为什么TCP握手刚刚好是3次呢?
- Part I Verilog quick start
- OOP栈类模板(模板+DS)
- GBASE 8s的级联删除功能
- Introduction to the isolation level of gbase 8s
猜你喜欢
随机推荐
重磅直播 | 相移法+多频外差之数学原理推导+实现
jsz中的join()
Xiaobai learns MySQL - Statistical 'opportunism'
Gbase 8s stored procedure flow control
Blob page in gbase 8s
The yii2 debug toolbar is missing
STM32的DMA双缓冲模式详解
Unit test coverage
Anaconda安装+TensorFlow安装+Keras安装+numpy安装(包含镜像和版本信息兼容问题)
什么是数据持久化?
Introduction to intstream API
彻底理解数据库事务
GBASE 8s的级联删除功能
2.0springmvc uses restful
如何筛选出和产品相关的词,精准排除掉无效词
GBASE 8s存储过程语法结构
Data view for gbase 8s
What is persistence? What are RDB and AOF in redis persistence?
LabVIEW development gas regulator
GBASE 8s的多线程结构



![[esp32 learning path 6 - Flash encryption]](/img/4c/f317ca4823dca50a9bccd285967ab0.png)





