ºìÁªLinuxÃÅ»§
Linux°ïÖú

Linux µÄ x86 »ã±à³ÌÐòÉè¼Æ

·¢²¼Ê±¼ä:2005-06-13 00:04:24À´Ô´:ºìÁª×÷Õß:007
±¾ÖÊÉÏÀ´Ëµ, ÕâƪÎÄÕÂÊÇ°ÑÎÒ×î¸ÐÐËȤµÄÁ½Ñù±à³Ì¶«Î÷: Linux ²Ù×÷ϵͳºÍ»ã±àÓïÑÔ³ÌÐòÉè¼Æ½áºÏÔÚÒ»Æð. ÕâÁ½¸ö¶¼²»(»òÕß˵Ӧ¸Ã²»)ÐèÒª½éÉÜ; Ïñ Win32 µÄ»ã±à,Linux µÄ»ã±àÔËÐÐÔÚ 32 λµÄ±£»¤Ä£Ê½ÏÂ...µ«ËüÓÖÓÐÒ»¸ö½ØÈ»²»Í¬µÄÓÅÊƾÍÊÇËüÔÊÐíÄãµ÷Óà C µÄ±ê×¼¿âº¯ÊýºÍ Linux µÄ¹²Ïí¿âº¯Êý. ÎÒ¿ªÊ¼¸ø Linux ϵĻã±àÓïÑÔ±à³ÌÀ´¸ö¼òÒª½éÉÜ; ΪÁ˸üºÃ¶ÁÒ»µã, Äã¿ÉÄÜÒªÌø¹ýÕâ¸ö»ù±¾µÄС½Ú.

±àÒëºÍÁ´½Ó
---------------------
Linux ÏÂÁ½¸ö×îÖ÷ÒªµÄ»ã±àÆ÷ÊÇ Nasm(free, Netwide Assembler)ºÍ GAS(free, Gnu Assembler),
ºóÒ»¸öºÍ GCC ½áºÏÔÚÒ»Æð. ÔÚÕâƪÎÄÕÂÀïÎÒ½«¼¯ÖÐÔÚ Nasm ÉÏ, °Ñ GAS ·ÅÔÚºóÃæ,ÒòΪËüʹÓà AT&T µÄÓï·¨, ÐèÒªÒ»¸ö³¤µÄ½éÉÜ.
Nasm µ÷ÓÃʱӦ¸Ã´øÉÏ ELF ¸ñʽѡÏî("nasm -f elf hello.asm"); ²úÉúµÄÄ¿±êÎļþÓÃGCC À´Á´½Ó("gcc hello.o"), ²úÉú×îÖÕµÄ ELF ¶þ½øÖÆ´úÂë. ÏÂÃæµÄÕâ¸ö½Å±¾¿ÉÓÃÀ´±àÒë ASM µÄÄ£¿é; ÎÒ¾¡Á¿°ÑËüдµÃ¼òµ¥, ËùÒÔËùÓÐËü×öµÄ¾ÍÊǽÓÊÜ´«¸øËüµÄµÚÒ»¸öÎļþÃû, Óà Nasm ±àÒë, Óà GCC À´Á´½Ó.
#!/bin/sh
# assemble.sh =========================================================
outfile=${1%%.*}
tempfile=asmtemp.o
nasm -o $tempfile -f elf $1
gcc $tempfile -o $outfile
rm $tempfile -f
#EOF =================================================================

»ù±¾ÖªÊ¶:
----------
µ±È»×îºÃµÄ¾ÍÊÇÔÚÁ˽âϵͳϸ½Ú֮ǰ´ÓÒ»¸öÀý×Ó¿ªÊ¼. ÕâÀïÊÇÒ»¸ö×î»ù±¾µÄ"hello-word" ÐÎʽµÄ³ÌÐò:
; asmhello.asm ========================================================
global main
extern printf
section .data
msg db "Helloooooo, nurse!",0Dh,0Ah,0
section .text
main:
push dword msg
call printf
pop eax
ret
; EOF =================================================================
¸ÙÒª: "global main" ±ØÐëÉùÃ÷Ϊȫ¾ÖµÄ(global) -- ²¢ÇÒ¼ÈÈ»ÎÒÃÇÓà GCC À´Á´½Ó,½øÈëµã±ØÐëÒÔ "main" À´ÃüÃû -- ´Ó¶ø×°Èëϵͳ. "extern printf" Ö»ÊÇÒ»¸öÉùÃ÷,ΪÒÔºóÔÚ³ÌÐòÖе÷ÓÃ; ×¢ÒâÕâÊDZØÐëµÄ; ²ÎÊýµÄ´óС²»ÐèÒªÉùÃ÷. ÎÒÒѾ­°ÑÕâ¸öÀý×ÓÓñê×¼µÄ .data, .text ·Ö½Ú, µ«Õâ²»ÊÇÑϸñ±ØÐëµÄ -- ¿ÉÄÜÖ»ÐèÒªÒ»¸ö .text¶Î, ¾ÍÏñÔÚ DOS ÏÂÒ»Ñù.
ÔÚ´úÂëµÄÖ÷Ì岿·Ö, Äã±ØÐë°Ñ²ÎÊýѹջÀ´´«µÝ¸øµ÷ÓÃ. ÔÚ Nasm Àï, Äã±ØÐëÉùÃ÷ËùÓв»Ã÷È·Êý¾ÝµÄ´óС; Òò´Ë¾ÍÓÐ "dword" Õâ¸öÏÞ¶¨´Ê. ×¢ÒâºÍÆäËû»ã±àÆ÷Ò»Ñù,Nasm ¼ÙÉèËùÓеÄÄÚ´æ/±êºÅµÄÒýÓö¼Ö¸µÄÊÇÄÚ´æµØÖ·»òÕß±êºÅ, ¶ø²»ÊÇËüµÄÄÚÈÝ.
Òò¶ø, Ö¸Ã÷×Ö·û´® msg µÄµØÖ·, ÄãÓ¦¸ÃʹÓà push dword msg, Ö¸Ã÷×Ö·û´® msg µÄÄÚÈÝ, Ó¦¸ÃÓà push dword [msg] (ÕâÖ»ÄÜ°üº¬ msg µÄÇ°Ëĸö×Ö½Ú). ÒòΪ printf
ÐèÒªÒ»¸öÖ¸Ïò×Ö·û´®µÄÖ¸Õë, ÎÒÃÇÓ¦¸ÃÖ¸Ã÷ msg µÄµØÖ·.
µ÷Óà printf ·Ç³£µÄÖ±½Ó. ×¢Òâÿһ´Îµ÷ÓúóÄã±ØÐë°ÑÕ»Çå³ý(¼ûÏÂ); ËùÒÔ PUSH ÁËÒ»¸ö
dword ºó, ÎÒ´ÓÕ»Àï°ÑÒ»¸ö dword POP ½øÒ»¸öÎÞÓõļĴæÆ÷. Linux ³ÌÐòÖ»¼òµ¥µÄÓÃÒ»¸ö RET À´·µ»Øϵͳ, ÓÉÓÚÿ¸ö½ø³Ì¶¼ÊÇ shell(»òÕßÊÇ PID)µÄ²úÎï, ËùÒÔ³ÌÐò½áÊøºó°Ñ ¿ØÖÆȨ»¹¸øËü.
×¢Òâµ½ÔÚ Linux ÏÂ, ÄãÊÇÔÚ "API" »òÖжϷþÎñµÄ³¡ËùÀïʹÓÃϵͳ´øÀ´µÄ±ê×¼¹²Ïí¿â.

ËùÓеÄÍⲿÒýÓÃÓÉ GCC ¹ÜÀí, Ëü¸ø asm ³ÌÐòÔ±½ÚÊ¡Á˴󲿷ֵŤ×÷. Ò»µ©ÄãÏ°¹ßÁË»ù±¾µÄ¼¼ÇÉ, Linux ϵĻã±à±à³Ìʵ¼ÊÉÏÒª±È DOS ¼òµ¥µÄ¶à.

C µ÷ÓõÄÓï·¨
--------------------
Linux ʹÓà C µÄµ÷ÓÃģʽ -- Òâζ×ŲÎÊýÒÔÏà·´µÄ˳Ðò½øÕ»(×îºóÒ»¸ö×îÏÈ), µ÷ÓÃÕß±ØÐëÇå
³ýÕ». Äã¿ÉÒÔ´ÓÕ»Àï°ÑÖµ pop ³öÀ´:
push dword szText
call puts
pop ecx
»òÕßÖ±½ÓÐÞ¸Ä ESP:
push dword szText
call puts
add esp, 4
µ÷Óõķµ»ØÖµÔÚ eax »ò edx:eax Èç¹ûÖµ´óÓÚ 32 λµÄ»°. EBP, ESI, EDI, EBX Óɵ÷ÓÃÕß
±£´æºÍ»Ö¸´. Äã±ØÐë±£´æÄãҪʹÓõļĴæÆ÷, ÏñÏÂÃæÕâÑù:
; loop.asm =================================================================

global main
extern printf
section .text
msg db "HoodooVoodoo WeedooVoodoo",0Dh,0Ah,0
main:
mov ecx, 0Ah
push dword msg
looper:
call printf
loop looper
pop eax
ret
; EOF ================================================================

´ÖÒ»¿´, ·Ç³£¼òµ¥: ÒòΪÄãÔÚ 10 ¸ö printf() µ÷ÓÃÓõÄÊÇͬһ¸ö×Ö·û´®, Äã²»ÐèÒªÇå³ýÕ». µ«µ±Äã±àÒëÒÔºó, Ñ­»·²»»áÍ£Ö¹. Ϊʲô? ÒòΪ printf() ÀïʲôµØ·½ÓÃÁË ECX µ«Ã»Óб£´æ. ʹÄãµÄÑ­»·ÕýÈ·µÄ¹¤×÷, Äã±ØÐëÔÚµ÷ÓÃ֮ǰ±£´æ ECX µÄÖµ, µ÷ÓÃÖ®ºó»Ö¸´Ëü, ÏñÕâÑù:
; loop.asm ================================================================
global main
extern printf
section .text
msg db "HoodooVoodoo WeedooVoodoo",0Dh,0Ah,0
main:
mov ecx, 0Ah
looper:
push ecx ;save Count
push dword msg
call printf
pop eax ;cleanup stack
pop ecx ;restore Count
loop looper
ret
; EOF ================================================================

I/O ¶Ë¿Ú±à³Ì
--------------------
µ«Ö±½Ó·ÃÎÊÓ²¼þ»áÔõôÑùÄØ? ÔÚ Linux ÏÂÄãÐèÒªÒ»¸öºËÐÄģʽµÄÇý¶¯³ÌÐòÀ´×öÕâЩ¹¤×÷... ÕâÒâζ×ÅÄãµÄ³ÌÐò±ØÐë·Ö³ÉÁ½¸ö²¿·Ö, Ò»¸öºËÐÄģʽÌṩӲ¼þÖ±½Ó²Ù×÷µÄ¹¦ÄÜ, ÆäËûµÄÓû§Ä£Ê½Ìṩ½Ó¿Ú. Ò»¸öºÃÏûÏ¢¾ÍÊÇÄãÈÔÈ»¿ÉÒÔÔÚÓû§Ä£Ê½µÄ³ÌÐòÖÐʹÓÃIN/OUT À´·ÃÎʶ˿Ú.
Òª·ÃÎʶ˿ÚÄãµÄ³ÌÐò±ØÐëÈ¡µÃϵͳµÄͬÒâ; Òª×öÕâ¸ö, Äã±ØÐëµ÷Óà ioperm(). Õâ¸öº¯ÊýÖ»Äܱ»ÓÐ root ȨÏÞµÄÓû§Ê¹ÓÃ, ËùÒÔÄã±ØÐëÓà setuid() ʹ³ÌÐòµ½ root »òÕßÖ±½ÓÔËÐÐÔÚ root ÏÂ. ioperm() µÄÓï·¨ÊÇÕâÑù:
ioperm( long StartingPort#, long #Ports, BOOL ToggleOn-Off)
StartingPort# Ö¸Ã÷Òª·ÃÎʵĵÚÒ»¸ö¶Ë¿ÚÖµ(0 ÊÇ¶Ë¿Ú 0h, 40h ÊÇ¶Ë¿Ú 40h, µÈµÈ),#Ports
Ö¸Ã÷Òª·ÃÎʶàÉÙ¸ö¶Ë¿Ú(Ò²¾ÍÊÇ˵, StartingPort# = 30h, #Port = 10, ¿ÉÒÔ·ÃÎʶ˿Ú
30h - 39h), ToggleOn-Off Èç¹ûÊÇ TRUE(1) ¾ÍÄܹ»·ÃÎÊ, ÊÇ FALSE(0) ¾Í²»ÄÜ·ÃÎÊ.
Ò»µ©µ÷ÓÃÁË ioperm(), ÒªÇóµÄ¶Ë¿Ú¾ÍºÍƽ³£Ò»Ñù·ÃÎÊ. ³ÌÐò¿ÉÒÔµ÷Óà ioperm() ÈÎÒâ¶à´Î,
¶ø²»ÐèÒªÔÚºóÀ´µ÷Óà ioperm()(µ«ÏÂÃæµÄÀý×ÓÕâÑù×öÁË), ÒòΪϵͳ»á´¦ÀíÕâЩ.
; io.asm ==============================================================
=
BITS 32
GLOBAL szHello
GLOBAL main
EXTERN printf
EXTERN ioperm
SECTION .data
szText1 db Enabling I/O Port Access,0Ah,0Dh,0
szText2 db Disabling I/O Port Acess,0Ah,0Dh,0
szDone db Done!,0Ah,0Dh,0
szError db Error in ioperm() call!,0Ah,0Dh,0
szEqual db Output/Input bytes are equal.,0Ah,0Dh,0
szChange db Output/Input bytes changed.,0Ah,0Dh,0
SECTION .text
main:
push dword szText1
call printf
pop ecx
enable_IO:
push word 1 ; enable mode
push dword 04h ; four ports
push dword 40h ; start with port 40
call ioperm ; Must be SUID "root" for this call!
add ESP, 10 ; cleanup stack (method 1)
cmp eax, 0 ; check ioperm() results
jne Error
;---------------------------------------Port Programming Part--------------
SetControl:
mov al, 96 ; R/W low byte of Counter2, mode 3
out 43h, al ; port 43h = control register
WritePort:
mov bl, 0EEh ; value to send to speaker timer
mov al, bl
out 42h, al ; port 42h = speaker timer
ReadPort:
in al, 42h
cmp al, bl ; byte should have changed--this IS a timer :)
jne ByteChanged
BytesEqual:
push dword szEqual
call printf
pop ecx
jmp disable_IO
ByteChanged:
push dword szChange
call printf
pop ecx
;---------------------------------------End Port Programming Part----------
disable_IO:
push dword szText2
call printf
pop ecx
push word 0 ; disable mode
push dword 04h ; four ports
push dword 40h ; start with port 40h
call ioperm
pop ecx ;cleanup stack (method 2)
pop ecx
pop cx
cmp eax, 0 ; check ioperm() results
jne Error
jmp Exit
Error:
push dword szError
call printf
pop ecx
Exit:
ret
; EOF ======================================================================

ÔÚ Linux ÏÂʹÓÃÖжÏ
-------------------------
Linux ÊÇÒ»¸öÔËÐÐÔÚ±£»¤Ä£Ê½ÏµĹ²Ïí¿âµÄ»·¾³, Òâζ×ÅûÓÐÖжϷþÎñ, Right?
´íÁË. ÎÒ×¢Òâµ½ÔÚ GAS µÄÀý×ÓÔ´ÂëÖÐÓÃÁË INT 80, ×¢ÊÍÊÇ "sys_write(ebx, ecx, ed
x)".
Õâ¸öº¯ÊýÊÇ Linux ϵͳµ÷ÓýӿڵÄÒ»²¿·Ö, Òâ˼ÊÇ INT 80 ±ØÐëÊǵ½´ïϵͳµ÷Ó÷þÎñ
µÄÃÅ»§. ÔÚ Linux Ô´ÂëÖе½´¦¿´Ê±(ºöÂÔ´Ó²»ÒªÊ¹Óà INT 80 ½Ó¿ÚµÄ¾¯¸æ, ÒòΪº¯ÊýºÅ

¿ÉÄÜËæʱ¸Ä±ä), ÎÒ·¢ÏÖ "ϵͳµ÷ÓúÅ(system call numbers)" -- ¾ÍÊÇ˵, ´«¸ø INT
80
µÄ # ¶ÔÓ¦×ÅÒ»¸öϵͳµ÷ÓÃ×Ó³ÌÐò -- ÔÚ UNISTD.H ÖÐ. Ò»¹²ÓÐ 189 ¸ö, ËùÒÔÎÒ²»»áÔÚ

ÕâÀïÁгöÀ´...µ«Èç¹ûÄãÔÚ Linux ×ö»ã±à, ¸ø×Ô¼º×ö¸öºÃÊÂ, ´òÓ¡³öÀ´°É.
µ±µ÷Óà INT 80 ʱ, eax ÉèΪÓõ÷ÓõŦÄܺÅ. ´«¸øϵͳµ÷ÓÃÔò³ÌÐòµÄ²ÎÊý±ØÐ밴˳Ðò

·ÅÔÚÏÂÁмĴæÆ÷ÖÐ:
ebx, ecx, edx, esi, edi
ÕâÑù, µÚÒ»¸ö²ÎÊý¾ÍÔÚ ebx Àï, µÚ¶þ¸öÔÚ ecx Àï... ×¢ÒâÔÚÒ»¸öϵͳµ÷ÓóÌÐòÀï, ²»
ÊÇ
ÓÃÕ»À´´«µÝ²ÎÊý. µ÷Óõķµ»ØÖµÔÚ eax Àï.
»¹ÓÐ, INT 80 ½Ó¿ÚºÍÒ»°ãµÄµ÷ÓÃÒ»Ñù. ÏÂÃæµÄÕâ¸ö³ÌÐò¾ÍÑÝʾÁË INT 80h µÄʹÓÃ. Õâ
¸ö
³ÌÐò¼ì²é²¢ÏÔʾÁËËü×Ô¼ºµÄ PID. ×¢Òâ ʹÓà printf() ¸ñʽ»¯×Ö·û´® -- Õâ¸öµ÷ÓõÄ
C ½á¹¹
ÊÇ:
printf( "%d\n", curr_PID);
ҲҪעÒâ½áÊø·ûÔÚ»ã±àÀï²»Ò»¶¨¿É¿¿, ÎÒ³£ÓÃÊ®Áù½øÖÆ(0Ah, 0Dh)´ú±í CR\LF.
;pid.asm====================================================================

BITS 32
GLOBAL main
EXTERN printf
SECTION .data
szText1 db Getting Current Process ID...,0Ah,0Dh,0
szDone db Done!,0Ah,0Dh,0
szError db Error in int 80!,0Ah,0Dh,0
szOutput db \%d,0Ah,0Dh,0 ;printf() µÄ¸ñʽ×Ö·û´®
SECTION .text
main:
push dword szText1 ;¿ªÊ¼ÐÅÏ¢
call printf
pop ecx
GetPID:
mov eax, dword 20 ; getpid() ϵͳµ÷ÓÃ
int 80h ; ϵͳµ÷ÓÃÖжÏ
cmp eax, 0 ; ûÓÐ PID 0 ! :)
jb Error
push eax ; °Ñ·µ»ØÖµ´«µÝ¸ø printf
push dword szOutput ; °Ñ¸ñʽ×Ö·û´®´«µÝ¸ø printf
call printf
pop ecx ; Çå³ýÕ»
pop ecx
push dword szDone ; ½áÊøÐÅÏ¢
call printf
pop ecx
jmp Exit
Error:
push dword szError
call printf
pop ecx
Exit:
ret
; EOF =====================================================================
×îºóµÄ»°
-----------
´ó¶àÊýµÄÂé·³À´×Ô¶Ô Nasm µÄÏ°¹ßÉÏ. ¶ø nasm ´øÓÐÊÖ²á, µ«È±Ê¡ÊDz»°²×°µÄ,
ËùÒÔÄã±ØÐë°ÑËü´Ó
/user/local/bin/nasm-0.97/nasm.man
ÒÆ(cp »ò mv)µ½
/usr/local/man/man1/nasm.man.
¸ñʽÓеãÂÒ, ¿ÉÒԺܼòµ¥µÄÓà nroff ָʾ·ûÀ´½â¾ö. µ«Ëü²»»á¸øÄã Nasm µÄÕû¸öÎÄ
µµ; Òª½â¾öÕâ¸öÎÊÌâ, °Ñ nasmdoc.txt ´Ó
/usr/local/bin/nasm-0.97/doc/nasmdoc.txt
¿½±´µ½
/usr/local/man/man1/nasmdoc.man
ÏÖÔÚÄã¿ÉÒÔÓà man nasm, man nasmdoc À´¿´ nasm µÄÊÖ²áºÍÎĵµÁË
ÏëµÃµ½¸ü¶àµÄÐÅÏ¢, ²é²éÕâÀï:
Linux Assembly Language HOWTO (Linux »ã±àÓïÑÔ HOWTO)
Linux I/O Port Programming Mini-HOWTO (Linux I/O ¶Ë¿Ú±à³Ì Mini-HOWTO)
Jans Linux & Assembler HomePage (http://www.bewoner.dma.be/JanW/eng.html)
ÎÒÒ²Òª¸Ðл Jeff Weeks(http://gameprog.com/codex), ÔÚÎÒÕÒµ½ Jan µÄÍøҳ֮ǰ
¸øÁËÎÒһЩ GAS µÄ hello-world ´úÂë.
ÎÄÕÂÆÀÂÛ

¹²ÓÐ 5 ÌõÆÀÂÛ

  1. yeqishi ÓÚ 2010-04-29 15:21:58·¢±í:

    ºÃ¶¨Î÷£¬ÊÕ²ØÁË

  2. ¸Ð¾õ˲¼ä ÓÚ 2005-10-29 01:19:37·¢±í:

    ѧϰÁË

  3. Ñà¹ýÁÖɽ ÓÚ 2005-10-09 00:22:19·¢±í:

    ѧϰÁË

  4. kerzy ÓÚ 2005-08-07 21:52:04·¢±í:

    Ö§³Ö

  5. linux ÓÚ 2005-08-04 00:15:11·¢±í:

    ¶¥