大小端
- 可以将内存想象为一个大数组。它包含字节。
- 每个地址存储内存“数组”的一个元素。每个元素都是一个字节。
- 例如我们有 4 个字节:
AA 56 AB FF
小端字节序
- 低地址存低位字节
1 2 3 4 |
0 FF 1 AB 2 56 3 AA |
大段字节序
- 高地址存低位字节
1 2 3 4 |
0 AA 1 56 2 AB 3 FF |
汇编程序组成
- data
- 用于声明初始化数据或常量
- bss
- 用于声明未初始化的变量
- text
- 用于代码
数据类型
- 字节
- 一个字节8个位
byte ptr
- 字
- 一个字两个字节
word ptr
- 双字
- 一个双字是 4 个字节
dword ptr
- 四字
- 一个四字是 8 个字节
qword ptr
- 双四字
- 一个双四字是 16 个字节
- 也就是有128位
示例1
- 数据段
- 3个常量
num1
,num2
,num3
1 2 3 4 |
section .data num1: equ 100 num2: equ 50 msg: db "hello,aet",10 |
声明数据
声明初始化数据
db
dw
dd
dq
dt
do
dy
dz
1 2 3 4 5 |
;; 初始化4个字节 db 0x01, 0x02, 0x03, 0x04 ;; 初始化一个字 dw ox1234 |
声明未初始化的变量
resb
resw
resd
resq
rest
reso
resy
resz
包括外部二进制文件
incbin
定义常数
equ
1 |
one equ 1 |
重复指令或数据
times
算术运算
add
:整数相加sub
:减去mul
:无符号乘法imul
:有符号乘法div
:无符号除法idiv
:有符号除法inc
:递增dec
:递减neg
:求补
控制流
1 2 3 |
;; 比较 cmp rax, 50 |
je
:如果相等jz
:如果为零jne
:如果不等于jnz
:如果不为零jg
:如果第一个操作数大于第二个操作数jge
:如果第一个操作数大于或等于第二个操作数ja
:与jg
相同,但执行无符号比较jae
:与jge
相同,但执行无符号比较
1 2 3 4 5 |
if (rax != 50) { exit(); } else { right(); } |
1 2 3 |
cmp rax, 50 jne .exit jmp .right |
jmp
:无条件跳转
1 |
jmp label |
1 2 3 4 5 6 7 8 9 |
_start: ;; do something jmp .exit .exit: mov rax, 60 mov rdi, 0 syscall |
示例2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
section .data num1: equ 100 num2: equ 50 msg: db "ok,ok\n" section .text global my_start my_start: mov rax, num1 mov rbx, num2 add rax, rbx cmp rax, 150 jne .exit jmp .right .right: mov rax, 1 mov rdi, 1 mov rsi, msg mov rdx, 6 syscall jmp .exit .exit: mov rax, 60 mov rdi, 0 syscall |
1 2 3 4 5 6 7 8 9 10 11 |
#include <iostream> extern "C" int my_start(); int main() { auto res = my_start(); std::cout << res << std::endl; return 0; } |
寄存器和栈
- 我们有
rax
,rbx
,rcx
,rdx
,rdi
,rsi
,rbp
,rsp
,以及r8-r15
16个通用寄存器可以用,严格来说还是比较少 - 但是我们可以使用栈,堆栈是内存中特殊区域,运行原理为后进先出
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
global _start section .text _start: mov rax, 1 call incRax cmp rax, 2 jne exit ;; ... incRax: inc rax ret |
参数
rdi
: 第一个参数rsi
: 第二个参数rdx
: 第三个参数rcx
: 第四个参数r8
: 第五个参数r9
: 第六个参数- 超过6个的参数将在堆栈中传递
堆栈指针
rbp寄存器
- 堆栈的基址指针寄存器,它指向当前堆栈帧的基址
rsp寄存器
- 堆栈指针,指向当前堆栈帧的顶部
push and pop
- 递增堆栈指针(RSP)并将参数存储在堆栈指针指向的位置
1 |
push arg |
- 将数据从堆栈指针指向的位置复制到参数,RSP会自动增加,指向新的栈顶位置
1 |
pop arg |
1 2 3 4 5 6 7 8 9 10 11 12 13 |
global _start section .text _start: mov rax, 1 mov rdx, 2 push rax push rdx mov rax, [rsp+8] ;; ... |
示例3
1 2 3 4 5 6 7 8 |
section .data SYS_WRITE equ 1 STD_IN equ 1 SYS_EXIT equ 60 EXIT_CODE equ 0 NEW_LINE db 0xa WRONG_ARGC db "Must be two command line argument", 0xa |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
section .text global _start _start: pop rcx cmp rcx, 3 jne argcError add rsp, 8 pop rsi call str_to_int mov r10, rax pop rsi call str_to_int mov r11, rax add r10, r11 |
1 2 3 4 5 6 7 8 9 10 11 12 13 |
argcError: ;; sys_write syscall mov rax, 1 ;; file descritor, standard output mov rdi, 1 ;; message address mov rsi, WRONG_ARGC ;; length of message mov rdx, 34 ;; call write syscall syscall ;; exit from program jmp exit |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
str_to_int: xor rax, rax mov rcx, 10 next: cmp [rsi], byte 0 je return_str mov bl, [rsi] sub bl, 48 mul rcx add rax, rbx inc rsi jmp next return_str: ret |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
print: ;;;; calculate number length mov rax, 1 mul r12 mov r12, 8 mul r12 mov rdx, rax ;;;; print sum mov rax, SYS_WRITE mov rdi, STD_IN mov rsi, rsp ;; call sys_write syscall jmp exit |
1 2 3 4 5 |
exit: mov rax, SYS_EXIT exit code mov rdi, EXIT_CODE syscall |
本文为原创文章,版权归Aet所有,欢迎分享本文,转载请保留出处!
你可能也喜欢
- ♥ Linux 进程间的通信方式和原理03/30
- ♥ 包管理器:各平台安装卸载相关记述09/17
- ♥ 51CTO:Linux C++网络编程五08/20
- ♥ Linux下修改用户密码记录08/08
- ♥ Linux 进程描述&&相关介绍03/28
- ♥ Dump分析:未捕获的异常,查看内存相关命令03/25