linux汇编知识总结(GAS和NASM汇编)

linux汇编总结(GAS和NASM汇编)

参考:
1. 阮一峰的网络日志:汇编语言入门教程
2. x86 Assembly Guide
3. Linux 汇编器:对比 GAS 和 NASM

目录:

1. 何为汇编?GAS和NASM汇编器对比
2. 基本的汇编语法与指令(基于AT&T语法)
3. 汇编中的系统调用
4. 几个汇编程序例子

1. 何为汇编?

assembly language --> 将文字指令(add,mov等)译成二进制机器码

.s 基于AT&T指令,采用GAS编译
.asm 基于intel指令,采用NASM编译
.o 链接文件,win下是obj文件
.a 静态链接,多个.o打包而成
.so 动态链接,多个.o打包而成

GAS汇编:基于AT&T指令,.s后缀
NASM汇编:基于intel指令,.asm后缀

GAS和NASM汇编器对比

GAS: GNU Assembler
NASM: Netwide Assembler

汇编格式对比:(linux64位下)
GAS编译 hello.s
as hello.s -o hello.o

NASM编译 hello.asm
nasm -f elf64 hello.asm -o hello.o
(elf64/elf32指定64/32位机器)

链接部分一致:
ld hello.o -o hello
(生成hello可执行文件)


2. AT&T语法汇编

UNIX上汇编基本基于AT&T语法,因此下面全部基于使用AT&T指令格式

x86的6个32位通用寄存器:
%eax %ebx %ecx %edx %edi %esi

系统调用的sys_exit():
int $0x80

基本语法示例:
movl $1 %eax 表示将1存入eax寄存器


2.1 格式段

.data段:已初始化的变量
.bss段:未初始化的变量
.text段:代码段

下面给出示例:

.data       
    msg:
	.ascii    "Hello, world!\n"    
	len = . - msg           
.text
    .global _start
_start:
    movl    $len,%edx
    movl    $msg,%ecx
    movl    $1,%ebx     
    movl    $4,%eax
    int    $0x80

    movl    $0,%ebx     
    movl    $1,%eax 
    int    $0x80
2.2 数据格式

.byte:1字节整型 0~255
.int:2字节整型 0~65535
.long:4字节整型 即C/C++的int
.ascii:1字节char字符

下面给出示例:

data_list:
	.long 12,34,98
data:
	.int 3456677
strHello:
	.ascii "luhao\0"  # 实际长度是6,末尾'\0'是结束符
2.3 寻址方式

立即寻址:
mov $1, %eax 将数值1送入eax寄存器

直接寻址:
mov 0xff004, %eax 将物理(虚拟)地址0xff004上的值送入eax寄存器

间接寻址:
mov (%ebx), %eax 将ebx中存的地址中的值,送入eax

基址寻址:
mov 4(%ebx), %eax 将ebx中存的地址的后4字节处(+4),送入eax中

索引寻址:
mov Data_List(, %ecx, 4), %eax
注意Data_List存放4字节的long,因此每次后移4字节
假设%ecx存的是0,则取出的是Data_List中第一个元素,送入eax中

2.4 系统调用

linux汇编知识总结(GAS和NASM汇编)_第1张图片


4. 几个汇编的示例

4.1 汇编输出"hello world"

重点:.ascii数据格式 sys_write系统调用

// hello.s
.data       
    msg:
	.ascii   "Hello world!\n"    
	len = . - msg           
.text
    .global _start
_start:
    movl    $len,%edx # size of buffer
    movl    $msg,%ecx # content of buffer
    movl    $1,%ebx   # fd 0:stdin 1:stdout
    movl    $4,%eax   # sys_write
    int    $0x80

    movl    $0,%ebx     
    movl    $1,%eax 
    int    $0x80


4.2 查找数值最大值

重点:.long数据格式 jmp指令 汇编实现循环loop

# max.s
# Code: find max element of the list
# GNU AS: based on AT&T
# %ebx: max
# %eax: tmp
# %edi: index

.data
    data_items:
    .long 1,2,3,4,5,0

.text
    .globl _start

_start:
    mov $0, %edi
    mov data_items(, %edi, 4), %eax
    mov %eax, %ebx
for_loop:
    cmp $0, %eax
    je exit_loop  # if eax==0, exit
    incl %edi
    mov data_items(, %edi, 4), %eax
    cmp %ebx, %eax
    jle for_loop
    mov %eax, %ebx
    jmp for_loop
exit_loop:
    mov $1, %eax
    int $0x80

# why can echo $? stdout "5" in %ebx? 

4.3 获取二进制中1的数量

重点:.lcomm数据格式(未初始化) 算式/逻辑移位

# pocnt.s
# count '1' in uint64_t of Binary-Format
.bss
    .lcomm buf,10

.data
    str:
	.ascii "test luhao!\n"

.text
    .globl _start

_start:
    mov $0x1111ffff1111ffff, %rax # number HEX
    mov $0, %edx   # count '1'
    mov $64, %ecx  # loop variable
    # 16 for int32
    # 32 for int64

_loop1:
    ror $1, %rax   # shift left 1
    jnc _loop2     # if CF=0, jump to loop2
    inc %edx       # else: count '1' += 1

_loop2:
    dec %ecx       # ecx -= 1
    jne _loop1     # if ecx!=0, go back to loop

    add $0x30, %edx
    mov $0, %rax
    mov %edx,buf(,%rax,1)
    mov $0xa, %edx
    inc %rax
    mov %edx,buf(,%rax,1)

    mov $1, %ebx   # fd: stdout
    mov $4, %rax   # sys_write
    mov $buf, %ecx # buf
    mov $2, %edx   # size
    int $0x80
    #mov $0, %ebx
    mov $1, %rax
    int $0x80

你可能感兴趣的:(linux,工具,C/C++)