# Chapter 9 指針
指針通常被用作函數返回值(recall scanf() case (6)).例如,當函數返回兩個值時。
## 9.1 Global variables example
```
#!bash
#include <stdio.h>
void f1 (int x, int y, int *sum, int *product)
{
*sum=x+y;
*product=x*y;
};
int sum, product;
void main()
{
f1(123, 456, &sum, &product);
printf ("sum=%d, product=%d
", sum, product);
};
```
編譯后
Listing 9.1: Optimizing MSVC 2010 (/Ox /Ob0)
```
#!bash
COMM _product:DWORD
COMM _sum:DWORD
$SG2803 DB ’sum=%d, product=%d’, 0aH, 00H
_x$ = 8 ; size = 4
_y$ = 12 ; size = 4
_sum$ = 16 ; size = 4
_product$ = 20 ; size = 4
_f1 PROC
mov ecx, DWORD PTR _y$[esp-4]
mov eax, DWORD PTR _x$[esp-4]
lea edx, DWORD PTR [eax+ecx]
imul eax, ecx
mov ecx, DWORD PTR _product$[esp-4]
push esi
mov esi, DWORD PTR _sum$[esp]
mov DWORD PTR [esi], edx
mov DWORD PTR [ecx], eax
pop esi
ret 0
_f1 ENDP
_main PROC
push OFFSET _product
push OFFSET _sum
push 456 ; 000001c8H
push 123 ; 0000007bH
call _f1
mov eax, DWORD PTR _product
mov ecx, DWORD PTR _sum
push eax
push ecx
push OFFSET $SG2803
call DWORD PTR __imp__printf
add esp, 28 ; 0000001cH
xor eax, eax
ret 0
_main ENDP
```
讓我們在OD中查看:圖9.1。首先全局變量地址被傳遞進f1()。我們在堆棧元素點擊“數據窗口跟隨”,可以看到數據段上分配兩個變量的空間。這些變量被置0,因為未初始化數據(BSS1)在程序運行之前被清理為0。這些變量屬于數據段,我們按Alt+M可以查看內存映射fig. 9.5.
讓我們跟蹤(F7)到f1()fig. 9.2.在堆棧中為456 (0x1C8) 和 123 (0x7B),接著是兩個全局變量的地址。
讓我們跟蹤到f1()結尾,可以看到兩個全局變量存放了計算結果。
現在兩個全局變量的值被加載到寄存器傳遞給printf(): fig. 9.4.

Figure 9.1: OllyDbg: 全局變量地址被傳遞進f1()

Figure 9.2: OllyDbg: f1()開始

Figure 9.3: OllyDbg: f1()完成

Figure 9.4: OllyDbg: 全局變量被傳遞進printf()

Figure 9.5: OllyDbg: memory map
## 9.2 Local variables example
讓我們修改一下例子:
Listing 9.2: 局部變量
```
#!bash
void main()
{
int sum, product; // now variables are here
f1(123, 456, &sum, &product);
printf ("sum=%d, product=%d
", sum, product);
};
```
f1()函數代碼沒有改變。僅僅main()代碼作了修改。
Listing 9.3: Optimizing MSVC 2010 (/Ox /Ob0)
```
#!bash
_product$ = -8 ; size = 4
_sum$ = -4 ; size = 4
_main PROC
; Line 10
sub esp, 8
; Line 13
lea eax, DWORD PTR _product$[esp+8]
push eax
lea ecx, DWORD PTR _sum$[esp+12]
push ecx
push 456 ; 000001c8H
push 123 ; 0000007bH
call _f1
; Line 14
mov edx, DWORD PTR _product$[esp+24]
mov eax, DWORD PTR _sum$[esp+24]
push edx
push eax
push OFFSET $SG2803
call DWORD PTR __imp__printf
; Line 15
xor eax, eax
add esp, 36 ; 00000024H
ret 0
```
我們在OD中查看,局部變量地址在堆棧中是0x35FCF4和0x35FCF8。我們可以看到是如何圧棧的fig. 9.6.
f1()開始的時候,隨機棧地址為0x35FCF4和0x35FCF8 fig. 9.7.
f1()完成時結果0xDB18和0x243存放在地址0x35FCF4和0x35FCF8。

Figure 9.6: OllyDbg: 局部變量地址被圧棧

Figure 9.7: OllyDbg: f1()starting

Figure 9.8: OllyDbg: f1()finished
## 9.3 小結
f1()可以返回結果到內存的任何地方,這是指針的本質和特性。順便提一下,C++引用的工作方式和這個類似。詳情閱讀相關內容(33)。
- 第一章 CPU簡介
- 第二章 Hello,world!
- 第三章? 函數開始和結束
- 第四章 棧
- Chapter 5 printf() 與參數處理
- Chapter 6 scanf()
- CHAPER7 訪問傳遞參數
- Chapter 8 一個或者多個字的返回值
- Chapter 9 指針
- Chapter 10 條件跳轉
- 第11章 選擇結構switch()/case/default
- 第12章 循環結構
- 第13章 strlen()
- Chapter 14 Division by 9
- chapter 15 用FPU工作
- Chapter 16 數組
- Chapter 17 位域
- 第18章 結構體
- 19章 聯合體
- 第二十章 函數指針
- 第21章 在32位環境中的64位值
- 第二十二章 SIMD
- 23章 64位化
- 24章 使用x64下的SIMD來處理浮點數
- 25章 溫度轉換
- 26章 C99的限制
- 27章 內聯函數
- 第28章 得到不正確反匯編結果
- 第29章 花指令
- 第30章 16位Windows
- 第31章 類
- 三十二 ostream