溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

C指針原理之AT&T匯編的示例分析

發(fā)布時(shí)間:2021-08-23 09:40:23 來源:億速云 閱讀:129 作者:小新 欄目:編程語言

這篇文章給大家分享的是有關(guān)C指針原理之AT&T匯編的示例分析的內(nèi)容。小編覺得挺實(shí)用的,因此分享給大家做個(gè)參考,一起跟隨小編過來看看吧。

匯編在LINUX系統(tǒng)下的意義遠(yuǎn)遠(yuǎn)大于WINDOWS系統(tǒng),LINUX內(nèi)核部分代碼就是匯編編寫的。然后,絕大多數(shù) Linux 程序員以前只接觸過DOS/Windows 下的匯編語言,這些匯編代碼都是 Intel 風(fēng)格的。但在 Unix 和 Linux 系統(tǒng)中,更多采用的還是 AT&T 格式,兩者在語法格式上有著很大的不同,因此應(yīng)對(duì)AT&T匯編應(yīng)有一個(gè)基本的了解和熟悉。

    我們?cè)贚INUX下用C編寫一段最簡(jiǎn)單的helloworld程序,命令為hello.c

#include <stdio.h>
 int main()
{ 
printf("hello,world\n");
 exit(0); 
}

然后,使用GCC編譯,同時(shí)使用-s參數(shù)生成中間匯編代碼,看看AT&T匯編的真實(shí)面目

.section .data#初始化的變量
output:
   .ascii "hello,world\n"
   #要打印的字符串,.data為初始化值的變量。output是標(biāo)簽,指示字符串開始的位置,ascii為數(shù)據(jù)類型
.section .bss#未初始化的變量,由0填充的緩沖區(qū)
   .lcomm num,20
   #lcomm為本地內(nèi)存區(qū)域,即本地匯編外的不能進(jìn)行訪問。.comm是通用內(nèi)存區(qū)域。
.section .text#匯編語言指令碼
   .globl _start#啟動(dòng)入口
   _start:
   movl $4,%eax#調(diào)用的系統(tǒng)功能,4為write  
   movl $output,%ecx#要打印的字符串
   movl $1,%ebx#文件描述符,屏幕為1  
   movl $12,%edx#字符串長(zhǎng)度
   int $0x80#顯示字符串hello,world
   movl $0,%eax
   movl $num,%edi
   movl $65,1(%edi)#A 的ascii
   movl $66,2(%edi)#B 的ascii
   movl $67,3(%edi)#C 的ascii
   movl $68,4(%edi)#D 的ascii
   movl $10,5(%edi)#\n的ascii
   movl $4,%eax#調(diào)用的系統(tǒng)功能,4為write   
   movl $num,%ecx#要打印的字符串 
   movl $1,%ebx#文件描述符,屏幕為1  
   movl $6,%edx#字符串長(zhǎng)度
   int $0x80#顯示字符串ABCD
   movl $1,%eax#1為退出
   movl $0,%ebx#返回給shell的退出代碼值
   int $0x80#內(nèi)核軟中斷,退出系統(tǒng)

gcc -S hello.c

.file  "hello.c"

  .section  .rodata

.LC0:

  .string "hello,world"

  .text

.globl main

  .type  main, @function

main:

  pushl  %ebp

  movl  %esp, %ebp

  andl  $-16, %esp

  subl  $16, %esp

  movl  $.LC0, (%esp)

  call  puts

  movl  $0, (%esp)

  call  exit

  .size  main, .-main

  .ident "GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3"

  .section  .note.GNU-stack,"",@progbits

匯編器(assembler)的作用是將用匯編語言編寫的源程序轉(zhuǎn)換成二進(jìn)制形式的目標(biāo)代碼。Linux 平臺(tái)的標(biāo)準(zhǔn)匯編器是 GAS,它是 GCC 所依賴的后臺(tái)匯編工具,通常包含在 binutils 軟件包中。
AT&T匯編主要有以下特點(diǎn):
1、在 AT&T 匯編格式中,寄存器名要加上 '%' 作為前綴。

如:

把eax寄存器的內(nèi)容復(fù)制到ebx中

movl %eax,%ebx
2、用 '$' 前綴表示一個(gè)立即操作數(shù)。

如:將1復(fù)制到eax中

movl $1, %eax
3、目標(biāo)操作數(shù)在源操作數(shù)的右邊

movl %eax,%ebx
eax是源操作數(shù),ebx是目標(biāo)操作數(shù)
4、在 AT&T 匯編格式中,操作數(shù)的字長(zhǎng)由操作符的最后一個(gè)字母決定,后綴'b'、'w'、'l'分別表示操作數(shù)為字節(jié)(byte,8 比特)、字(word,16 比特)和長(zhǎng)字(long,32比特)

比如:

movl對(duì)32位進(jìn)行操作,將eax寄存器32位的內(nèi)容復(fù)制到ebx中

movl %eax, %ebx

movw對(duì)16位進(jìn)行操作,將ax寄存器的內(nèi)容復(fù)制到bx中

movw %ax, %bx

movb對(duì)8位進(jìn)行操作,將al寄存器的內(nèi)容復(fù)制到bl中

movb %al, %bl

我們?cè)僖匀霔槔?

pushl %ecx  # 32位ecx的內(nèi)容入棧

pushw %cx   # 16位ecx的內(nèi)容入棧

pushl $180  # 80做為一個(gè)32位整數(shù)入棧

pushl data  # data變量?jī)?nèi)容入棧,長(zhǎng)度為32位

pushl $data # 這一個(gè)操作很特別,在變量前面加上$表示取變量的地址,這是將data變量的地址入棧
5、在 AT&T 匯編格式中,絕對(duì)轉(zhuǎn)移和調(diào)用指(jump/call)的操作數(shù)前要加上'*'作為前綴
6、遠(yuǎn)程轉(zhuǎn)移指令和遠(yuǎn)程子調(diào)用指令的操作碼,在 AT&T 匯編格式中為 ljump和lcall
我們從生成的中間代碼可以看出這幾個(gè)特點(diǎn)。

我們?cè)賮砜匆欢斡肁T&T匯編編寫的helloworld程序。

.section .data#初始化的變量
output:
  .ascii "hello,world\n"
  #要打印的字符串,.data為初始化值的變量。output是標(biāo)簽,指示字符串開始的位置,ascii為數(shù)據(jù)類型
.section .bss#未初始化的變量,由0填充的緩沖區(qū)
  .lcomm num,20
  #lcomm為本地內(nèi)存區(qū)域,即本地匯編外的不能進(jìn)行訪問。.comm是通用內(nèi)存區(qū)域。
.section .text#匯編語言指令碼
  .globl _start#啟動(dòng)入口
  _start:
  movl $4,%eax#調(diào)用的系統(tǒng)功能,4為write  
  movl $output,%ecx#要打印的字符串
  movl $1,%ebx#文件描述符,屏幕為1  
  movl $12,%edx#字符串長(zhǎng)度
  int $0x80#顯示字符串hello,world

  movl $0,%eax
  movl $num,%edi
  movl $65,1(%edi)#A 的ascii
  movl $66,2(%edi)#B 的ascii 
  movl $67,3(%edi)#C 的ascii 
  movl $68,4(%edi)#D 的ascii
  movl $10,5(%edi)#\n的ascii 

  movl $4,%eax#調(diào)用的系統(tǒng)功能,4為write  
  movl $num,%ecx#要打印的字符串 
  movl $1,%ebx#文件描述符,屏幕為1  
  movl $6,%edx#字符串長(zhǎng)度
  int $0x80#顯示字符串ABCD

  movl $1,%eax#1為退出
  movl $0,%ebx#返回給shell的退出代碼值

  int $0x80#內(nèi)核軟中斷,退出系統(tǒng)

我們對(duì)上面這段匯編代碼的結(jié)構(gòu)和內(nèi)容進(jìn)行解說:

1、.section .data段存放著初始化的變量, .section .bss段存放著未初始化的變量

2、變量的定義采用以下格式:
變量名:
  變量類型 變量值
上面代碼中的output變量就是這么定義的
output:
   .ascii "hello,world\n"
下面例子定義了多個(gè)變量
.section .data
msg:
.ascii “This is a text”
x:
.double 109.45, 2.33, 19.16
y:
.int 89
z:
.int 21, 85, 27
 
.equ  a 8
 
其中,msg為字符符,x為雙精度符點(diǎn)數(shù),y和z為整數(shù),a是一個(gè)特別的定義,它的是一個(gè)靜態(tài)變量的定義,使用.equ 變量名 變量值來實(shí)現(xiàn)

3、.section .bss段中變量訪問區(qū)域的定義規(guī)則為:

lcomm為本地內(nèi)存區(qū)域,即本地匯編外的不能進(jìn)行訪問,而.comm是通用內(nèi)存區(qū)域
比如上面的定義
 .lcomm num,20 
num為本地內(nèi)存區(qū)域。

4、section .text段為匯編語言指令碼,使用.globl _start指示_start標(biāo)記后的代碼為程序啟動(dòng)入口。

5、#表示注釋,上面代碼的其它部分均有注釋,有匯編基礎(chǔ)的程序員應(yīng)很容易理解

變量的類型有以下幾種:
.ascii 文本字符串
.asciz 以NULL結(jié)束的文本字符串
.byte  字節(jié)值
.double 雙精度符點(diǎn)數(shù)
.float 單精度符點(diǎn)數(shù)
.int 32位整數(shù)
.long 32位整數(shù)
.octa 16位整數(shù)
.quad 8位整數(shù)
.short 16位整數(shù)
.single 單精度符點(diǎn)數(shù)

此外,AT&T匯編經(jīng)常會(huì)涉及字節(jié)順序反轉(zhuǎn),比較加載,交換,壓入彈出所有寄存器等操作,以下例子涉及了這些操作,
每行代碼都有詳細(xì)的注釋。

.bss段定義的數(shù)據(jù)元素為未初始化的變量,在運(yùn)行時(shí)對(duì)其進(jìn)行初始化。

可分為數(shù)據(jù)通用內(nèi)存區(qū)域和本地通用內(nèi)存區(qū)域

本地通用內(nèi)存區(qū)域不能從本地匯編代碼之外進(jìn)行訪問。

.text段存放代碼

感謝各位的閱讀!關(guān)于“C指針原理之AT&T匯編的示例分析”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,讓大家可以學(xué)到更多知識(shí),如果覺得文章不錯(cuò),可以把它分享出去讓更多的人看到吧!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI