首页 未分类

C语言基础

先来一段简单的C程序

//hello.c
#include<stdio.h>
int main(){
    printf("hello world");
    return 0;
}

C源码到二进制文件需要经过
预处理,编译,汇编,链接四个步骤

预处理

gcc -E hello.c -o hello.i

编译

编译也是生产汇编代码的过程

gcc -S hello.c -o hello.s

显示:

    .file    "hello.c"
    .text
    .section    .rodata
.LC0:
    .string    "hello world"
    .text
    .globl    main
    .type    main, @function
main:
.LFB0:
    .cfi_startproc
    pushq    %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    leaq    .LC0(%rip), %rdi
    movl    $0, %eax
    call    printf@PLT
    movl    $0, %eax
    popq    %rbp
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE0:
    .size    main, .-main
    .ident    "GCC: (Arch Linux 9.3.0-1) 9.3.0"
    .section    .note.GNU-stack,"",@progbits

编译过程就是把预处理完的文件进行一系列词法分析,语法分析,语义分析,及优化后生产相应的汇编代码

汇编

gcc -c hello.c -o hello.o 
或者
gcc -c hello.s -o hello.o 

可以使用

objdump -sd hello.o
hello.o:     文件格式 elf64-x86-64

Contents of section .text:
 0000 554889e5 488d3d00 000000b8 00000000  UH..H.=.........
 0010 e8000000 00b80000 00005dc3           ..........].    
Contents of section .rodata:
 0000 68656c6c 6f20776f 726c6400           hello world.    
Contents of section .comment:
 0000 00474343 3a202841 72636820 4c696e75  .GCC: (Arch Linu
 0010 7820392e 332e302d 31292039 2e332e30  x 9.3.0-1) 9.3.0
 0020 00                                   .               
Contents of section .eh_frame:
 0000 14000000 00000000 017a5200 01781001  .........zR..x..
 0010 1b0c0708 90010000 1c000000 1c000000  ................
 0020 00000000 1c000000 00410e10 8602430d  .........A....C.
 0030 06570c07 08000000                    .W......        

Dis of section .text:

0000000000000000 <main>:
   0:    55                       push   %rbp
   1:    48 89 e5                 mov    %rsp,%rbp
   4:    48 8d 3d 00 00 00 00     lea    0x0(%rip),%rdi        # b <main+0xb>
   b:    b8 00 00 00 00           mov    $0x0,%eax
  10:    e8 00 00 00 00           callq  15 <main+0x15>
  15:    b8 00 00 00 00           mov    $0x0,%eax
  1a:    5d                       pop    %rbp
  1b:    c3                       retq   

汇编器将汇编代码转变成机器可以执行的指令

链接

gcc hello.o -o hello

查看

objdump -d -j .text hello 

hello:     文件格式 elf64-x86-64


Dis of section .text:

0000000000001040 <_start>:
    1040:    f3 0f 1e fa              endbr64 
    1044:    31 ed                    xor    %ebp,%ebp
    1046:    49 89 d1                 mov    %rdx,%r9
    1049:    5e                       pop    %rsi
    104a:    48 89 e2                 mov    %rsp,%rdx
    104d:    48 83 e4 f0              and    $0xfffffffffffffff0,%rsp
    1051:    50                       push   %rax
    1052:    54                       push   %rsp
    1053:    4c 8d 05 76 01 00 00     lea    0x176(%rip),%r8        # 11d0 <__libc_csu_fini>
    105a:    48 8d 0d ff 00 00 00     lea    0xff(%rip),%rcx        # 1160 <__libc_csu_init>
    1061:    48 8d 3d d1 00 00 00     lea    0xd1(%rip),%rdi        # 1139 <main>
    1068:    ff 15 72 2f 00 00        callq  *0x2f72(%rip)        # 3fe0 <__libc_start_main@GLIBC_2.2.5>
    106e:    f4                       hlt    
    106f:    90                       nop

...

1 寄存器

1.1 数据寄存器

数据寄存器:用来操作数,计算结果
EAX(Accumulator) 累加寄存器
EBX(Base) 基地址寄存器
ECX(Count) 记数器寄存器
EDX(Data) 数据寄存器
32位寄存器:EAX,EBX,ECX,EDX
16位寄存器:ax,bx,cx,dx
eax --32
ax --16
al --低8位
ah --高8位

1.2 指针寄存器

指针寄存器:操作栈的寄存器
栈:参数,变量
EBP:栈底的指针
ESP:栈顶的指针 (改变)

1.3 变址寄存器

用来存放地址的寄存器
esi
edi

1.4 指令指针寄存器

eip :保存cpu下一步要执行的代码的地址

1.5 标志寄存器

标志寄存器:flag寄存器16位

1514131211109876543210
OFDFIFTFSFZF AF PF CF

格子为空的说明在8086cpu中没有使用,不具有意义
ZF --运算结果为非0 ZF就为0
  --运算结果为0 ZF就为1

1.6 段寄存器

举例:

mov dword ptr ds:[0x405528],edx

结构:

32bit32bit16bit16bit
BaseLimitattribute(属性)selecter段(可见)

2 指令

2.1 数据传送指令

mov

mov eax,ebx;
mov ax,bx;必须变量类型相同

2.2 加减运算指令

add--加法运算

add eax,8; 相当于C语言的-->int 8;a=8+0;

sub--减法运算

mov eax,0x00;
add eax,8;
sub eax,5

结果为3

2.3 逻辑运算

逻辑于:and

mov eax,1;
and eax,2;
;01&&10==00

逻辑或:or

mov eax,1;
or eax,2;
;01||10==11

逻辑异或:xor

mov eax,1; 01
xor eax,2; 10
;结果为:11

逻辑非:not

mov eax,3; 11
not eax; 
;结果为:    FF-----32----FC

2.4 移位指令

2.4.1 算数逻辑指令

算术左移指令:SAL

功能:左移一次,最低位补0,最高位送入CF标志位

mov eax,2;
sal eax,1;左移1次

算术右移指令:SAR

功能:左移一次,最高位不变,最低位送入CF标志位

mov eax,2;
sar eax,1;右移1次

2.4.2 逻辑移位指令

逻辑左移指令:SHL

逻辑右移指令:SHR

汇编语言中 sal(算术左移指令)和shl(逻辑左移指令)指令的区别?

汇编语言中 sal(算术左移指令)和shl(逻辑左移指令)指令的寻址方式、控制移位方式等都一样,区别其实只有一处:
SAL算术移位指令在执行时,实际上把操作数看成有符号数进行移位,最高位符号位移入CF,但本身保持原值;其余位顺序左移,次高位被舍弃。
SHL逻辑移位指令在执行时,实际上把操作数看成无符号数进行移位,所有位顺序左移,最高位移入CF。
举例如下:

;算术左移
MOV AX,8001H;(AX)=1000 0000 0000 0001B
SAL AX,1 ;(AX)=1000 0000 0000 0010B
;逻辑左移
MOV AX,8001H;(AX)=1000 0000 0000 0001B
SHL AX,1 ;(AX)=0000 0000 0000 0010B



文章评论

目录