asm

asm

demo

hello world

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
section .data
    hello db "hello world!", 0xa, 0

section .text

global main;  // 程序入口点,要调c的库函数要用main,否则链接时提示找不到main

main:
    push dword hello  ;; //c函数参数传递放在栈中
    extern printf           
    call printf                 ; // 调用外部函数的作用

    add esp, byte 4      ;; // 事实上这是一个出栈动作,以让程序找到正确的地址进行返回
    ret
1
2
nasm -f elf hello.asm -o hello.o
tcc  hello.o -o hello.exe -m32

1 加到 100

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
section .data
    format db "%d", 0xa, 0;

section .text

    global main
    main:
        mov eax, 0
        mov ecx, 100

    l:
        add eax, ecx
        loop l
        ;mov eax, (1+100)*100/2;

        extern printf
        push dword eax;
        push dword format;   printf(const char*,...);
        call printf
        add esp, byte 8
        ret

win32

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
STD_OUTPUT_HANDLE   equ -11
NULL                equ 0

global main

extern ExitProcess, GetStdHandle, WriteConsoleA

section .data
msg                 db "Hello World!", 13, 10, 0
msg.len             equ $ - msg

section .bss
dummy               resd 1

section .text

main:
    push    STD_OUTPUT_HANDLE
    call    GetStdHandle

    push    NULL
    push    dummy
    push    msg.len
    push    msg
    push    eax
    call    WriteConsoleA 

    push    NULL
    call    ExitProcess

http://www.godevtool.com/Golink.zip

1
2
nasm -f win32 hello.asm -o hello.obj
GoLink.exe /console /entry GobleyGook hello.obj kernel32.dll

tcc只支持elf格式,gcc/vc的是coff格式


汇编格式

主要列一些 AT&T 和 intel 汇编区别

  • 相反的源和目标操作数次序、立即数 $
1
2
Intel:mov eax, 4
AT&T:movl $4, %eax
  • 操作数大小标识
1
2
Intel:mov al, byte ptr foo
AT&T:movb foo, %al

一个用 byte ptr ,一个用 movb

汇编器区别

masm , nasm

1
2
3
; masm 编译器自动加上:
;   push ebp
;   mov ebp,esp
1
2
3
;masm
mov edi,[PVal];  mov edi,PVal 结果一样
 mov eax,[var1];  mov eax,var1 结果一样

Nasm最接近编译后的程序,MASM在源码上方便了程序的代码编写操作,但隐藏太多底层的细节

可执行文件格式

os 读可 ELF 文件头部,找到标记为可加载(loadable)的段,调 mmap()把段内容加载到内存中,段标记作用内存中是否可读、可写,可执行

a.out 不适应共享库,COFF可包含更多的段,但对动态连接和C++程序的支持仍然比较困难

unix 开发出 ELF格式,作为ABI(应用和内核底层接口)

比如有初始化段.init和结束段.fini(对应构和析构函数)支持C++

ABI

  • 数据类型的大小、布局和对齐
  • 调用约定(函数参数如何传送以及如何接受返回值),如参数通过栈传递,还是部分参数通过寄存器传递;哪个寄存器用于哪个函数参数;通过栈传递的第一个函数参数是最先push到栈上还是最后
  • 系统调用的编码和一个应用如何向操作系统进行系统调用
  • C++ 名称修饰

API 对应源码的可编译,ABI对应目标文件的可直接运行