变量的声明

  • 声明变量就是告诉计算机,我要用一块内存,你给我留着,宽度和存储格式有数据类型决定。
  • 计算机什么时候把这块内存给你,取决于变量的作用范围,如果是全局变量,在程序编译完就已经分配了空间,如果是局部变量,只有所在的程序被调用的时候,才会分配空间。
  • 全局变量如果不赋初始值,默认是0,但局部变量在使用前一定要赋初值

类型转换

  1. MOVSX先符号扩展,再传送(有符号数用)

    1
    2
    3
    4
    MOV AL, 0xFF               1111 1111
    MOVSX CX, AL 1111 1111 1111 1111
    MOV AL, 80 1000 0000
    MOVSX CX, AL 1111 1111 1000 0000
  2. MOVZX先零扩展,再传送(无符号数用)

    1
    2
    3
    4
    MOV AL, 0xFF               1111 1111
    MOVZX CX, AL 0000 0000 1111 1111
    MOV AL, 80 1000 0000
    MOVZX CX, AL 0000 0000 1000 0000

当表达式中存在不同宽度的变量时,结果将转换为宽度最大的那个。
当表达式中同时存在有符号和无符号数的时候,表达式的结构将转换为无符号数。

课后作业

  1. 基于缓冲区溢出的 HelloWorld

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #include "stdafx.h"

    void HelloWorld() {
    printf("Hello World");
    getchar();
    }
    void Func() {
    int arr[5] = {1, 2, 3, 4, 5};
    arr[6] = (int)HelloWorld;
    }
    int main(int argc, char* argv[]) {
    Func();
    return 0;
    }

    数组首先开辟了存储 5 个变量的空间,arr[0] 在 [ebp-14h] 的位置,那么 arr[6] 就会存在 [ebp-14h]+6*4 的位置也就是 [ebp+4](如图箭头所指),而原本这里是存储函数返回地址的,现在被覆盖成了 HelloWorld 函数的首地址,所以在 Func 执行结束返回时,CPU 就跳去执行 HelloWorld 了。

  2. 永不停止的 HelloWorld

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #include "stdafx.h"

    void Func() {
    int i;
    int arr[5] = {0};
    for (i = 0; i <= 5; i++) {
    arr[i] = 0;
    printf("Hello World!\n");
    }
    }
    int main(int argc, char* argv[]) {
    Func();
    return 0;
    }

从汇编中可以看出来,arr 数组存在 [ebp-18]~[ebp-8][ebp-4] 这里存的是 i,问题就在于 for 循环对 arr 数组进行了六次赋值,而第六次赋值时 arr[5] 的地址是 [ebp-4] 也就是 i 的位置,又把 i 变成了 0,导致一直在 for 循环里出不来