一、 優點
使用內聯匯編可以在 C/C++ 代碼中嵌入匯編語言指令,而且不需要額外的匯編和連接步驟。在 Visual C++ 中,內聯匯編是內置的編譯器,因此不需要配置諸如 MASM 一類的獨立匯編工具。這里,我們就以 Visual Studio .NET 2003 為背景,介紹在 Visual C++ 中使用內聯匯的相關知識(如果是早期的版本,可能會有些許出入)。
內聯匯編代碼可以使用 C/C++ 變量和函數,因此它能非常容易地整合到 C/C++ 代碼中。它能做一些對于單獨使用 C/C++ 來說非常笨重或不可能完成的任務。
內聯匯編的用途包括:
* 使用匯編語言編寫特定的函數;
* 編寫對速度要求非常較高的代碼;
* 在設備驅動程序中直接訪問硬件;
* 編寫 naked 函數的初始化和結束代碼。
二、 關鍵字
使用內聯匯編要用到 __asm 關鍵字,它可以出現在任何允許 C/C++ 語句出現的地方。我們來看一些例子:
* 簡單的 __asm 塊:
__asm
{
MOV AL, 2
MOV DX, 0xD007
OUT AL, DX
}
* 在每條匯編指令之前加 __asm 關鍵字:
__asm MOV AL, 2
__asm MOV DX, 0xD007
__asm OUT AL, DX
* 因為 __asm 關鍵字是語句分隔符,所以可以把多條匯編指令放在同一行:
__asm MOV AL, 2 __asm MOV DX, 0XD007 __asm OUT AL, DX
顯然,第一種方法與 C/C++ 的風格很一致,并且把匯編代碼和 C/C++ 代碼清楚地分開,還避免了重復輸入 __asm 關鍵字,因此推薦使用第一種方法。
不像在 C/C++ 中的“{}”,__asm 塊的“{}”不會影響 C/C++ 變量的作用范圍。同時,__asm 塊可以嵌套,而且嵌套也不會影響變量的作用范圍。
為了與低版本的 Visual C++ 兼容,_asm 和 __asm 具有相同的意義。另外,Visual C++ 支持標準 C++ 的 asm 關鍵字,但是它不會生成任何指令,它的作用僅限于使編譯器不會出現編譯錯誤。要使用內聯匯編,必須使用 __asm 而不是 asm 關鍵字。
三、 匯編語言
1. 指令集
內聯匯編支持 Intel Pentium 4 和 AMD Athlon 的所有指令。更多其它處理器的指令可以通過 _EMIT 偽指令來創建(_EMIT 偽指令說明見下文)。
2. MASM 表達式
在內聯匯編代碼中,可以使用所有的 MASM 表達式(MASM 表達式是指用來計算一個數值或一個地址的操作符和操作數的組合)。
3. 數據指示符和操作符
雖然 __asm 塊中允許使用 C/C++ 的數據類型和對象,但它不能使用 MASM 指示符和操作符來定義數據對象。這里特別指出,__asm 塊中不允許 MASM 中的定義指示符(DB、DW、DD、DQ、DT 和 DF),也不允許使用 DUP 和 THIS 操作符。MASM 中的結構和記錄也不再有效,內聯匯編不接受 STRUC、RECORD、WIDTH 或者 MASK。
4. EVEN 和 ALIGN 指示符
盡管內聯匯編不支持大多數 MASM 指示符,但它支持 EVEN 和 ALIGN。當需要的時候,這些指示符在匯編代碼里面加入 NOP 指令(空操作)使標號對齊到特定邊界。這樣可以使某些處理器取指令時具有更高的效率。
5. MASM 宏指示符
內聯匯編不是宏匯編,不能使用 MASM 宏指示符(MACRO、REPT、IRC、IRP 和 ENDM)和宏操作符(<>、!、&、% 和 .TYPE)。
6. 段
必須使用寄存器而不是名稱來指明段(段名稱“_TEXT”是無效的)。并且,段跨越必須顯式地說明,如 ES:[EBX]。
7. 類型和變量大小
在內聯匯編中,可以用 LENGTH、SIZE 和 TYPE 來獲取 C/C++ 變量和類型的大? ?
* LENGTH 操作符用來取得 C/C++ 中數組的元素個數(如果不是一個數組,則結果為 1)。
* SIZE 操作符可以獲取 C/C++ 變量的大小(一個變量的大小是 LENGTH 和 TYPE 的乘積)。
* TYPE 操作符可以返回 C/C++ 類型和變量的大小(如果變量是一個數組,它得到的是數組中單個元素的大小)。
例如,程序中定義了一個 8 維的整數型變量:
int iArray[8];
下面是 C 和匯編表達式中得到的 iArray 及其元素的相關值:
__asm C Size
LENGTH iArray sizeof(iArray)/sizeof(iArray[0]) 8
SIZE iArray sizeof(iArray) 32
TYPE iArray sizeof(iArray[0]) 4
8. 注釋
內聯匯編中可以使用匯編語言的注釋,即“;”。例如:
__asm MOV EAX, OFFSET pbBuff ; Load address of pbBuff
因為 C/C++ 宏將會展開到一個邏輯行中,為了避免在宏中使用匯編語言注釋帶來的混亂,內聯匯編也允許使用 C/C++ 風格的注釋。
9. _EMIT 偽指令
_EMIT 偽指令相當于 MASM 中的 DB,但是 _EMIT 一次只能在當前代碼段(.text 段)中定義一個字節。例如:
__asm
{
JMP _CodeLabel
_EMIT 0x00 ; 定義混合在代碼段的數據
_EMIT 0x01
_CodeLabel: ; 這里是代碼
_EMIT 0x90 ; NOP指令
}
10. 寄存器使用
一般來說,不能假定某個寄存器在 __asm 塊開始的時候有已知的值。寄存器的值將不能保證會從 __asm 塊保留到另外一個 __asm 塊中。
如果一個函數聲明為 __fastcall 調用方式,則其參數將通過寄存器而不是堆棧來傳遞。這將會使 __asm 塊產生問題,因為函數無法被告知哪個參數在哪個寄存器中。如果函數接收了 EAX 中的參數并立即儲存一個值到 EAX 中的話,原來的參數將丟失掉。另外,在所有聲明為 __fastcall 的函數中,ECX 寄存器是必須一直保留的。為了避免以上的沖突,包含 __asm 塊的函數不要聲明為 __fastcall 調用方式。
* 提示:如果使用 EAX、EBX、ECX、EDX、ESI 和 EDI 寄存器,你不需要保存它。但如果你用到了 DS、SS、SP、BP 和標志寄存器,那就應該用 PUSH 保存這些寄存器。
* 提示:如果程序中改變了用于 STD 和 CLD 的方向標志,必須將其恢復到原來的值。
四、 使用 C/C++ 元素
1. 可用的 C/C++ 元素
C/C++ 與匯編語言可以混合使用,在內聯匯編中可以使用 C/C++ 變量以及很多其它的 C/C++ 元素,包括:
* 符號,包括標號、變量和函數名;
* 常量,包括符號常量和枚舉型成員;
* 宏定義和預處理指示符;
* 注釋,包括“/**/”和“//”;
* 類型名,包括所有 MASM 中合法的類型;
* typedef 名稱,通常使用 PTR 和 TYPE 操作符,或者使用指定的的結構或枚舉成員。
在內聯匯編中,可以使用 C/C++ 或匯編語言的基數計數法。例如,0x100 和 100H 是相等的。
2. 操作符使用
內聯匯編中不能使用諸如“<<”一類的 C/C++ 操作符。但是,C/C++ 和 MASM 共有的操作符(比如“*”和“[]”操作符),都被認為是匯編語言的操作符,是可以使用的。舉個例子:
int iArray[10];
__asm MOV iArray[6], BX ; Store BX at iArray + 6 (Not scaled)
iArray[6] = 0; // Store 0 at iArray+12 (Scaled)
* 提示:在內聯匯編中,可以使用 TYPE 操作符使其與 C/C++ 一致。比如,下面兩條語句是一樣的:
__asm MOV iArray[6 * TYPE int], 0 ; Store 0 at iArray + 12
iArray[6] = 0; // Store 0 at iArray + 12
3. C/C++ 符號使用
在 __asm 塊中可以引用所有在作用范圍內的 C/C++ 符號,包括變量名稱、函數名稱和標號。但是不能訪問 C++ 類的成員函數。
下面是在內聯匯編中使用 C/C++ 符號的一些限制:
* 每條匯編語句只能包含一個 C/C++ 符號。在一條匯編指令中,多個符號只能出現在 LENGTH、TYPE 或 SIZE 表達式中。
* 在 __asm 塊中引用函數必須先聲明。否則,編譯器將不能區別 __asm 塊中的函數名和標號。
* 在 __asm 塊中不能使用對于 MASM 來說是保留字的 C/C++ 符號(不區分大小寫)。MASM 保留字包含指令名稱(如 PUSH)和寄存器名稱(如 ESI)等。
* 在 __asm 塊中不能識別結構和聯合標簽。
4. 訪問 C/C++ 中的數據
內聯匯編的一個非常大的方便之處是它可以使用名稱來引用 C/C++ 變量。例如,如果 C/C++ 變量 iVar 在作用范圍內:
__asm MOV EAX, iVar ; Stores the value of iVar in EAX
如果 C/C++ 中的類、結構或者枚舉成員具有唯一的名稱,則在 __asm 塊中可以只通過成員名稱來訪問(省略“.”操作符之前的變量名或 typedef 名稱)。然而,如果成員不是唯一的,你必須在“.”操作符之前加上變量名或 typedef 名稱。例如,下面的兩個結構都具有 SameName 這個成員變量:
struct FIRST_TYPE
{
char *pszWeasel;
int SameName;
};
struct SECOND_TYPE
{
int iWonton;
long SameName;
};
如果按下面方式聲明變量:
struct FIRST_TYPE ftTest;
struct SECOND_TYPE stTemp;
那么,所有引用 SameName 成員的地方都必須使用變量名,因為 SameName 不是唯一的。另外,由于上面的 pszWeasel 變量具有唯一的名稱,你可以僅僅使用它的成員名稱來引用它:
__asm
{
MOV EBX, OFFSET ftTest
MOV ECX, [EBX]ftTest.SameName ; 必須使用“ftTest”
MOV ESI, [EBX]. pszWeasel ; 可以省略“ftTest”
}
* 提示:省略變量名僅僅是為了書寫代碼方便,生成的匯編指令還是一樣的。
5. 用內聯匯編寫函數
如果用內聯匯編寫函數的話,要傳遞參數和返回一個值都是非常容易的。看下面的例子,比較一下用獨立匯編和內聯匯編寫的函數:
; PowerAsm.asm
; Compute the power of an integer
PUBLIC GetPowerAsm
_TEXT SEGMENT WORD PUBLIC 'CODE'
GetPowerAsm PROC
PUSH EBP ; Save EBP
MOV EBP, ESP ; Move ESP into EBP so we can refer
; to arguments on the stack
MOV EAX, [EBP+4] ; Get first argument
MOV ECX, [EBP+6] ; Get second argument
SHL EAX, CL ; EAX = EAX * (2 ^ CL)
POP EBP ; Restore EBP
RET ; Return with sum in EAX
GetPowerAsm ENDP
_TEXT ENDS
END
C/C++ 函數一般用堆棧來傳遞參數,所以上面的函數中需要通過堆棧位置來訪問它的參數(在 MASM 或其它一些匯編工具中,也允許通過名稱來訪問堆棧參數和局部堆棧變量)。
下面的程序是使用內聯匯編寫的:
// PowerC.c
#i nclude <Stdio.h>
int GetPowerC(int iNum, int iPower);
int main()
{
printf("3 times 2 to the power of 5 is %d\n", GetPowerC( 3, 5));
}
int GetPowerC(int iNum, int iPower)
{
__asm
{
MOV EAX, iNum ; Get first argument
MOV ECX, iPower ; Get second argument
SHL EAX, CL ; EAX = EAX * (2 to the power of CL)
}
// Return with result in EAX
}
使用內聯匯編寫的 GetPowerC 函數可以通過參數名稱來引用它的參數。由于 GetPowerC 函數沒有執行 C 的 return 語句,所以編譯器會給出一個警告信息,我們可以通過 #pragma warning 禁止生成這個警告。
內聯匯編的其中一個用途是編寫 naked 函數的初始化和結束代碼。對于一般的函數,編譯器會自動幫我們生成函數的初始化(構建參數指針和分配局部變量等)和結束代碼(平衡堆棧和返回一個值等)。 使用內聯匯編,我們可以自己編寫干干凈凈的函數。當然,此時我們必須自己動手做一些有關函數初始化和掃尾的工作。例如:
void __declspec(naked) MyNakedFunction()
{
// Naked functions must provide their own prolog.
__asm
{
PUSH EBP
MOV ESP, EBP
SUB ESP, __LOCAL_SIZE
}
.
.
.
// And we must provide epilog.
__asm
{
POP EBP
RET
}
}
6. 調用 C/C++ 函數
內聯匯編中調用聲明為 __cdecl 方式(默認)的 C/C++ 函數必須由調用者清除參數堆棧,下面是一個調用 C/C++ 函數例子:
#i nclude <Stdio.h>
char szFormat[] = "%s %s\n";
char szHello[] = "Hello";
char szWorld[] = " world";
void main()
{
__asm
{
MOV EAX, OFFSET szWorld
PUSH EAX
MOV EAX, OFFSET szHello
PUSH EAX
MOV EAX, OFFSET szFormat
PUSH EAX
CALL printf
// 壓入了 3 個參數在堆棧中,調用函數之后要調整堆棧
ADD ESP, 12
}
}
* 提示:參數是按從右往左的順序壓入堆棧的。
如果調用 __stdcall 方式的函數,則不需要自己清除堆棧。因為這種函數的返回指令是 RET n,會自動清除堆棧。大多數 Windows API 函數均為 __stdcall 調用方式(僅除 wsprintf 等幾個之外),下面是一個調用 MessageBox 函數的例子:
#i nclude <Windows.h>
TCHAR g_tszAppName[] = TEXT("API Test");
void main()
{
TCHAR tszHello[] = TEXT("Hello, world!");
__asm
{
PUSH MB_OK OR MB_ICONINFORMATION
PUSH OFFSET g_tszAppName ; 全局變量用 OFFSET
LEA EAX, tszHello ; 局部變量用 LEA
PUSH EAX
PUSH 0
CALL DWORD PTR [MessageBox] &
//****************************************************************************
轉自:
http://hi.baidu.com/xocoder/blog/item/55dd5a12975d6a28dd5401e7.html
43"To be an effective leader, a public official must maintain the highest ethical and moral standards."
is a public official must maintain the highest ethical and moral standards to be an effective leader ,as the author asserts? I think we should take it to the case-to-case analysis.
Admittedly, in some cases, such like monarchy countries and religious nations, high ethical and moral standards are remarkable for leaders. Becaue those leaders are not only the politicians but also the spiritual leader. Their power don’t come from the Democratic elections ,but the religious belief. If their image of ethics collapse, it will threaten the leadership directly. Like dalai lama…Scandals on dalai lama
tends to render social chaos and breakdown of people's belief, which will even lead to a war at last. Therefore, high ethical and moral standards for spiritual or religious leaders are not only crucial, but also necessary.吹。。。。
But in the democracy society, which operates by its scientific belief ,the leader’s personality or Moral Charm is not that significant as the ancient time. The really thing that count is the leader’s governing philosophy, the Economic Policy which can bring his people to a better life. He moral or ethics charm is just a private thing which are not very crucial.
So , the leaders in the democracy system, is just a screw in a large machine , which could be replaced by any suitable person and it has not much thing to do with the leader’s moral image in he public. Like Bill Clinton ,who are always mentioned by his sex scandal, is of course a good leader in the US history .
On the other hand, even in democratic societies, moral charisma is useful and helpful for political leaders. A candidate with high moral reputation is more likely to win a campaign, which is the beginning to become an effective leader. When it comes to a decision maker, if he or she is famous for good morality, the policies are usually easier to be accepted by public. Let's take the Chinese Premier Wen (Premier Wen in China) as an example, who played an important role in the rescue in Sichuan Earthquake which killed (claimed) more than seventy thousand lives in 2008(災難常用句型:e.g The hurricane claimed more than 5,000 lives。颶風奪去了5000人的生命). His mercy and devoted figure moved millions of people all over the world. As a result, his leadership in rescuing activity rescue is convincing and his orders are implemented efficiency…Efficiently
which saved thousands of people buried underground in time. In this case, there is no doubt that the leader's personal moral charm improves the effect of Premier Wen's leadership.
In the final analysis , the ethic and morality of public leader could be very significant in some cases , especially to that spiritual leaders and religious leaders and it also benefits the leaders from democratic society as well. However, we have to notice that the real standard to evaluate a leader should base on his or her political achievement.