汇编速查-IA32汇编helloword

本文介绍了IA32汇编语言的基础,包括AT&T语法、数据段定义、C库函数的使用,以及如何通过汇编程序实现Linux系统调用如helloworld和cpuid。涉及的内容包括编译、调试和段如.data、.rodata、bss的使用。

AT&T语法

  1. $表示立即数,引用10进制数4,AT&T语法 $4,Intel语法是4
  2. AT&T语法在寄存器前加 % ,Intel语法不需要
  3. AT&T语法处理源操作数和目的操作数和Intel语法相反
    AT&T: movl $4, %eax
    Intel: mov eax, 4
  4. AT&T语法在助记符后使用一个单独的字符来引用操作中使用的数据长度, Intel 语法中数据长度被声明为单独的操作数
    AT&T: movl $test, %eax
    Intel: mov eax, dword ptr test
  5. 长调用和跳转使用不同的语法定义段和偏移值
    AT&T: ljmp $section, $offset
    Intel: jmp section:offset

cpuid.s的编译

汇编器$: as -o cpuid.o cpuid.s
连接器$: ld -o cpuid cpuid.o

gdb是命令行调试器
objdump反汇编器 obj=>汇编$objdump -d test.o
gprof简档器 ,分析程序的执行和确定应用程序中的“热点”

$./demo
...
$gprof demo > gprof.txt

汇编程序的基础模板

.section  .data     
;.section命定义段 参数只能为 .data, .bss, .text
;.data 是初始化了的数据
.section .bss
;使用0(null)初始化,常用做汇编语言程中的缓冲区
.section .text      
;文本段,所有汇编语言程序中都必须有文本段,数据段,bss段是可选的
.globl   _start     
;.globl命令声明外部程序可以访问的程序,如过编写外部汇编程序或C语言程序使用的一组工具,应该用.globl声明每个函数标签
_start:         
;定义起始点,连接器必须知道指令码的起点,默认标签是_start,表明程序应该从这条指令开始执行

这里写图片描述

定义数据元素

.data 命令声明数据段

这个段中的任何元素都保留在内存中,并且可以被汇编程序中的指令读取和写入

.rodata 中数据段中的数据只能按照只读方式访问

数据段中定义元素需要一个标签和一个命令;
数据声明之后必须定义一个或多个默认值

命令数据类型
.ascii文本字符串
.asciz以空字符结尾的文本字符串
.byte字节值
.double双精度浮点值
.float单精度浮点值
.int32位整数
.long32位整数(同.int)
.octa16字节整数
.quad8字节整数
.short16位整数
.single单精度浮点数(和.float相同)

e.g.

pi:
  .float 3.14159
sizes:
  .long 100, 150, 200, 250, 300

定义静态符号

可以出现在数据段任何位置,建议在定义其他数据之前定义数据符号

.equ factor, 3
.equ LINUX_SYS_CALL, 0x80

使用$引用,movl LINUX_SYS_CALL, %eax

bss段

无需声明数据类型,只要声明为所需目的保留的原始内存部分即可

命令描述
.comm声明未初始化的数据的通用内存区域
.lcomm声明未初始化的数据的本地通用内存区域

这两种区域工作情况类似;
本地通用内存区域 是 为不会从本地汇编代码之外进行访问的数据保留的
e.g.

.section .bss
.lcomm buffer, 10000

这条语句把10000字节的内存区域赋值给bufffer标签。在声明本地通用内存区域的程序之外的函数是不能访问的(不能在.globl命令中使用他们)

bss段中声明的数据不包含在可执行程序中。

.section .data
buffer:
  .fill 1000
;.fill命令使汇编器自动创建1000个元素。默认为每个字段创建一个字节,并用0填充

helloworld hw.s

.section .data
word:
        .ascii "Hello world!\n"
.section .text
.globl _start
_start:

        movl $4, %eax
        movl $1, %ebx
        movl $word, %ecx
        movl $13, %edx
        int $0x80


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

int $0x80 Linux系统调用

  • write系统调用
    EAX 系统调用值
    EBX 要写入的文件描述符的值
    ECX 包含字符串的开头
    EDX 包含字符串的长度
  • exit系统调用
    EAX 系统调用值
    EBX 退出代码值

编译:

giantpoplar@Lenovo:~/Desktop$ as -o hw.o hw.s
giantpoplar@Lenovo:~/Desktop$ ld -o hw hw.o 

gdb调试

giantpoplar@Lenovo:~/Desktop$ as -gstabs -o hw.o hw.s
giantpoplar@Lenovo:~/Desktop$ ld -o hw hw.o 

1.单步运行

giantpoplar@Lenovo:~/Desktop$ gdb hw
加断点 break *_start 断点在start后的第一条指令
next/step执行下一条程序
cont继续执行

2.查看信息

info registers 显示寄存器内容
print显示特定寄存器,来自程序变量的值
print/x $ebx
x 显示特定内存位置的值

cpuid.s

;cpuid.s 
;Sample program to extract the processor Vendor ID
.section .data;cpuid.s 
output:
   .ascii "The processor Vendor ID is 'xxxxxxxxxxxx'\n"
.section .text
.globl _start
_start:
   movl $0, %eax
   cpuid
   movl $output, %edi
   movl %ebx, 28(%edi)
   movl %edx, 32(%edi)
   movl %ecx, 36(%edi)
   movl $4, %eax
   movl $1, %ebx
   movl $output, %ecx
   movl $42, %edx
   int $0x80
   movl $1, %eax
   movl $0, %ebx
   int $0x80
$as -o cpuid.o cpuid.s
$ld -o cpuid cpuid.o

使用C库函数

;cpuid2.s 
;View the CPUID Vendor ID string using C library calls

.section .datatext
output:
    .asciz "The processor Vendor ID is '%s'\n"
.section .bss
    .lcomm buffer, 12
.section .text
.globl _start
_start:
    movl $0, %eax
    cpuid
    movl $buffer, %edi
    movl %ebx, (%edi)
    movl %edx, 4(%edi)
    movl %ecx, 8(%edi)
    pushl $buffer
    pushl $output
    call printf
    addl $8, %esp
    pushl $0
    call exit

; .asciz在定义的字符串末尾添加空字符
; .lcomm buffer, 12  声名了12字节的缓冲区
; pushl 压栈,参数放入堆栈的顺序和printf函数获取他们的顺序是相反的
; call 指令调用printf函数
; addl 出栈8个字节
#连接 要使用32位的链接库
$as -o cpuid.o cpuid.s
$ld -dynamic-linker /lib/ld-linux.so.2  -o cpuid2 -lc cpuid.o
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值