《汇编语言程序设计(AT&T语法)》读书笔记(一)

《汇编语言程序设计(AT&T语法)》读书笔记(一)


  • 第一个例程
  • 前言
  • 一、书中的第一个例程
  • 二、使用步骤
    • 1.提取例程中的算法
    • 2.改写例程
  • 总结



前言

书中的代码是32位的,在目前流行的X86_64的Linux版本中很难运行通过,所以有一个想法,把里面的32位汇编代码改成64位的以便方便学习研究。我并不想改变书中的代码风格,毕竟我是为了学习AT&T语法风格才看这本书的。
要编译运行就要有编译环境,原书中没有说明编译环境和使用的Linux版本,我用当下流行的版本运行,我所用的Linux版本:Ubuntu 20.04.3 X86_64 TLS,gcc 版本 9.3.0。



一、书中的第一个例程

.section .data
    output:
        .asciz "Now my age is %d\n"
    age:
        .int 23
# .data ends
.section .text
.global _start
_start:
        nop
        pushl $output
        pushl age
        call printf
        add $8, %esp
        pushl $0
        call exit

 要改成X86_64的64位汇编代码,并符合AMD64 ABI规范。我分两步走,第一步,提取例程中的算法,第二步,改写例程。


二、使用步骤


1.提取例程中的算法

这个例程看起来很简单,它调用了c语言的两个函数printf 和 exit,那么我们在改写成64位汇编代码时要符合AMD64 ABI的规范。为了方便编译,我们使用gcc,这样可以一步到位直接生成可执行文件。为了提取算法,我在这里引入一个虚拟CPU,这个CPU是尺度可变的,它有8个通用寄存器,分别是vAX,vBX,vCX,vDX,vSP,vBP,vSI,vDI,与实体的X86架构CPU中的寄存器对应。

与64位CPU的对应关系:

R0 R1 R2 R3 R4 R5 R6 R7
RAX RCX RDX RBX RSP RBP RSI RDI
vAX vCX vDX vBX vSP vBP vSI vDI

与32位CPU的对应关系:

R0D R1D R2D R3D R4D R5D R6D R7D
EAX ECX EDX EBX ESP EBP ESI EDI
vAX vCX vDX vBX vSP vBP vSI vDI

 有虚拟CPU还不够,还要一个中立的语言来描述,我采用自然语言并模拟BASIC指令来描述。

开始提取例程算法:

;Non-Basic Description for Assembly

statement
    label output:
            chap string '......'
    label age:
            int ?
end statement

declare extern function printf, exit

begin
        pass parameter for function
        call printf
        pass parameter for function
        call exit
end

汇编语言中的c函数调用要使用寄存器传递参数,传递参数的寄存器是有顺序的, 在64位的X86架构CPU中依次是RDI,RSI,RDX,RCX。现在把上面的算法描述语言改一改。

;Non-Basic Description for Assembly

statement
    label output:
            chap string '......'
    label age:
            int ?
end statement

declare extern function printf, exit

begin
        let vdi load address of label output
        let vsi load content from label age
        call printf
        let vdi = 0
        call exit
end

要把例程改写成64位的汇编代码只要把算法描述语言中的vdi,vsi改成rdi,rsi即可。 


2.改写例程

代码如下:

/*-----------------------------------------------------------------------------
At&T style Assembly program, would use:
            gcc -no-pie -o P1-test P1-test.S

-------------------------------------------------------------------------------*/
.section .data
    output:
        .asciz "Now my age is %d\n"
    age:
        .int 23
# .data ends
.section .text
.global main
.extern printf
.extern exit
main:
        nop
        pushq $output
        popq %rdi
        pushq (age)
        popq %rsi
        xor %rax, %rax
        call printf
        xor %rdi, %rdi
        call exit
# .text ends
# end _start


总结

为了方便编译,我用main作为入口标记,用gcc编译即可。
例如:gcc -no-pie -o P1-test P1-test.S

你可能感兴趣的:(算法,c语言)