Linux x86 Assembler Programming-general Linux technology-Linux programming and kernel information. The following is a detailed description. Essentially, this article combines two programming things that interest me most: the Linux operating system and assembly language programming. neither of these two needs to be introduced (or should not); like Win32 assembly, Linx Assembly runs in 32-bit protection mode... however, it has another distinct advantage: it allows you to call C's standard library functions and Linux's shared library functions. I started to give a brief introduction to assembly language programming in Linux. To better read this, you may have to skip this basic section.
Compilation and link
---------------------
In Linux, the two most important compilers are Nasm (free, Netwide compiler ER) and GAS (free, Gnu Compiler ER ),
The last one is combined with GCC. In this article, I will focus on Nasm and put GAS behind it, because it uses AT&T syntax and requires a long introduction.
The ELF format option ("Nasm-f elf hello. asm "); the generated target file is linked using GCC (" gcc hello. o ") to generate the final ELF binary code. the following script can be used to compile the ASM module. I try to write it easily, so all it does is to accept the first file name passed to it and compile it with Nasm, use GCC to link.
#! /Bin/sh
# Assemble. sh ======================================================== ============================
Outfile =$ {1% % .*}
Tempfile = asmtemp. o
Nasm-o $ tempfile-f elf $1
Gcc $ tempfile-o $ outfile
Rm $ tempfile-f
# EOF =================================================== ======================================
Basic knowledge:
----------
Of course, the best thing is to start with an example before learning about the system details. Here is a basic program in the "hello-word" format:
; 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 =================================================== ======================================
Outline: "global main" must be declared as global -- and since we use GCC for link, the entry point must be named "main" -- to mount the system. "extern printf" is only a declaration that will be called in the program later. Note that this is required. The parameter size does not need to be declared. I have used this example as a standard. data ,. text is segmented, but this is not strictly required-only one. text Segment, just like in DOS.
In the main part of the code, you must pass the parameter pressure stack to the call. in Nasm, you must declare the size of all ambiguous data. Therefore, there is a qualified word "dword. note that, like other compilers, Nasm assumes that all memory/label references refer to the memory address or label, rather than its content.
Therefore, specify the string msg address. You should use push dword msg to specify the content of the string msg, and use push dword [msg] (this can only contain the first four bytes of msg ). because printf
We need a pointer to the string. We should specify the msg address.
The call to printf is very direct. Note that you must clear the stack after each call (see below); therefore,
After dword, I POP a dword from the stack into a useless register. the Linux program simply uses a RET to return to the system. Since each process is a product of shell (or PID), the control is returned after the program ends.
Note that in Linux, you use the standard shared libraries brought by the system in an "API" or service interruption location.
All external references are managed by GCC, which saves most of the work for asm programmers. Once you get used to basic skills, assembly programming in Linux is much simpler than DOS.
C call syntax
--------------------
Linux uses the C call mode-meaning that the parameters are pushed to the stack in reverse order (the last one is the first), and the caller must clear
In addition to the stack, you can pop the value from the stack:
Push dword szText
Call puts
Pop ecx
Or directly modify the ESP:
Push dword szText
Call puts
Add esp, 4
The returned value of the call is eax or edx: eax if the value is greater than 32 bits. EBP, ESI, EDI, EBX by the caller
Save and restore. You must save the register you want to use, as shown below:
; Loop. asm ============================================== ======================================
Global main
Extern printf
Section. text
Msg db "HoodooVoodoo WeedooVoodoo", 0Dh, 0Ah, 0
Main:
Mov ecx, 0Ah
Push dword msg
Logoff:
Call printf
Loop Logoff
Pop eax
Ret
; EOF =================================================== ======================================
A rough look is very simple: because you use the same string in 10 printf () calls, you do not need to clear the stack. however, after compilation, the loop will not stop. why? Because ECX is used in printf () but it is not saved, so that your loop works correctly, you must save the value of ECX before calling and restore it after calling, as shown in the following code:
; Loop. asm ============================================== ======================================
Global main
Extern printf
Section. text
Msg db "HoodooVoodoo WeedooVoodoo", 0Dh, 0Ah, 0
Main:
Mov ecx, 0Ah
Logoff:
Push ecx; save Count
Push dword msg
Call printf
Pop eax; cleanup stack
Pop ecx; restore Count
Loop Logoff
Ret
; EOF =================================================== ======================================
I/O port programming
--------------------
But what if I access the hardware directly? In Linux, you need a core-mode driver to do this... this means that your program must be divided into two parts. One core mode provides direct hardware operation, and the other user mode provides interfaces. the good news is that you can still use IN/OUT to access the port IN a user-Mode Program.
To access the port, your program must obtain the system's consent. To do this, you must call ioperm (). this function can only be used by users with root permissions. Therefore, you must use setuid () to send the program to root or directly run it under root. the ioperm () syntax is as follows:
Ioperm (long StartingPort #, long # Ports, BOOL ToggleOn-Off)
StartingPort # specify the first port to be accessed (0 is port 0 h, 40 h is port 40 h, etc.), # Ports
Specify the number of ports to be accessed (that is, StartingPort # = 30 h, # Port = 10 ).
30 h-39 h), ToggleOn-Off. If it is TRUE (1), it can be accessed. If it is FALSE (0), it cannot be accessed.
Once ioperm () is called, the required port is accessed as usual. The program can call ioperm () multiple times,
Instead of calling ioperm () later (but the following example does), because the system will process these.
; 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 04 h; four ports
Push dword 40 h; 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 43 h, al; port 43 h = control register
WritePort:
Mov bl, 0EEh; value to send to speaker timer
Mov al, bl
Out 42 h, al; port 42 h = speaker timer
ReadPort:
In al, 42 h
Cmp al, bl; byte shoshould 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 04 h; four ports
Push dword 40 h; start with port 40 h
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 =================================================== ====================================
Interruption in Linux
-------------------------
Linux is an environment for shared libraries running in protected mode. It means that the service is not interrupted, Right?
Wrong. I noticed that INT 80 is used in the GAS example source code, and the comment is "sys_write (ebx, ecx, ed
X )".
This function is part of the Linux system call interface, meaning that INT 80 must arrive at the system call service.
In Linux source code (ignore warnings that do not use the INT 80 interface, because the function number
May change at any time), I found that "system call numbers" -- that is, passed to INT
80
# Corresponds to a system call subroutine-In UNISTD. H, there are a total of 189 subprograms, so I will not
It is listed here... but if you are doing a compilation in Linux and doing a good thing for yourself, print it out.
When INT 80 is called, eax is set to use the called function number. If it is passed to the system call, the program parameters must be in order.
In the following registers:
Ebx, ecx, edx, esi, edi
In this way, the first parameter is in ebx, and the second parameter is in ecx... note that in a system calling program
Yes
The stack is used to pass parameters. The returned value of the call is in eax.
Also, the INT 80 interface is the same as the general call. The following program demonstrates the use of INT 80 h.
Items
The program checks and displays its own PID. Be sure to format the string using printf ()-The called
C Structure
Yes:
Printf ("% d \ n", curr_PID );
Note that the Terminator is not necessarily reliable in the Assembly. I usually use hexadecimal (0Ah, 0Dh) to represent 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 () Format String
SECTION. text
Main:
Push dword szText1; start information
Call printf
Pop ecx
GetPID:
Mov eax, dword 20; getpid () system call
Int 80 h; system call interrupted
Cmp eax, 0; no PID 0!
Jb Error
Push eax; pass the returned value to printf
Push dword szOutput; pass the format string to printf
Call printf
Pop ecx; clear Stack
Pop ecx
Push dword szDone; end information
Call printf
Pop ecx
Jmp Exit
Error:
Push dword szError
Call printf
Pop ecx
Exit:
Ret
; EOF =================================================== ====================================
Last words
-----------
Most of the troubles come from the habit of Nasm. nasm has a manual, but it is not installed by default,
So you must extract it from
/User/local/bin/nasm-0.97/nasm. man
Migrate (cp or mv)
/Usr/local/man/man1/nasm. man.
The format is messy and can be easily solved using the nroff indicator, but it will not give you the entire Nasm file.
To solve this problem
/Usr/local/bin/nasm-0.97/doc/nasmdoc.txt
Copy
/Usr/local/man/man1/nasmdoc. man
Now you can use man nasm and man nasmdoc to view the nasm manual and documents.
For more information, check here:
Linux Assembly Language HOWTO (Linux Assembly Language HOWTO)
Linux I/O Port Programming Mini-HOWTO (Linux I/O Port Programming Mini-HOWTO)
Jans Linux & explorer HomePage (http://www.bewoner.dma.be/JanW/eng.html)
I would also like to thank Jeff Weeks (http://gameprog.com/codex) before I found Jan's web page
Gave me some GAS hello-world code.
The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion;
products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the
content of the page makes you feel confusing, please write us an email, we will handle the problem
within 5 days after receiving your email.
If you find any instances of plagiarism from the community, please send an email to:
info-contact@alibabacloud.com
and provide relevant evidence. A staff member will contact you within 5 working days.