使用YASM编程 - 01

YASM 继承了NASM ,扩展了支持的语法和平台
支持INTEL 格式语法和 GNU AS 语法
下面是一个例子,实现了简单的invoke 调用和编程的一个基本的框架
它能够:
0 win32 程序,控制台打印
1 调用外部程序
2 被外部调用(入口函数)
3 数据段
4 代码段
5 函数定义
6 函数从栈传入参数,从eax返回值
7 include 其他的文件
8 编译
9 链接

;;;;;;;;;;;;;;;;;;;;;;;;
;windows.inc
;;;;;;;;;;;;;;;;;;;;;;;;

%ifndef windows_inc
%define windows_inc 1

extern _CreateFileA@28
extern _CreateFileW@28
extern _MessageBoxA@16
extern _MessageBoxW@16
extern _OutputDebugStringA@4
extern _OutputDebugStringW@4
extern _ExitProcess@4


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;帮助我们像使用C语言一样使用API
;定义很多宏供用户使用

%define CreateFileA _CreateFileA@28
%define CreateFileW _CreateFileW@28
%define MessageBoxA _MessageBoxA@16
%define MessageBoxW _MessageBoxW@16
%define OutputDebugStringA _OutputDebugStringA@4
%define OutputDebugStringW _OutputDebugStringW@4
%define ExitProcess _ExitProcess@4
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


%endif

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;test.asm
;这个是 YASM 的样板程序,使用一下NASM的各个语法使以后变成可以参考这个程序
;大体一个程序使用一下的功能
; 入口:必须以 _ 开始,因为在link 的时候 link /entry:xxxx ,这个xxxx 是C的符号xxxx,
;       真实的是_xxxx
; 数据段:
;   section .data  ; 在masm中是  .data 没有section修饰
; 代码段:
;   section .text  ; 在masm中是  .code
; 导出的符号:
;   global xxxx
;   必须要导出入口,否则链接程序找不到这个入口函数
; 引入的符号:
;   extern xxxx
;   说明这个符号是外部的,在此不存在,只是一个占位符,在其他模块应该能够找到它
; 伪操作符
;    db
;   dw
;   equ
; 宏定义
;   %define xxxx yyyyyy ; 和 C的宏样子类似
; 调用约定:
;   这里没有调用约定,所以导入的符号的名称都比较原始
;   比如:MessageBoxA 这个函数,在dll内部其实是_MessageBoxA@16(因为它有4个函数所以叫16)
;   调用的时候 stdcall 不需要处理栈平衡,因此在我们call了之后什么都没有处理
;   调用C函数的时候如何处理呢?
;    push hello
;    call _printf
;    add esp,4
;    只能这样手动的维持栈平衡
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;test.asm
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;编译和链接
;vsyasm -f win32 -o obj test.asm
;link /entry:start /subsystem:console /debug /machine:x86 /out:test.exe /release /verbose:lib 
;     /libpath:"C:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\Lib"  
;     kernel32.lib user32.lib test.obj msvcrt.lib
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;数据段,不可变
;SECTION .data 都可以
%include "windows.inc"

SECTION .data
    HelloMsg: db "Hello",0
    TitleString db "msg",0
    Hello : db "Hello Yasm",0x0a,0
    printFormat : db "retValue=%d",0x0a,0
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;includelib---------------------------

extern _printf
;-------------------------------------



;压栈
;%macro push_param 1-* ;*表示宏的参数个数没有上限
;    %rep %0
        ;参数旋转,最后一个参数为1
;        %rotate -1
        ;将 %1 参数入栈
;        push %1
;    %endrep
;%endmacro
;;;;;;;;;;;;;;;;;;;;;;;;;;;
;macro invoke
;使用宏来实现MASM 中的invoke
;当参数最高达到2的时候,后续的
;参数全部编程%2
;invoke 只能调用参数个数>1的函数
;参数个数=0的函数请使用 call 来调用
;;;;;;;;;;;;;;;;;;;;;;;;;;;;
%macro invoke 2-*
    %define _j %1
    %rep %0-1
        %rotate -1
        push dword %1
    %endrep
    call _j
%endmacro

;%macro invoke 2+ ; 
    ;循环%0 表示宏的参数个数
;    push_param %2
;    call %1
;%endmacro
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

SECTION .text
global _start
printRetValue:
    push ebp
    mov ebp,esp
    mov eax,[ebp+8]
    invoke _printf,printFormat,eax
    add esp,8
    pop ebp
    ret
add1:
    push ebp
    mov ebp,esp
    mov eax,[ebp+8]
    mov edx,[esp+0ch]
    add eax,edx
    pop ebp
    ret
sayHello:
    mov eax,Hello
    push eax
    call _printf
    add esp,4
    ret
_start:
    invoke add1,100,200
    invoke printRetValue,eax
    call sayHello       
    invoke MessageBoxA,0,HelloMsg,TitleString,0
    push HelloMsg
    call OutputDebugStringA
    invoke ExitProcess,0
    ret

你可能感兴趣的:(汇编语言)