Trao đổi với tôi

http://www.buidao.com

6/21/09

[Iczelion's Tuts] TUTORIAL 1: THE BASICS

TUTORIAL 1: THE BASICS

Đây là tut hướng dẫn cho người đọc biết cách dùng MASM như thế nào. Nếu bạn ko có MASM thì bạn hảy download win32asm.exe (http://spiff.tripnet.se/~iczelion/files/win32asm.exe) và học các bài hướng dẫn trong package của nó trước khi đọc tut này. Good. Bây giờ bạn đã sẳn sàng. Chúng ta cùng đi nhé.

LÝ THUYẾT:

Các chương trình Win32 chạy trong chế độ bảo vệ mà nó có thể dùng trong 80286. Nhưng 80286 ngày nay chỉ còn là lịch sử.Vì vậy chúng ta chỉ còn liên quan đến 80386 và các con cháu của nó mà thôi.Windows chạy mỗi chương trình win32 trong một vùng bộ nhớ ảo được phân sẳn. Điều này có nghĩa là mỗi một chương trình win32 sẽ có cho riêng mình một vùng nhớ địa chỉ đến 4GB.Tuy nhiên điều này ko có nghĩa là mỗi một chương trình win32 có 4 GB vùng nhớ vật lý, chỉ có nghĩa là chương trình có thể định địa chỉ trên bộ nhớ trong range 4GB này thôi. Windows sẽ làm điều gì đó để chương trình có thể tham khảo đến các giá trị trong vùng nhớ nói trên. Tất nhiên chương trình phải bám vào rules (các qui tắc)Windows đã qui định., nếu khác nó sẽ gây ra lỗi protection. Mỗi chương trình chỉ “ở một mình” trong vùng địa chỉ của nó. Điều này tương phản với win16. Tất cả các chương trình trong win16 có thể “nhìn thấy nhau”. Nhưng nó ko giống vậy ở win32. Đây là điểm đặc trưng giúp cho giảm bớt việc thay đổi một chương trình viết đè lên code hay data của một chương trình khác.

Memory model cũng khác xa với thế giới win16. Dưới win32 chúng ta ko cần quan tâm đến memory model hay các segment (“đọan vùng nhớ” trong Win16) . Chỉ có một memory model: đó là kiểu bộ nhớ phẳng (Flat memory model). Không có lọai 64k cho mỗi segment như win16. Memory ở win32 là một vùng liên tục 4GB. Điều đó cũng có nghĩa là bạn ko phải chơi với những thanh ghi segment. Bạn có thể dùng bất kỳ thanh ghi segment nào để định một địa chỉ bất kỳ trên vùng nhớ. Điều này giúp cho các lập trình viên rất nhiều. Đây cũng là những gì giúp lập trình trên win32 ASM dễ dàng như lập trình trong C.

Khi bạn viết trình trong Win32, bạn phải biết vài Rules (quy tắc) quan trọng. Một trong những rules đó như sau:

Windows dùng các thanh ghi ESI,EDI,EBP, và EBX nội tại bên trong nó khi nó xử lý nó sẽ ko cho phép giá trị của các thanh ghi đó thay đổi. Vì vậy hảy nhớ qui tắc (rules) đầu tiên như sau: Nếu bạn dùng một trong 4 thanh ghi đó trong các hàm khi callback trở lại , thì đừng quên phục hồi lại các thanh ghi đó trước khi trả lại điều kiển cho Windows xử lý. Một hàm khi callback chính là hàm của các bạn được Windows gọi. Hiển nhiên nó là một thủ tục của Windows. Điều này ko có nghĩa là bạn ko được dùng một trong 4 thanh ghi trên, bạn vẫn có thể sử dụng, nhưng chỉ chắc rằng bạn sẽ phục hồi lại giá trị cho nó trước khi bạn chuyển quyền điều khiển chương trình cho Windows (ở đây khái niệm về Windows tức là hệ điều hành Windows).

NỘI DUNG:

Đây là “nhân” của một chương trình MASM. Nếu bạn ko hiểu những gì sau đây bạn đừng hỏang sợ. Tôi sẽ giải thích cặn kẽ sau đó:

.386
.MODEL Flat, STDCALL
.DATA

......
.DATA?

......
.CONST

......
.CODE

Chúng ta hảy phân tích nhân chương trình này:

.386

Đây là một chỉ thị asm,nói cho asm biết dùng cấu trúc 80386 để sử dụng biên dịch. Bạn có thể dùng .486 hay .586 nhưng an tòan nhất hảy bám vào cấu trúc .386. Trong thực tế có hai cấu trúc gần giống nhau về hình thức cho mỗi CPU model. .386/.386p, .486/.486p. Chử “p”(chử đầu của privileged : có nghĩa là đặc quyền) chỉ cần thiết khi chương trình của bạn cần sử dụng một số chỉ thị đặc quyền. Những chỉ thị đó là những chỉ thị được reversed (đảo nghịch mã chương trình) bởi CPU/ họat động của hệ thống khi ở chế độ protected (chế độ được bảo vệ).. Chúng chỉ có thể được dùng bởi code đặc quyền. Ví dụ như các thiết bị drivers. Phần lớn các chương trình của bạn làm việc trong chế độ non-p vì vậy để an tòan hảy dùng phiên bản non-p.

.MODEL FLAT, STDCALL

.MODEL là một chỉ thị asm chỉ rõ memory model cho chương trình chúng ta. Dưới win32 chỉ có một model là FLAT model.

STDCALL nói cho asm biết qui ước truyền tham số cho các hàm. Qui ước truyền tham số chỉ ra lọai tham số được truyền, từ trái qua phải hay từ phải qua trái và cũng chính nó cân bằng cấu trúc stack khi hàm gọi về.

Dưới win16 có 2 qui ước là C và Pascal.

Qui ước trong C: truyền tham số từ phải sang trái, điều này có nghĩa tham số bên phải ngòai cùng sẽ được push trước tiên. Hàm gọi thủ tục (hay còn gọi là “kẻ gọi” caller) phải chịu trách nhiệm cân bằng cấu trúc stack sau khi gọi. Ví dụ, để gọi một hàm có tên là :

foo (int first_param,int second_param, int third_param)

theo qui ước trong C, thì code asm sẽ như sau:

push [third_param] ; Push the third parameter
push [second_param] ; Followed by the second
push [first_param] ; And the first
call foo
add sp, 12 ; The caller balances the stack frame

Qui ước trong Pascal: nghịch lại qui ước trong C. Nó truyền tham số từ trái sang phải. Và “kẻ bị gọi” (Callee) (hàm bị gọi) có nhiệm vụ cân bằng stack sau khi gọi.

Win16 chấp nhận qui ước trong Pascal bởi vì nó sinh ra những code nhỏ. Qui ước trong C thì thường dùng khi bạn ko biết bao nhiêu tham số được truyền cho hàm như trong trường hợp hàm wsprintf(). Trong case hàm wsprintf(), hàm sẽ ko có cách nào xác định được bao nhiêu tham số để sẳn sàng push vào trong stack, vì vậy nó ko thể nào làm chức năng cân bằng stack.

STDCALL là qui ước ” ngọai lai” của hai qui ước gọi hàm trong C và Pascal. Nó truyền tham số từ phải sang trái, nhưng “Kẻ bị gọi Callee” sẽ chịu trách nhiệm cân bằng stack sau khi gọi. Win32 platform dùng STDCALL như một độc quyền. Ngọai trừ 1 trường hợp: wsprintf(). Bạn phải dùng qui ước gọi hàm trong C với hàm wsprintf().

.DATA

.DATA?

.CONST

.CODE

Tất cả 4 chỉ thị trên được gọi là Section(đọan). Bạn ko có các segments (khái niệm đọan bộ nhớ trong Win16) trong win32, hảy nhớ kỷ điều đó.Nhưng bạn có thể chia tòan bộ vùng địa chỉ của bạn thành những logical section. Đầu của một section là đích của một section kế tiếp. Có 2 nhóm section: data và code. Data sections được chia ra làm 3 lọai:

.DATA là section chứa dữ liệu được gán giá trị ngay từ đầu chương trình của bạn

.DATA? Dây là section chứa các dữ liệu ko cho giá trị khởi điểm của chương trình của bạn.Đôi khi bạn muốn chỉ định vài vùng nhớ nhưng ko muốn cho nó chứa giá trị nào lúc khởi tạo.Section này dành cho mục đích đó. Lợi thế của chỉ thị này là : ko chiếm khỏang trống trong file thực thi. Ví dụ: Nếu bạn chỉ định 10000 bytes trong khai báo .DATA? section, file exe của bạn sẽ ko phồng lên 10000 bytes. Kích thước của nó sẽ ko nhiều như vậy. Ở đây bạn chỉ nói cho asm biết khỏang trống bao nhiêu bạn cần khi chương trình được tải vào trong memory.

.CONST Là section chứa hằng số được dùng trong chương trình của bạn. Những hằng số trong section này sẽ ko thay đổi trong chương trình của bạn.

Bạn ko phải sử dụng cả 3 section trên trong chương trình của bạn. Chỉ khai bo những section nào bạn muốn dùng.

Chỉ có 1 section cho code đó là : .CODE . Đây là nơi cư trú code chương trình của bạn.

end

Ở đây > là một nhãn bất kỳ được dùng để chỉ định khỏang rộng của code bạn. Hai nhãn trên , dưới phải giống nhau. Tất cả các code của bạn phải được cư trú trong end

---------The End tut---------------

Benina 26/10/04

Update 20/11/2005

(Không đồng ý bất kỳ ai sử dụng tài liệu này cho mục đích thương mại nếu ko được phép của người dịch)