1, 操作數提示符:
三種:
立即數:常數值, 在ATT格式的彙編代碼中, 書寫格式是 $ + 整數, 如:$-123 $0X12
寄存器:如:32位的%eax 16位的%ax 8位的%al
存儲器引用:
Imm(Eb) 表示地址爲:Eb+Imm
Imm(Eb, Ei) 地址爲:Eb(基址)+ Ei(變址) + Imm(立即數偏移),
Imm(Eb, Ei, s) 地址爲: Eb + Ei * s + Imm
2, 字節傳送指令:
mov 同等傳送, 即倆者的大小一致 (如:movb byte, movew word, movel longword(DW))
movs/ movz 不同等傳送, 即倆者的大小可以不一致, 如:movsbl 表示將源byte傳送到目的longword, 用1 或0補充剩餘位(取決於源byte的最高位是否爲1), movzbl 與movsbl相似, 用0補充剩餘位
push & pop
3, 特殊指令:
lea: 直接上例:
lea 4(%eax) %ebx //表示 %ebx 裏面的值爲%eax + 4 。
而 mov 4(%eax) %ebx //表示 %ebx裏面的值爲【eax+4】這個地址的值
其實, 複雜的來說, lea 表示獲取源地址的偏移地址, 對於上例來說, 偏移地址當然是%eax + 4 咯。
int fun (unsigned x)
{
int val = 0;
while (x) {
val ^= x;
x >>= 1;
}
return val & 0X1;
}
這個函數是測試x二進制裏面1的個數的奇偶, 奇返回1, 偶返回0;
理解, 第一着重於移位操作, 每次移位 都使前一位移動至後一位(即使得n位與n-1位之間的運算成爲可能), 第二 着重於異或操作,對於1bit ^ 1bit來說, 恰好是查看這倆者的1的總個數是否爲偶, 第三着重於第一位, 每次移位操作 都使得前一位都能跟當前第一位進行異或操作, 而這一位的結果是這一位上的1的個數是否爲偶。loop, 測試前前一位。。。。。 again and again until it ends.
int fun (unsigned x) {
int val = 0;
int i;
for (i = 0; i< 32; i++) {
val = (val <<1) | (x & 0x1);
x >>= 1;
}
return val;
}
這是獲取x的位反轉製造出來的鏡像4, switch指令較條件跳轉的優越性
條件跳轉, 在asm中, 是以類似cmp + jne 等指令實現的。 對於N種情況來說, 就意味着要N對cmp-jne這些指令。
switch對於條件轉換來說, 是利用了跳轉表來進行的(其實就是地址偏移),例如情況爲100-106, 即只需要計算當前值-100 的大小(k), 跳轉到jt【k】所指的位置即可。
其實這個也說明了某種問題, 也就是對於疏散的情況集合, 對於跳轉表的使用會不會添加空白無用的區域浪費呢?
to be continued.......
5, Union的作用:
類似struct可以存放數據, 不同在於, Union所有數據共用內存, 即Union的大小爲數據中大小最大的, 而不是大小之和。
用處: 類型轉換。。。注意小端法讀取數據
6, 爲什麼要數據對齊:
條件:1,平臺獲取數據都是以固定字節數獲取的。 2,有些數據不規則,如:struct{int a, char c;}A; 其標準大小是5Bytes
導致的情況: 比如固定字節數爲8, 不對齊數據就意味着第一次讀取, 獲得 A1 以及A2的部分數據, 爲了讀取A2的值, 必須讀取兩次,以及需要進行高低位的修補。。。。
所以數據對齊, 是一種以空間換時間的策略。
這也是爲什麼 sizeof(A)!= 5 而是8(test in VS2013)。
測試:
struct A{
int a;
char c;
int b;
};
void testSizeOf()
{
printf("size of A is %d\n", sizeof(A));
A k = { 1, 'c', 2 };
printf("A:\na: %d\nc: %c\nb: %d\n\n", k.a, k.c, k.b);
printf("A:\na: %x\nc: %x\nb: %x\n\n", k, k, k); //其中%x表示十六進制整數。 科普:\x 表示其後面兩位爲十六進制數,常用於printf cout等。
}
結果爲:
size of A is 12
A:
a: 1
c: c
b: 2
A:
a: 1
c: cccccc63 // 63是 'c'的十六進制ASCII字符表示形式
b: 2
表明:
1, 對於結構體k來說, 執行printf多次輸出,其過程類似於文件流讀取(讀即前進)。
2, 結構體A中, c佔用的字節爲4, 其中多餘3字節作爲補充。
注:char *c 對象大小爲4, 因爲裏面裝的是地址。。。。。 void *v 大小亦是4,同理。
這也表明了數據位置排列的重要性。一般來說 應按照從大到小排列。 因爲這樣可以縮小對齊要求的字節數,如4->>2。(???若是從小到大, 會怎樣? 會呵呵。。。)
7, 理解指針:
1) 指針指向函數:
int func(int a, int *b){...}
typedef int (*fp) (int a, int *b);
fp = func;
int result = fp(a, &b);
其實函數調用call也是移動到某一指令, 跟指針有差別嗎?
2)指針跟數組無異:
int a[n], *(a+1) = a [1];
3) 改變類型後 尋址的區別:
char *cp;
(int*)cp + 7 => (cp, 4, 7)的位置
(int*)(cp+7) => (cp, 1, 7)的位置
8, 存儲器的越界引用以及緩衝區溢出:
防範:
注: sizeof(“1234”)is 5; because of ‘\0’(0x00); 但是strlen返回的是4, 故在malloc的調用時, 應該malloc ( strlen(buf)+1 ). 記得要對返回值進行NULL判斷。
9. AGE OF 64:
特殊數字: 0x101010101010101 72340172838076673