汇编语言教程(二) 汇编器 NASM(Intel语法)& as(AT&T语法) 样例

编译器种类

汇编语言取决于处理器的指令集和体系结构。

  有很多好的汇编器,例如 -

  • 微软汇编器采用Intel语法(MASM)
  • Borland Turbo 汇编编译器 (TASM)
  • AT&T 语法的汇编编译器 -  GNU gas(as)  //as是作为gcc的后端来使用的
  • Yet Another Assembler - YASM
  •  NASM是采用Intel风格语法的汇编编译器              

   两种语法和运行平台决定了,你可能会采用一种编译器
 

以下主要针对NASM和GNU的as 
实验环境:

//nasm 汇编器
[root@ht6 huibian]# nasm -v  //centos平台,yum install nasm安装即可
NASM version 2.10.07 compiled on Jun  9 2014

//gnu as 汇编器
[root@ht6 huibian]# as -v
GNU assembler version 2.27 (x86_64-redhat-linux) using BFD version version 2.27-44.base.el7_9.1

[root@ht6 huibian]# cat /etc/redhat-release 
CentOS Linux release 7.9.2009 (Core)

[root@ht6 huibian]# uname -a
Linux ht6.node 3.10.0-1160.62.1.el7.x86_64 #1 SMP Tue Apr 5 16:57:59 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux

 

一、编译器采用 NASM
      1) nasm采用intel语法
      2) nasm汇编文件后缀为 .asm
      3) 段采用 section .text  /  section .data / section .bbs
      4)注解采用 ; 形式
  
     例子1:   寄存器采用IA-32位架构汇编代码

;Copyright (c) 1999 Konstantin Boldyshev <konst@linuxassembly.org>
;
;"hello, world" in assembly language for Linux
;
;   to build an executable:
;       nasm -f elf test.asm
;       ld -s -o test test.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

  

    验证、编译test.asm

[root@ht6 huibian]# vim test.asm
[root@ht6 huibian]# nasm -f elf test.asm
[root@ht6 huibian]# ll
total 8
-rw-r--r-- 1 root root 932 Mar  5 18:18 test.asm
-rw-r--r-- 1 root root 640 Mar  5 18:18 test.o
[root@ht6 huibian]# ld -s -o test test.o
ld: i386 architecture of input file `test.o' is incompatible with i386:x86-64 output

这个程序编译是没有问题,因为符合语法,但是ld就会报错, 因为是x86-64平台

   ld: i386 architecture of input file `test.o' is incompatible with i386:x86-64 output
   
  例子2: 寄存器采用x86-64位架构汇编代码

; -----------------------------------------------------------------------------
; A 64-bit Linux application that writes the first 90 Fibonacci numbers. To
; assemble and run:
;
;     nasm -felf64 test1.asm && gcc test1.o && ./a.out
; -----------------------------------------------------------------------------

        global  main
        extern  printf

        section .text
main:
        push    rbx                     ; we have to save this since we use it

        mov     ecx, 90                 ; ecx will countdown to 0
        xor     rax, rax                ; rax will hold the current number
        xor     rbx, rbx                ; rbx will hold the next number
        inc     rbx                     ; rbx is originally 1
print:
        ; We need to call printf, but we are using rax, rbx, and rcx.  printf
        ; may destroy rax and rcx so we will save these before the call and
        ; restore them afterwards.

        push    rax                     ; caller-save register
        push    rcx                     ; caller-save register

        mov     rdi, format             ; set 1st parameter (format)
        mov     rsi, rax                ; set 2nd parameter (current_number)
        xor     rax, rax                ; because printf is varargs

        ; Stack is already aligned because we pushed three 8 byte registers
        call    printf                  ; printf(format, current_number)

        pop     rcx                     ; restore caller-save register
        pop     rax                     ; restore caller-save register

        mov     rdx, rax                ; save the current number
        mov     rax, rbx                ; next number is now current
        add     rbx, rdx                ; get the new next number
        dec     ecx                     ; count down
        jnz     print                   ; if not done counting, do some more

        pop     rbx                     ; restore rbx before returning
        ret
format:
        db  "%20ld", 10, 0

  验证、编译 test1.asm 

[root@ht6 huibian]# nasm -felf64 test1.asm
[root@ht6 huibian]# ll
total 12
-rw-r--r-- 1 root root 0 Mar 5 18:21 a.out
-rw-r--r-- 1 root root 2021 Mar 5 18:56 test1.asm
-rw-r--r-- 1 root root 832 Mar 5 18:56 test1.o
-rw-r--r-- 1 root root 932 Mar 5 18:18 test.asm

  [root@ht6 huibian]# gcc test1.o && ./a.out

  编译通过....

  test1.asm 输出的结果 分析一下:

[root@ht6 huibian]# size a.out
text    data    bss    dec    hex    filename
1208    548    4    1760    6e0    a.out


   我们看下 NASM程序的结构大概是下面的样子, 图片来自: https://cs.lmu.edu/~ray/notes/nasmtutorial/

 

 

 

 

 二汇编语法采用AT&T语法,采用GNU Gas(as) 编译器
     1) gnu as采用AT&T语法
     2) 段使用 .text .data .bbs
     3)注解采用#形式
     4) 文件后缀为.s

# ----------------------------------------------------------------------------------------
# Writes "Hello, World" 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   //编译通过
   
   三、NASM 和 as 使用小结:
   1、Intel和AT&T 语法是不同的
   2、as是从左到右赋值,而nasm是从右到左
   3、注解as是 #, 而 nasm采用;
   4、标签也不同等。
   所以他们之间差异还是比较大的。

  

 

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