汇编教程二(Intel 风格语法)

 https://www.tutorialspoint.com/assembly_programming/assembly_basic_syntax.htm

Intel x86 Assembly - 基础语法

本教程主要用的编译器的NASM ,NASM 采用的是Intel风格语法

Intel 汇编程序可以分为三个部分

  • data部分

  • bss部分 

  • text 部分.

data部分

data部分用于声明初始化数据或常量。此数据在运行时不会更改。您可以在此部分声明各种常量值、文件名或缓冲区大小等。

声明数据部分的语法是 -

section .data

bss 部分

bss部分用于声明变量声明 bss 部分的语法是 -

section .bss

text 部分

text部分用于保存实际代码。此部分必须以声明global _start开始,它告诉内核程序执行从哪里开始。

声明text部分的语法是 -

section .text
   global _start
_start:

注释

 Intel风格语法汇编语言注释以分号 (;) 开头。它可能包含任何可打印字符,包括空白。它可以单独出现在一行中,例如 :

; This program displays a message on screen

  或者,在同一行上连同一条指令,比如 :

add eax, ebx  ;adds ebx to eax

而 GNU gas(as)采用的是#作为注解。

Intel x86汇编语言声明

汇编语言程序由三种类型的声明语句组成 -

  • 可执行指令或指令
  • 汇编程序指令或伪操作
  • 宏.

可执行指令或简单指令告诉处理器做什么。每条指令都包含一个操作码(opcode)。每条可执行指令生成一条机器语言指令。  每条可执行指令生成一条机器语言指令。

汇编程序指令操作告诉汇编程序有关汇编过程的各个方面。这些是不可执行的,不会生成机器语言指令

基本上是一种文本substitution机制

Intel汇编语言语句的声明语法

Assembly language statements are entered one statement per line. Each statement follows the following format −

汇编语言语句每行输入一个声明语句。每个语句都遵循以下格式 -

[label]  mnemonic   [operands]   [;comment]

方括号中的字段是可选的。一条基本指令有两部分,第一部分是要执行的指令(或助记符)的名称,第二部分是操作数或命令的参数。

以下是典型的汇编语言语句的一些示例 :

INC COUNT        ; Increment the memory variable COUNT

MOV TOTAL, 48    ; Transfer the value 48 in the 
                 ; memory variable TOTAL
					  
ADD AH, BH       ; Add the content of the 
                 ; BH register into the AH register
					  
AND MASK1, 128   ; Perform AND operation on the 
                 ; variable MASK1 and 128
					  
ADD MARKS, 10    ; Add 10 to the variable MARKS
MOV AL, 10       ; Transfer the value 10 to the AL register

 

 实验环境:

[root@ht6 1]# nasm -v
NASM version 2.10.07 compiled on Jun  9 2014
[root@ht6 1]# uname -r
3.10.0-1160.62.1.el7.x86_64
[root@ht6 1]# cat /etc/redhat-release 
CentOS Linux release 7.9.2009 (Core)
[root@ht6 1]# as -v
GNU assembler version 2.27 (x86_64-redhat-linux) using BFD version version 2.27-44.base.el7_9.1
[root@ht6 1]# gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-redhat-linux/4.8.5/lto-wrapper
Target: x86_64-redhat-linux
Configured with: ../configure --prefix=/usr --mandir=/usr/share/man
....
Thread model: posix
gcc version 4.8.5 20150623 (Red Hat 4.8.5-44) (GCC)
平台是x86-64架构的linux操作系统,内核 x86_64

 

一、Intel x86-32 汇编的样例程序(Intel风格语法)

  test.c汇编程序 (注意程序是针对的32位的寄存器编写,采用的Intel风格语法,从右到左赋值)

section    .text
   global _start     ;must be declared for linker (ld)
    
_start:                ;tells linker entry point
   mov    edx,len     ;message length
   mov    ecx,msg     ;message to write
   mov    ebx,1       ;file descriptor (stdout)
   mov    eax,4       ;system call number (sys_write)
   int    0x80        ;call kernel
  
   mov    eax,1       ;system call number (sys_exit)
   int    0x80        ;call kernel

section    .data
msg db 'Hello, world!', 0xa  ;string to be printed
len equ $ - msg     ;length of the string

   test.asm使用NASM(默认是Intel风格语法)编译和链接test.asm汇编程序

[root@ht6 1]# yum install nasm   //如果没有,安装很简单

   
     Nasm编译步骤如下:
     首先确保已在 PATH 环境变量中设置
nasmld二进制文件的路径。现在,按照以下步骤编译和链接上述程序 :

  • 使用vim 键入以上代码并将其保存为 test.asm。//这里是.asm 而不是.s后缀

  • 确保您与保存hello.asm 的目录位于同一目录中。

  • 输入命令 :   nasm -f elf64  test.asm

  • 如果有任何错误,系统会在此阶段提示您。否则,将创建名为hello.o的程序目标文件。

  • 要链接目标文件并创建名为 test的可执行文件,请键入ld -m elf_i386 -s -o test test.o

  • 通过键入./test来执行程序。

   我们也可以直接运行 nasm -f elf64 test.asm && ld test.o && ./a.out

     实验过程: 

[root@ht6 2]# nasm -f elf test.asm && ld test.o && ./a.out
ld: i386 architecture of input file `test.o' is incompatible with i386:x86-64 output
[root@ht6 1]# nasm -f elf64 test.asm && ld test.o && ./a.out   //在x86-64平台上编译,必须改成elf64
Hello, world!
[root@ht6 2]# ls
a.out test.asm test.o

[root@ht6 2]# file a.out
a.out: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, not stripped
 
 小结:利用x86-64平台编译,结果兼容x86-32程序


 二、Intel x86-64 汇编的样例程序(Intel风格语法)

 样例来自: https://montcs.bloomu.edu/Information/LowLevel/Assembly/hello-asm.html
样例2: test1.asm(本汇编程序是针对的64位的寄存器进行编写的,风格采用的是Intel)
register用到了 rax、rdi、rsi、rdx等64-bits寄存器
; ----------------------------------------------------------------------------------------
; Writes "this is test x86-64" to the console using only system calls. Runs on 64-bit Linux only.
; To assemble and run:
;
;     nasm -felf64 test1.asm && ld test1.o && ./a.out
; ----------------------------------------------------------------------------------------

          global    _start

          section   .text
_start:   mov       rax, 1                  ; system call for write
          mov       rdi, 1                  ; file handle 1 is stdout
          mov       rsi, message            ; address of string to output
          mov       rdx, 13                 ; number of bytes
          syscall                           ; invoke operating system to do the write
          mov       rax, 60                 ; system call for exit
          xor       rdi, rdi                ; exit code 0
          syscall                           ; invoke operating system to exit

          section   .data
message:  db        "Hello, World", 10      ; note the newline at the end

  实验过程:

[root@ht6 1]# nasm -f elf64 test1.asm && ld test1.o && ./a.out
Hello, World
[root@ht6 1]# file test1.asm
test1.asm: ASCII text
[root@ht6 1]# file a.out
a.out: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, not stripped

 

三、GCC(AS) x86-64 汇编的样例程序(风格语法为AT&T)

   样例3: 本例用gcc来进行编译
  aozhejin.s (本汇编程序是针对的64位寄存器编写的,语法风格采用的是AT&T,所以用gcc(as)来进行编译)

# ----------------------------------------------------------------------------------------
# Writes "this is test" to the console using only system calls. Runs on 64-bit Linux only.
# To assemble and run:
#
#     gcc -c aozhejin.s && ld aozhejin.o && ./a.out
#
# or
#
#     gcc -nostdlib aozhejin.s && ./a.out
# ----------------------------------------------------------------------------------------

        .global _start

        .text
_start:
        # write(1, message, 13)
        mov     $1, %rax                # system call 1 is write
        mov     $1, %rdi                # file handle 1 is stdout
        mov     $message, %rsi          # address of string to output
        mov     $13, %rdx               # number of bytes
        syscall                         # invoke operating system to do the write

        # exit(0)
        mov     $60, %rax               # system call 60 is exit
        xor     %rdi, %rdi              # we want return code 0
        syscall                         # invoke operating system to exit
message:
        .ascii  "this is test\n"

实验过程:

[root@ht5 s]# gcc -c aozhejin.s && ld aozhejin.o && ./a.out   //编译通过
this is test

 

     指令

       汇编代码是很多条指令的序列,一个指令可以完成一个CPU操作。那我们就先来细细研究一下单条指令的特征和格式。

   一条指令由操作码和0~2个操作数构成。操作码指定了当前指令要执行的操作,如将两数相加,操作数则是操作码的作用对象。因此可以看出,指令的长度不固定,短则1个字节,长则15字节。

  1.操作码(opcode)
           操作码是指令的第一部分,它告诉计算机执行什么功能,也称为 操作码。操作码是保存提供给计算机系统的指令的数字代码。 这些指令描述了 CPU 要执行的操作。计算机系统为赋予它的每个功能都有一个操作码操作码。
       2.操作数(operand)
        
 操作数是指令的另一个第二部分,它指示计算机系统到哪里去寻找数据或指令,或将数据或指令存储到哪里。 操作数的数量因不同的计算机系统而异。每条指令指示计算机系统的控制单元要执行什么以及如何执行。 这些操作是算术、逻辑、分支操作等,具体取决于提供给计算机的问题。

    下面的样例只能运行在x86-32位的处理器上

;Copyright (c) 1999 Konstantin Boldyshev <konst@linuxassembly.org>
;
;"hello, world" in assembly language for Linux
;
;to build an executable:
;       nasm -f elf hello.asm   //如果想运行在x86-64平台需更换为 elf64
;       ld -s -o hello hello.o

section .text
; Export the entry point to the ELF linker or loader.  The conventional
; entry point is "_start". Use "ld -e foo" to override the default.
    global _start

section .data
msg db  'Hello, world!',0xa ;our dear string
len equ $ - msg         ;length of our dear string

section .text

; linker puts the entry point here:
_start:

; Write the string to stdout:

    mov edx,len ;message length
    mov ecx,msg ;message to write
    mov ebx,1   ;file descriptor (stdout)
    mov eax,4   ;system call number (sys_write)
    int 0x80    ;call kernel

; Exit via the kernel:

    mov ebx,0   ;process' exit code
    mov eax,1   ;system call number (sys_exit)
    int 0x80    ;call kernel - this interrupt won't return

 

posted @ 2023-03-03 19:56  jinzi  阅读(0)  评论(0)    收藏  举报