XAsmTools |
X
Server
(Desktop) Programming in Assembler
jeff owens @2008 GNU General Public License CONTENTS 1. Introduction - what this document covers 2. Linux Programming Environments 3. Overview of X programming 4. Connecting to the X server 5. Sending X commands 6. Receiving X data 7. Speed Considerations 8. X protocol extensions 9. Compiling 10 Example program using asmlibx 11. Example program without asmlibx 12. Debugging 13. X tools 14. Useful Links 15. Example 1 source 16. Example 2 source 1.0 Introduction ---------------- This document explores assembler programming for the Linux x server. It describes building a sample program and debugging x programs. 2.0 Linux Programming Environments ---------------------------------- Linux programs can run in the console, on a terminal, or utilize the X server. Each environment is unique and has different features available. A short summary follows: Console programs talk directly to the Linux kernel and most are command line (text) programs. The kernel does not supply graphics functions, mouse drivers, or audio handlers. This environment is home to a large number of classical unix utilities. It can host very fast and efficient programming, has lots of documentation, and can be confusing to new programmers. Terminal programs run in a "terminal" talking to the X server. The terminal environment is very close the the console environment and most console programs can also run on a terminal. There are a large number of different terminals and each provides different features. The more popular terminals add mouse handling and menus to control fonts and other features. X servers are starting to dominate Linux computing and provide a more robust and simpler interface for most programming jobs. The X server provides very good handling for keyboards, mice, graphics, and adds window control for working with multiple programs at the same time. Which environment is best for portable programs? Assembler isn't considered portable and very few tools assist with portability. Currently there is an library (HLA) that provides some basic functions. It supports terminal programming and may be useful for simple text programs. There are many non-assembler libraries that supply portability for X server/Microsoft and they can be called from most assemblers. Portable assemblers include nasm and fasm. Unix to Unix portability has been attempted on the LinuxAssembly web site, but has not got a lot of support. If portability is a goal the best path is probably to work in a HLL such as "C" and use one of the portable libraries. If the choice is between console/terminal/ x server programming, the x server interface is well standardized and available on other operating systems. Why choose console/terminal programming? Unix administration and setup is still done in the console and on terminals. Servers and other demanding tasks, do not need a X server and run from the console. Also, many embedded systems or standalone work stations have chosen efficient console programming. All these programs are textual and work on minimal hardware. For textual programs needing efficiency, choose the console. Why choose X server programming? Today most games, applications, browsers, and general use software runs under the X server. This environment provides a fast growing tool set and very robust programming arena. It also, is home to many bloated and inefficient programs. Assembler can fit into this environment easily, but few tools exist today. It is probably a good choice for casual programming. The largest audience is also on the x desktop and the desktop interacts with web and remote computers. Overall it provides the best future growth path. Other considerations for console/terminals Most Linux assembler information is about terminals or the console. There are lots of example programs and a few libraries. This area is popular with novice programmers, but they tend to move on to other areas. The HLL libraries for the console are still maintained, but activity is minimal. Other considerations for X server programming The X server is mostly the domain of HLL languages and libraries. A few programs call the low level xlib and 2 or 3 other low level libraries. Low level X programming fits assembler but design and coding requires a server mind set. All communication with the X server is via a socket and responses to requests or unsolicited input can appear at any time. This makes simple one-step-at-a-time programming unworkable. Instead, programs are usually event driven. For speed all X server requests are collected in a buffer and send in one large transfer. Responses have a sequence number to indicate which request they are for, and not all requests have a response. Most programmers will let the various libraries handle X server communication, but it helps to understand what is happening. 3.0 Overview of X programming ----------------------------- One of the largest problems facing programmers, is supporting all the different displays, keyboards, and other input devices. The manufactures may provide device drivers and often the operating system will try to standardize the interface. Libraries, also try to solve this problem by providing standard routines. A group at MIT decided the best solution was to leap frog the needs of programmers and provide a standard tool with additional features for abstraction and multiprocessing. This would allow displays to be on a remote computer or even multiple displays on one computer. They also addressed problems with multiple users and programs sharing the same display. Next, they wrote a low level library to further isolate programmers from the details. Today, most programs have gone further and add another library level. The picture looks something like this: computer hardware operating system x server x library HLL library applications This stack of handlers has produced fairly fast programs, but often they end up bloated in size and slow to load. Assembler programmers can work with the x library or with the HLL library, and may prefer doing graphic applications using these libraries. For non-graphical applications, the assembly programmer can easily bypass the standard libraries and gain some speed and size advantages. This document introduces the tools and information needed for talking directly to a x server. Another concept to be aware of is abstraction. With x servers we have levels of usage: display desktop window sub-window The display can be a device or file and a computer can have multiple displays defined. Within a display we can have multiple desktops. Each desktop can have a set of windows, and windows can have sub-windows. Any program can talk to these abstract items and request control of resources. Creating them and finding out about them is where things get difficult. 4.0 Connecting to the X server ------------------------------ In a multiprocessing environment you want the display to be available for everyone and still resolve conflicts. Also, you want to avoid having any process hog the communication channels. This is accomplished by using a socket that any process can connect to. To keep this socket secure a simple handshake process was defined. Once we have a socket connected, the data flows to and from the x server as demand requires. We don't have to worry about other programs. The connection process goes like this: 1. Select the display. Usually, we look in a programs environment for the variable: DISPLAY=0:0 The 0:0 specifies our target display. 2. Look for the authorization string. This key will open x server communication and is often placed in a local file. 3. Create a socket and send our key 4. Read reply with connection information. 5.0 Sending X commands ---------------------- Commands are sent as packets of information. These packets share a standard format and set of rules. For portability all packets have lengths in multiples of dwords. The initial packet always contains: 1 byte - op code 1 byte - value depends upon op code 2 bytes- length of this request in dwords The rest of the packet depends upon the op code. The format of the various op codes is called the protocol. Each request has a sequence number associated with it. The first request will be "1" and the next "2", etc. This number must be kept by the sending function and another counter is kept by the x server. This sequence number is needed to identify replies. The next section will discuss this further. The protocol op codes (request codes) are:
The fields for each request code are documented at MIT (see links). A good description of these requests is contained in the book: X protocol Reference Manual, by O'Reilly & Associates 6.0 Receiving X data -------------------- Some protocol commands have replies and most can generate errors. If we have windows, then they we can enable various event notifications. All received data follows these rules: 1. The initial packet is 32 bytes long and has a standard header. Normal replies have a op code of "1" and errors have a opcode of "0". Other opcodes are defined for events. 2. If additional information is coming, it's size is given. 3. All replies to requests must provide a sequence number The initial packet looks like this: 1 byte - code 1 byte - (depends upon code) 2 bytes- sequence number (if reply or error) 4 bytes- length of additional data to be sent The remaining fields depend on the code byte value. 7.0 Speed Considerations ------------------------ Commands can be sent at any time and it is possible events can occur at any time. If we collect requests and send a large block at one time, a big speed increase occurs. The same is true of some event processing. All x libraries have request batching and they provide a "flush" function to force sending the current buffer contents. Normally, requests are sent when the buffer is full of requests. 8.0 X protocol extensions -------------------------- Extensions to protocol (requests) can be added by compiling them into x servers. The programmer can use these extensions as follows: 1. Use QueryExtension request to check if extension is available. 2. Get extension opcode from reply to QueryExtension. The example program in section 10.0 will list available extensions. 9.0 Compiling ------------- Our example code is written for the nasm assembler and can be compiled with: nasm -f elf -O999 -g -o example.o example.asm where: -f elf <-- output in elf format -O999 <-- optimization passes -g <-- include debug information -o example.o <-- create object file example.asm <-- assembler source file The example.o output file must be linked with two libraries to create an executable. ld -o example example.o asmlibx.a asmlib.a where: -0 example <-- output executable example.o <-- input file to link asmlibx.a <-- library to link with asmlib.a <-- library to link with The linker "ld" is on almost all Linux distributions and is part of the bin utilities. Nasm is available at sourceforge (see links). 10.0 Example program - using asmlibx ------------------------------------- The full source for example is included in section 15. A discussion of the code follows: Once we are connected, extensive information can be requested from the server. For a starter, we might want to know which extensions this server supports. For this we need to send a protocol request: ListExtensions - protocol #99 If we utilize the library "asmlibx" our program would appear as follows: ---- program start ----- _start: call env_stack ;save ptr to environment call x_list_extension;get x server extensions call show_extensions ;display extensions mov eax,01 ;exit function int byte 80h ;exit program ---- program end ---- The call to env_stack creates a global variable that points to the program environment strings. This is used by a server connection routine to find our display number. The x_list_extension call first checks to see if we are connected, and if not, attempts a connection. Next, it sends a request to server and collects the replies. Finally, the show_extensions is a small subroutine we must write to display the extension names. The complete listing of this program can be found in section 14.0. That was easy, but what happened? Most of the details were handled by asmlibx and we are left with the results. What if we wanted to go down another level? The next example goes into the gory details. If you want to enter example 1 and test it, skip to section 12 Debugging. 11.0 Example program - without asmlibx -------------------------------------- This example (example2) does not use any libraries and is identical to example 1. It is interesting to note that the source file for example 1 is about 600 bytes and this example has a source file of over 32,000 bytes. Libraries save a lot of coding time and effort! The easiest way to approach x programming is to use a common x connect routine for all programs. Then use the common send/receive handlers to talk to the x server. The server protocol functions may be available in asmlibx, but often they must be coded. In example 2 we will talk about how to code a protocol function and use asmlibx to send and receive data. The library function that connects to a x server is called x_connect. We can call x_connect at the start of a program or let the send function do it for us. Our only requirement is to call env_stack at the start of our program. The two library functions for sending and receiving are: x_send_request x_wait_reply We provide x_send_request with a protocol packet then call x_wait_reply to get the response. The code to get a list of x server extensions would look like this: list_extension_request: db 99 ;opcode db 0 ;unused dw 1 ;request length in dwords qer_end: x_list_extension: mov ecx,list_extension_request mov edx,(qer_end - list_extension_request) neg edx ;indicate reply expected call x_send_request js ger_exit call x_wait_reply ger_exit: ret If a reply is expected we must negate the size of the send packet. The tells the send function that a flush is needed after sending the packet. If we didn't flush, the packet would sit in a buffer and the reply would return a timeout error. If all goes well, the reply pointer will be returned in register ecx. resb 1 ;1 Reply resb 1 ;number of names returned resb 2 ;sequence number resb 4 ;reply length resb 24 ;unused resb 1 ;length of extension n resb x ;extension n string resb 1 ;length of extension n+1 resb x ;extension n+1 string The length of the reply packet is variable and we must check the name count and use it for processing. Also, this reply is held in a temporary buffer and the data must be used before other library functions are called. We now have the tools to code complex programs by adding our own protocol functions. All we need is to connect and then use x_send_request and x_wait_reply . If a library function exists we could use it, but mixing libraries may not work. Each library would try to set up its own x server connection. 12.0 Debugging -------------- To quickly check if the x server communication is occurring, we can use "tracex". Tracex creates a log file containing all server communication packets. Run tracex as follows: tracex example1 The output trace is stored at example1.tra. Entries contain the name of protocol functions, sequence numbers, and a dump of packet contents. We should see the following: --- start of file example1.tra --- Authorization packet written ListExtensions request#=0001 63 00 01 00 c... -Event-reply-to#0001 01 1D 01 00 50 00 00 00 04 00 00 00 01 00 00 00 ....P........... 00 00 00 00 04 00 00 00 90 01 00 00 04 00 00 00 ................ -continuation of reply#0001 05 53 48 41 50 45 16 4D 49 54 2D 53 55 4E 44 52 .SHAPE.MIT-SUNDR 59 2D 4E 4F 4E 53 54 41 4E 44 41 52 44 0C 42 49 Y-NONSTANDARD.BI 47 2D 52 45 51 55 45 53 54 53 04 53 59 4E 43 10 G-REQUESTS.SYNC. 4D 49 54 2D 53 43 52 45 45 4E 2D 53 41 56 45 52 MIT-SCREEN-SAVER 07 58 43 2D 4D 49 53 43 18 58 46 72 65 65 38 36 .XC-MISC.XFree86 2D 56 69 64 4D 6F 64 65 45 78 74 65 6E 73 69 6F -VidModeExtensio 6E 0C 58 46 72 65 65 38 36 2D 4D 69 73 63 0B 58 n.XFree86-Misc.X 46 72 65 65 38 36 2D 44 47 41 04 44 50 4D 53 07 Free86-DGA.DPMS. 54 4F 47 2D 43 55 50 1B 45 78 74 65 6E 64 65 64 TOG-CUP.Extended 2D 56 69 73 75 61 6C 2D 49 6E 66 6F 72 6D 61 74 -Visual-Informat 69 6F 6E 06 58 56 69 64 65 6F 0A 58 2D 52 65 73 ion.XVideo.X-Res 6F 75 72 63 65 0D 44 4F 55 42 4C 45 2D 42 55 46 ource.DOUBLE-BUF 46 45 52 03 47 4C 58 07 53 47 49 2D 47 4C 58 06 FER.GLX.SGI-GLX. 52 45 43 4F 52 44 07 4D 49 54 2D 53 48 4D 0F 58 RECORD.MIT-SHM.X 49 6E 70 75 74 45 78 74 65 6E 73 69 6F 6E 05 58 InputExtension.X 54 45 53 54 09 58 4B 45 59 42 4F 41 52 44 0B 58 TEST.XKEYBOARD.X 43 2D 41 50 50 47 52 4F 55 50 08 53 45 43 55 52 C-APPGROUP.SECUR 49 54 59 06 58 46 49 58 45 53 0F 58 46 72 65 65 ITY.XFIXES.XFree 38 36 2D 42 69 67 66 6F 6E 74 06 52 45 4E 44 45 86-Bigfont.RENDE 52 05 52 41 4E 44 52 06 44 41 4D 41 47 45 00 00 R.RANDR.DAMAGE.. --- end of file example1.tra --- The second entry is our request. It has a op code of 63 hex or 99 decimal. The length field says it is one dword long. Following the request is a reply. The reply code of 01 says we were successful and the length field of 50 says we need to read an additional packet of 80 decimal bytes. If we want to dig a little deeper, the asmbug program will walk through the program as it executes. Type: asmbug example1 AsmBug is easy to use if you just assume it knows what you want. Click on a address to set a break and then click run. Or click step and watch it execute. If you want a complete trace of every instruction, the asmtrace program can be used. It is interactive and also creates the log file example1.tra. Beware, asmtrace produces a lot of data and expect a large file. The final debugging tool is inserting print statements into our example program. Often this works well with event driven programs. Our simple example program will not need print statements, but it is good to be prepared. The asmlib provides some functions to do logging which save registers to avoid introducing additional bugs. links to tracex, asmbug, and asmtrace are in section 14 13.0 X tools ------------ For graphics, sound, and other needs, the HLL libraries may be of interest. Libraries to explore are: GTK, QT, and SDL. xwininfo To get information about displayed windows, run the xwininfo program. It allows you to click on window of interest and then sends a lot of data to stdout. xdpyinfo A good display of x server information can be obtained from xdpyinfo. Just type: xdpyinfo and stand back. It will dump just about everything. 14.0 Useful Links ----------------- link to home of this tutorial and asmlib, asmlibx, asmbug, tracex, and other x related programs https://thlorenz.com/linuxasmtools-net/x/ link to hundreds of X related web sites http://www.rahul.net/kenton/xsites.html#FAQ nasm assembler http://sourceforge.net/projects/nasm bin utilities, ld and others http://www.gnu.org/software/ individual tools http;//sourceforge.net/projects/tracex http://sourceforge.net/projects/asmbug http://sourceforge.net/projects/asmtrace libraries http://sourceforge.net/projects/asmlibx http://sorceforge.net/projects/asmlib X documentation, protocol, extensions http://webcvs.freedesktop.org/xorg/xc/ 15.0 example 1 source --------------------- A source file for this example is in download page of https://thlorenz.com/linuxasmtools-net/x/ ;-code1- extern env_stack extern crt_write extern x_list_extension global _start _start: call env_stack ;save ptr to environment call x_list_extension;get x server extensions call show_extensions ;display extensions mov eax,01 ;exit function int byte 80h ;exit program ;------------------------------------------------ ;subroutine to display list of x server extensions ;inputs: ecx = ptr to reply from x server ; show_extensions: lea esi,[ecx+32] ;get ptr to extension xor eax,eax mov al,[ecx+1] ;get number of extensions mov ebp,eax ;save count show_loop: call line_feed lea ecx,[esi+1] ;get ptr to extension name xor edx,edx mov dl,[esi] ;get length of name add esi,edx ;move to next name inc esi ;move to next name call crt_write ;display extension dec ebp ;dec extension count jnz show_loop ;loop if more names call line_feed ;add final line feed ret ;----------------------------------------------- ;subroutine to display line-feed ;inputs: registers esi,ebp must be ; preserved line_feed: mov ecx,linefeed mov edx,1 call crt_write ret ;----------- [section .data] linefeed: db 0ah [section .text] ;-code end- 16.0 example 2 source --------------------- A source file for this example is in download page of https://thlorenz.com/linuxasmtools-net/x/ ;-code2- ;----------------------------------------------------------------------- ; Copyright (C) 2007 Jeff Owens ; ; This program is free software: you can redistribute it and/or modify ; it under the terms of the GNU General Public License as published by ; the Free Software Foundation, either version 3 of the License, or ; (at your option) any later version. ; ; This program is distributed in the hope that it will be useful, ; but WITHOUT ANY WARRANTY; without even the implied warranty of ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ; GNU General Public License for more details. ; ; You should have received a copy of the GNU General Public License ; along with this program. If not, see <http://www.gnu.org/licenses/>. global _start _start: call env_stack call x_list_extension call show_extensions mov eax,01 int byte 80h ;----------- [section .data] crlf: db 0ah [section .text] show_extensions: lea esi,[ecx+32] xor eax,eax mov al,[ecx+1] ;get number of items returned mov ebp,eax ;save count show_loop: call line_feed lea ecx,[esi+1] xor edx,edx mov dl,[esi] ;get length of name add esi,edx ;move to next name inc esi call crt_write dec ebp jnz show_loop call line_feed ret line_feed: mov ecx,crlf mov edx,1 call crt_write ret ;---------- x_list_extension ------------------ ; x_list_extension - get list of extensions ; INPUTS ; none ; OUTPUT: ; failure - eax = negative error code ; flags set for "js" ; success - eax positive read length and flag set "jns" ; ecx = buffer ptr with ; resb 1 ;1 Reply ; resb 1 ;number of names returned ; resb 2 ;sequence number ; resb 4 ;reply length ; resb 24 ;unused ; resb 1 ;length of extension n ; resb x ;extension n string ; resb 1 ;length of extension n+1 ; resb x ;extension n+1 string ; * ---------------------------------------------- x_list_extension: mov ecx,list_extension_request mov edx,(qer_end - list_extension_request) neg edx ;indicate reply expected call x_send_request js ger_exit call x_wait_reply ger_exit: ret [section .data] list_extension_request: db 99 ;opcode db 0 ;unused dw 1 ;request length in dwords qer_end: [section .text] ;-------------------------------------------------- ; env_stack - find stack ptrs to environment ; INPUTS ; esp = stack ptr before any pops or pushes ; OUTPUT ; ebp = ptr to environment pointers ; [enviro_ptrs] set also ; * ---------------------------------------------- env_stack: cld mov esi,esp es_lp: lodsd or eax,eax jnz es_lp ;loop till start of env ptrs mov ebp,esi mov [enviro_ptrs],esi ret ;-------------------------------------------------------- struc connect_reply .reply_code resb 1 resb 1 ;unused .proto_major resw 1 .proto_minor resw 1 .append_len resw 1 ;dword len .release_num resd 1 .id_base resd 1 .id_mask resd 1 .motion_buf_len resd 1 .vendor_len resw 1 .max_req_size resw 1 .screen_cnt resb 1 ;number of screen struc's at end .format_cnt resb 1 ;number of format struc's at end .img_byte_ordr resb 1 ;image byte order 0=lsb 1=msb .map_byte_ordr resb 1 ;bitmap byte order 0=least sig first .scan_unit resb 1 .scan_pad resb 1 .min_keycode resb 1 .max_keycode resb 1 resd 1 ;unused .vendor resb 8 ;string here .pad resb 12 ;? .formats: ;format strucs start here, followed by screen strucs connect_reply_len: endstruc struc format .depth resb 1 .bytes_per_pix resb 1 .scanline_pad resb 1 resb 5 ;unused format_len: endstruc struc screen .root_win resd 1 .color_map resd 1 .white_pixel resd 1 .black_pixel resd 1 .event_mask resd 1 .pix_width resw 1 .pix_height resw 1 .width_mil resw 1 .height_mil resw 1 .min_maps resw 1 .max_maps resw 1 .root_visual resd 1 .backing resb 1 ;0=never 1=when mapped 2=always .save_under resb 1 ;bool .root_depth resb 1 .depth_cnt resb 1 ;number of depths that follow ;more data here endstruc ;--------------------- ; x_connect - connect to x server ; INPUTS ; env_stack library function must be called before ; using x_connect ; OUTPUT: ; flag set (jns) if success ; and [socket_fd] global set to socket fd (dword) ; [x_id_base] base for id assign (dword) ; [root_win_id] set (dword) ; [root_win_pix_width] set (word) ; [root_win_pix_height] set (word) ; [root_win_color_map] set (dword) ; lib_buf has connection reply ; connection_reply_length = size of reply ; flag set (js) if err, eax=error code ; ecx points to connection table as follows: ; c_reply_code db 0 ; db 0 ;unused ; c_proto_major dw 0 ; c_proto_minor dw 0 ; c_append_len dw 0 ;dword len ; c_release_num dd 0 ; x_id_base dd 0 ; c_id_mask dd 0 ; c_motion_buf_len dd 0 ; c_vendor_len dw 0 ; c_max_req_size dw 0 ; c_screen_cnt db 0 ;number of screen struc's at end ; c_format_cnt db 0 ;number of format struc's at end ; c_img_byte_ordr db 0 ;image byte order 0=lsb 1=msb ; c_map_byte_ordr db 0 ;bitmap byte order 0=least sig first ; c_scan_unit db 0 ; c_scan_pad db 0 ; c_min_keycode db 0 ; c_max_keycode db 0 ; ; c_depth db 0 ; c_bytes_per_pix db 0 ; c_scanline_pad db 0 ; db 0 ;pad ; root_win_id dd 0 ; root_win_color_map dd 0 ; c_white_pixel dd 0 ; c_black_pixel dd 0 ; c_event_mask dd 0 ; root_win_pix_width dw 0 ; root_win_pix_height dw 0 ; c_width_mil dw 0 ; c_height_mil dw 0 ; c_min_maps dw 0 ; c_max_maps dw 0 ; c_root_visual dd 0 ; c_backing db 0 ;0=never 1=when mapped 2=always ; c_save_under db 0 ;bool ; c_root_depth db 0 ; c_depth_cnt db 0 ;number of depths that follow ; * ---------------------------------------------- x_connect: xor eax,eax cmp dword [socket_fd],eax jne err ;exit if already connected ;check if environment variable DISPLAY=:x set mov ecx,display_var mov edx,display_var_contents call find_env_variable mov al,[display_var_contents+1] or al,al jz x_conn_strt ;jmp if no display variable mov [display_number],al x_conn_strt: call get_authorization ;get server info js err ;exit if error call connect ;connect to socket js err ;exit if error mov [connection_reply_length],eax mov esi, lib_buf cmp byte [esi],1 je x_conn_ok mov eax,-1 jmp short err x_conn_ok: ;save data from connnecton reply mov edi,c_reply_code mov esi,lib_buf mov ecx,(c_max_keycode+1) - c_reply_code rep movsb mov esi,lib_buf+connect_reply_len mov ecx,4 rep movsb ;compute index to first screen struc xor eax,eax mov ax,[lib_buf+connect_reply.format_cnt] shl eax,3 ;multiply by 8 add eax,connect_reply_len ;move to start of screen struc add eax,lib_buf ;add in buffer start mov esi,eax mov ecx,36 rep movsb mov ecx,c_reply_code err: ret ;-------------- [section .data] connection_reply_length: dd 0 socket_fd: xfd_array: dd 0,-1 c_reply_code db 0 db 0 ;unused c_proto_major dw 0 c_proto_minor dw 0 c_append_len dw 0 ;dword len c_release_num dd 0 x_id_base dd 0 c_id_mask dd 0 c_motion_buf_len dd 0 c_vendor_len dw 0 c_max_req_size dw 0 c_screen_cnt db 0 ;number of screen struc's at end c_format_cnt db 0 ;number of format struc's at end c_img_byte_ordr db 0 ;image byte order 0=lsb 1=msb c_map_byte_ordr db 0 ;bitmap byte order 0=least sig first c_scan_unit db 0 c_scan_pad db 0 c_min_keycode db 0 c_max_keycode db 0 ;struc format c_depth db 0 c_bytes_per_pix db 0 c_scanline_pad db 0 db 0 ;pad ;format_len ;endstruc ;struc screen root_win_id dd 0 root_win_color_map dd 0 c_white_pixel dd 0 c_black_pixel dd 0 c_event_mask dd 0 root_win_pix_width dw 0 root_win_pix_height dw 0 c_width_mil dw 0 c_height_mil dw 0 c_min_maps dw 0 c_max_maps dw 0 c_root_visual dd 0 c_backing db 0 ;0=never 1=when mapped 2=always c_save_under db 0 ;bool c_root_depth db 0 c_depth_cnt db 0 ;number of depths that follow ;more data here ;endstruc [section .text] ;--------------------------------- ;output: eax=negative if error,sign bit set ; connect: ; create a socket mov eax,102 ;socket mov ebx,1 ;create socket mov ecx,socket_create_blk int byte 80h or eax,eax js c_exit mov [socket_fd2],eax mov [socket_fd],eax ; connect to it mov eax,102 ;socket kernel function mov ebx,3 ;connect mov ecx,socket_connect_blk int byte 80h or eax,eax js c_exit ; make the socket non-blocking mov ebx, [socket_fd] mov ecx, 3 ;F_GETFL (get flags) mov eax,55 ;fcntl int byte 0x80 or eax,eax js c_exit ;exit if error mov ebx, [socket_fd] mov ecx, 4 ;F_SETFL (set flags) mov edx, eax or edx, 0x800 ; NON_BLOCKING mov eax,55 ;fcntl int byte 0x80 or eax,eax js c_exit ; write a connection request to it mov eax,4 ;write kernel function mov ebx, [socket_fd] mov ecx, conn_request mov edx, [conn_request_length] int byte 80h or eax,eax js c_exit ;exit if error ; wait for reply mov eax,[socket_fd] mov esi,xfd_array mov [esi],eax ;store fd into array xor eax,eax ;wait forever call wait_event or eax,eax ;error check js conn_err ;test set bit, did our fd have an event? mov eax,[socket_fd] mov edi,ecx call bit_test jc read_conn_reply ;jmp if correct bit conn_err: mov eax,-1 jmp short c_exit ;read the connection reply read_conn_reply: mov ebx, [socket_fd] call read_fd c_exit: or eax,eax ;set return flag ret ;-------------------------------------- ; check for x socket info ;input: [enviro_ptrs] - environment ;output: eax= negative if error ; eax= connection packet setup if eax=positive ; get_authorization: mov ebx,[enviro_ptrs] mov edi,auth_path call env_home ;extract home path mov esi, auth_file_name mov ecx, auth_file_name_len rep movsb ;append .Xauthority to home path open_xauth: mov eax,5 ;open kernel function mov ebx, auth_path xor ecx, ecx ;readonly int byte 80h ;read file .Xauthority mov edi, conn_request_len ;in case no .Xauth found or eax,eax js no_auth ;jmp if file not found ;read and process Xauthority file mov ebx, eax ;get handle in ebx call read_fd js gx_exit ;exit if error mov eax,6 ;close kernel function int byte 80h ; copy authorization proto name and data ; to connect request data packet mov esi, lib_buf + 3 ; offset of host name length movzx eax, byte [esi] ; host name length lea esi, [esi + eax + 2] ; skip host name movzx eax, byte [esi] ; length lea esi, [esi + eax + 2] ; skip it movzx ecx, byte [esi] ; this ought to be auth name length mov [conn_request.proto_str_len], cx inc esi mov edi, conn_request.proto_str rep movsb inc esi add edi,byte 3 ; round up for "pad" and edi,byte -4 movzx ecx, byte [esi] ; length of auth data mov [conn_request.proto_data_len], cx inc esi rep movsb sub edi, conn_request add edi,byte 3 and edi,byte -4 no_auth: mov [conn_request_length], edi xor eax,eax ;set good return gx_exit: or eax,eax ;set result flag ret ;---------------------- [section .data] socket_create_blk: ;create a socket data dd 1 ;PF_UNIX dd 1 ;SOCK_STREAM dd 0 ; socket_connect_blk: socket_fd2: dd 0 dd socket_path dd socket_path_len socket_path: dw 1 ; 1: AF_UNIX, AF_LOCAL (/usr/include/linux/socket.h) db "/tmp/.X11-unix/X" display_number: db "0" ;from display variable socket_path_len equ $ - socket_path auth_file_name db '/.Xauthority', 0 auth_file_name_len equ $ - auth_file_name auth_path times 200 + 1 db 0 display_var: db 'DISPLAY',0 display_var_contents: times 8 db 0 ; Connection Setup info align 4, db 0 conn_request: .endian db 6Ch ; LSB first .unused db 0 .major dw 11 .minor dw 0 ; major/minor version .proto_str_len dw 0 ; protocol_string_len .proto_data_len dw 0 ; fill in at runtime .unused2 dw 0 conn_request_len equ $ - conn_request .proto_str times 256 db 0 ; enough for anybody conn_request_length dd 0 local_fd dd 0 [section .text] ;---------------------- ;input: ebx= fd ;output: eax = result & sign bit set read_fd: mov [local_fd],ebx ;save fd mov eax,3 ;kernel read function mov ecx, lib_buf mov edx, 700 ;lib_buf_len int byte 80h ;read file jns rf_exit ;jmp if good read cmp eax,-11 jne rf_exit mov eax,[local_fd] mov ebx,-1 ;wait forever call poll_socket js rf_exit ;exit if error mov ebx,[local_fd] jmp short read_fd rf_exit: or eax,eax ret [section .text] ;---------------------- ; wait_event - poll fd input/output status ; INPUTS ; esi = array of dword fd's terminated by -1 ; eax = max wait time(usec), or zero to wait forever, and ; minus 1 for immediate return of status ; OUTPUT ; eax = 0 child has died? signal? ; = negative, then error/signal active(-4) ; = positive number of events pending ; ecx = ptr to array of bits set for each fd with ; pending actions, bit 1 represents stdin (fd 0). ; fd's must be in numerical order (small to large). ; * --------------------------------------------------- wait_event: push eax ;save wait forever flag mov ecx,20 mov edi,event_buf ;temp buffer for array call blk_clear call bit_set_list ;set bits mov ebx,[esi-8] ;get value of highest fd inc ebx ;ebx = highest fd +1 mov ecx,edi ;ecx = bit array ptr (input) xor edx,edx ;edx = 0 (no write bit array) xor esi,esi ;esi = 0 (no exceptfds bit array) pop edi ;get wait flag or edi,edi js we_fast_rtn ;jmp if immediate return jz we_forever ;edi = number of microseconds to wait mov [_time+4],edi ;set microseconds we_fast_rtn: mov edi,_time ;assume stored time is zero we_forever: mov eax,142 int 80h ret [section .data] _time: dd 0 ;zero seconds, returns status immediately dd 0 ;microseconds to wait event_buf: dd 0,0,0,0,0,0,0 ;bits representing fd numbers to poll, stdin=bit#1 [section .text] ;---------------------- ; blk_clear - clear array of bytes ; INPUTS ; ecx = size of array (byte count) ; edi = array pointer ; the CLD flag is set ; OUTPUT ; ecx = 0 ; edi = unchanged ; * --------------------------------------------------- blk_clear: push eax push edi xor eax,eax rep stosb pop edi pop eax ret ;---------------------- ;bit_set_list - set bits in array ; INPUTS ; esi = pointer to list of dword bit values ; 0 = bit 1 or 00000001h ; -1 = end of list ; values in increasing order ; edi = array pointer ; OUTPUT ; bits set in array ; esi moved to end of list, beyond -1 entry ; * --------------------------------------------------- bit_set_list: push edx push eax sa_loop: lodsd ;get bit value or eax,eax js sa_exit ;exit if done (end of list) mov edx,eax shr edx,5 and eax,1fh lea edx,[edx*4 + edi] bts [edx],eax jmp short sa_loop ;loop sa_exit: pop eax pop edx ret ;------------------------------ ; bit_test - test array of bits ; INPUTS ; eax = bit number ; (0=bit 1) or 00000001h ; edi = bit array pointer ; OUTPUT ; carry = bit set ; no-carry = bit cleared ; registers unchanged ; * --------------------------------------------------- bit_test: push edx mov edx,eax shr edx,5 lea edx,[edx*4 + edi] and eax,1fh bt dword [edx],eax ;check bit pop edx ret ;------------------------------ ; env_home - search the environment for $HOME ; INPUTS ; ebx = ptr to list of env pointers ; edi = buffer to store $HOME contents ; OUTPUT ; edi = ptr to zero at end of $HOME string ; * ---------------------------------------------- env_home: or ebx,ebx jz fh_50 ;jmp if home path not found mov esi,[ebx] or esi,esi jz fh_50 ;jmp if home path not found cmp dword [esi],'HOME' jne fh_12 ;jmp if not found yet cmp byte [esi + 4],'=' je fh_20 ;jmp if HOME found fh_12: add ebx,byte 4 jmp short env_home ;loop back and keep looking fh_20: add esi, 5 ;move to start of home path ; ; assume edi points at execve_buf ; call str_move fh_50: ret [section .data] lib_buf times 700 db 0 enviro_ptrs dd 0 ;from entry stack [section .text] ;---------------------------------- ; str_move - move asciiz string ; INPUTS ; esi = input string ptr (asciiz) ; edi = destination ptr ; OUTPUT ; edi points at zero (end of moved asciiz string) ; * ---------------------------------------------- str_move: cld ms_loop: lodsb stosb or al,al jnz ms_loop ;loop till done dec edi ret ;------------------- poll_socket ---------------------------------- ; poll_socket - check if key avail. ; INPUTS ; eax = fd (file descriptor) ; edx = milliscond wait count, ; -1=forever, 0=immediate return ; OUTPUT ; flags set "js" - error (check before jnz) ; "jz" - no event waiting, or timeout ; "jnz" - event ready ; * ---------------------------------------------- poll_socket: mov [poll_tbl],eax ;save fd mov eax,168 ;poll mov ebx,poll_tbl mov ecx,1 ;one structure at poll_tbl int 80h or eax,eax js poll_exit jz poll_exit test byte [poll_data],1 poll_exit: ret [section .data] poll_tbl dd 0 ;stdin dw 1 ;events of interest,data to read poll_data dw -1 ;return from poll [section .text] ;--------------------------------------- ; find_env_variable - search environment for variable name ; INPUTS ; [enviro_ptrs] - setup by env_stack ; ecx = ptr to variable name (asciiz) ; edx = storage point for variable contents ; OUTPUT ; data stored at edx, if edi is preloaded with ; a zero it can be checked to see if variable found ; edi - if success, edi points to end of variable stored ; * ---------------------------------------------- find_env_variable: mov ebx,[enviro_ptrs] fev_10: or ebx,ebx jz fev_50 mov edi,[ebx] or edi,edi jz near fev_50 mov esi,ecx ;get input variable name ptr call str_match jne fev_12 cmp [edi],byte '=' je fev_20 ;jmp if var= found fev_12: add ebx,byte 4 jmp short fev_10 ; ; match found, store it ; fev_20: inc edi ;move past "=" mov esi,edi mov edi,edx call str_move fev_50: ret ;-------------------------------------------------- ; str_match - compare asciiz string to buffer data, use case ; INPUTS ; esi = string1 (asciiz string) ; edi = string2 buffer ; assumes direction flag set to -cld- forward state ; OUTPUT ; flags set for je or jne ; esi & edi point at end of strings if match ; * ---------------------------------------------- str_match: push ecx call strlen1 ;find length of string1 repe cmpsb pop ecx ret ;---------------------------------------------------- ; strlen1 - get length of esi string ; INPUTS ; esi = pointer to asciiz string ; OUTPUT ; ecx = length of string ; all registers restored except for ecx ; * ---------------------------------------------- strlen1: push eax push edi cld mov edi,esi sub al,al ;set al=0 mov ecx,-1 repnz scasb not ecx dec ecx pop edi pop eax ret ;--------------------- ; x_send_request - send request to x server ; INPUTS ; ecx = packet ptr ; edx = packet length, negative packet length ; indicates a reply is expected. Length ; is can be set negative with "neg edx" ; OUTPUT: ; flag set (jns) if success ; flag set (js) if err, eax=error code ; [sequence] - sequence number of packet sent ; ; NOTES ; If socket_fd is zero this functions connects to ; x socket. If the packet length is negative a ; reply is expected and the sequence# is stored ; for retrevial by x_read_socket ; * ---------------------------------------------- x_send_request: x_send: mov ebx,[socket_fd] ;get socket fd or ebx,ebx jnz x_send2 ;jmp if connected push ecx push edx call x_connect ;connect to the server pop edx pop ecx js x_send_exit ;exit if error x_send2: inc dword [sequence] or edx,edx ;check if reply expected jns x_send3 ;jmp if no reply expected neg edx ;make packet length positive push edx push ecx mov edx,list_block mov esi,sequence call list_put_at_end pop ecx pop edx x_send3: push ecx push edx mov ebx,[socket_fd] call poll_out pop edx pop ecx ;append to buffer cmp edx,[x_buf_avail] jb queue_packet call x_flush ;flush before queue_packet: sub [x_buf_avail],edx mov esi,ecx mov edi,[x_buf_ptr] mov ecx,edx rep movsb mov [x_buf_ptr],edi xor eax,eax ;set exit flag ret ;--------------------- ;>1 server ; x_flush - send queued events to x server ; the x_send_request function buffers all output ; and sends if buffer becomes full or the program ; waits for input. This function flushes (sends) ; the buffer to the x server. ; INPUTS ; none ; OUTPUT: ; sign flag set if error and eax modified ; all other registers preserved. ; * ---------------------------------------------- x_flush: pusha mov ecx,x_buf mov edx,[x_buf_ptr] sub edx,ecx or edx,edx jz x_send_exit ;exit if buffer empty mov eax,4 ; __NR_write mov ebx, [socket_fd] int byte 80h cmp eax,-11 ;is server busy jne x_send4 ;jmp if success or error jmp short x_flush x_send4: mov [x_buf_ptr],dword x_buf mov [x_buf_avail],dword x_buf_size x_send_exit: mov [save_eax],eax popa mov eax,[save_eax] or eax,eax ret ;--------------------- poll_out: mov [polled_fd],ebx mov eax,168 mov ebx,poll_block mov ecx,1 ;one fd mov edx,-1 ;timeout int byte 80h test [poll_response], byte 4 ret ;--------------------- [section .data] poll_block: polled_fd: dd 0 dw 4 ;write now will not block poll_response: dw -1 sequence: dd 0 ;socket sequence# ;sequence# database control block list_block: dd buffer ;top of buffer dd buffer_end ;end of buffer dd 2 ;each entry x bytes long dd buffer ;first entry ptr dd buffer ;last entry ptr ;storage for sequence# expecting a reply buffer: times 60 dw 0 buffer_end: x_buf_size equ 1024 x_buf_ptr dd x_buf x_buf_avail dd x_buf_size x_buf times x_buf_size db 0 save_eax dd 0 ;------------------------------------------------------------- [section .text] ;---------------- list_put_at_end.asm ------------------- struc list .list_buf_top_ptr resd 1 .list_buf_end_ptr resd 1 .list_entry_size resd 1 .list_start_ptr resd 1 .list_tail_ptr resd 1 endstruc ;--------------------- ;>1 list ; list_put_at_end - add entry to end of list ; INPUTS ; edx = list control block ; struc list ; .list_buf_top_ptr resd 1 ; .list_buf_end_ptr resd 1 ; .list_entry_size resd 1 ; .list_start_ptr resd 1 ; .list_tail_ptr resd 1 ; endstruc ; ; Initially the control block for a empty ; list could be set as follows by caller: ; dd buffer ;top of buffer ; dd buffer_end ;end of buffer ; dd x ;each entry x bytes long ; dd buffer ;first entry ptr ; dd buffer ;last entry ptr ; ; esi = ptr to data of length ; liss_entry_size ; ; OUTPUT: ; flag set (jns) if success ; esi = will be advanced by size of entry ; edx,ebp unchanged ; flag set (js) if no room ; esi,edx,ebp unchanged ; ; if data wraps in buffer, the global ; [last_buf_put_at_end_adr] will be set ; NOTES ; A full list will have a one entry gap ; between the list_start_ptr and list_tail_ptr. ; The list pointers cycle around the buffer ; and entries can be removed from start or ; end of list. ; * ---------------------------------------------- list_put_at_end: call next_put_at_end ;eax=next stuff edi=current stuff cmp eax,[edx+list.list_start_ptr] ;room for another entry jne have_room mov eax, -1 jmp short list_put_at_end_exit have_room: mov [edx+list.list_tail_ptr],eax mov ecx,[edx+list.list_entry_size] rep movsb list_put_at_end_exit: or eax,eax ret ;--------------------- ; compute next put ptr ;input: edx = control block ; esi,ebp not available ;output: eax=next ptr ptr ; edi=current stuff ptr ; next_put_at_end: mov eax,[edx+list.list_tail_ptr] ;get ptr to last entry mov edi,eax ;save stuff ptr add eax,[edx+list.list_entry_size] ;move ptr forward cmp eax,[edx+list.list_buf_end_ptr] ;beyond end of buffer jb np_exit ;jmp if ok mov eax,[edx+list.list_buf_top_ptr] ;restart put at top of buffer np_exit: ret ;--------------------- ;--------------------- [section .text] ;--------- x_wait_reply ------------- ;struc XAnyEvent ;.type resd 1 ; ;.serial resd 1 ; # of last request processed by server ;.send_event resd 1 ; true if this came from a SendEvent request ;.display resd 1 ; Display the event was read from ;.window resd 1 ; window on which event was requested in event mask ;endstruc struc XKeyEvent .type resd 1; of event .serial resd 1; # of last request processed by server .send_event resd 1; true if this came from a SendEvent request .display resd 1; Display the event was read from .window resd 1; "event" window it is reported relative to .root resd 1; root window that the event occurred on .subwindow resd 1; child window .time resd 1; milliseconds .x resd 1 .y resd 1; pointer x, y coordinates in event window .x_root resd 1 .y_root resd 1; coordinates relative to root .state resd 1; key or button mask .keycode resd 1; detail .same_screen resd 1; same screen flag endstruc struc XButtonEvent .type resd 1; of event .serial resd 1; # of last request processed by server .send_event resd 1; true if this came from a SendEvent request .display resd 1; Display the event was read from .window resd 1; "event" window it is reported relative to .root resd 1; root window that the event occurred on .subwindow resd 1; child window .time resd 1; milliseconds .x resd 1 .y resd 1; pointer x, y coordinates in event window .x_root resd 1 .y_root resd 1; coordinates relative to root .state resd 1; key or button mask .button resd 1; detail .same_screen resd 1; same screen flag endstruc ;--------------------- ;>1 server ; x_wait_reply - wait for xx milliseconds for reply ; INPUTS ; none ; OUTPUT: ; failure - eax=negative error code ; flags set for js ; -1=reply read error (buffer error) ; -2=error packet in buffer ; -3=reply out of sequence ; -4=timeout expired or servers in tryagain loop ; -5=unexpected event while waiting for reply. ; -6=socket dead ; -x=all other errors are from kernel ; success - eax = number of bytes read from server ; ecx = pointer to reply buffer info. ; (see file event_info.inc for buffer data) ; NOTES ; source file: x_wait_reply.asm ; If replies are not pending this function will ; return an error of -1 ; If reply does not occur within 2 seconds a timeout ; error will be returned ; * ---------------------------------------------- x_wait_reply: mov edx,list_block call list_check_front js wr_exit ;exit if no reply pending mov eax,2000 ;wait for 2 seconds max mov ecx,lib_buf ;buffer mov edx,700 ;buffer length call x_read_socket wr_exit: ret ;--------------------- ; list_check_front - check list top, do not remove entry ; INPUTS ; edx = list control block ; struc list ; .list_buf_top_ptr resd 1 ; .list_buf_end_ptr resd 1 ; .list_entry_size resd 1 ; .list_start_ptr resd 1 ; .list_tail_ptr resd 1 ; endstruc ; ; OUTPUT: ; flag set (jns) if success ; esi = ptr to data ; eax = 0 ; edx,ebp unchanged ; flag set (js) if no data on list ; eax=-1 ; edx,ebp unchanged ; ; NOTES ; A full list will have a one entry gap ; between the list_start_ptr and list_tail_ptr. ; The list pointers cycle around the buffer ; and entries can be removed from start or ; end of list. ; * ---------------------------------------------- list_check_front: mov esi,[edx+list.list_start_ptr] cmp esi,[edx+list.list_tail_ptr] jne have_data mov eax,-1 jmp short list_check_front_exit have_data: xor eax,eax ;set success flag list_check_front_exit: or eax,eax ret ;--------------------- ; x_read_socket - read x server socket ; INPUTS ; eax = wait length in milliseconds ; 0=no wait,immediate check for data ; -1=forever ; ecx = buffer for data ; edx = buffer length ; ; note: the sequence number queue set ; by x_send_request may be used. ; ; OUTPUT: ; success state ; flag set (jns) if success - expected reply or event ; eax = number of bytes in buffer ; ecx = reply buffer ptr ; fail state ; flags - set for js ; eax = negative error ; -1=reply read error (buffer error) ; -2=error packet in buffer ; -3=reply out of sequence ; -4=timeout expired or servers in tryagain loop ; -5=unexpected event while waiting for reply. ; -6=socket died ; -x=all other errors are from kernel ; ; NOTES ; see file event_info.inc for reply codes ; This is the low level function used by all other ; x server packet read functions. See also, ; x_wait_event ; x_wait_reply ; x_wait_big_reply ; window_event_decode ; * ---------------------------------------------- x_read_socket: mov [poll_timeout],eax mov [pkt_buf],ecx mov [pkt_buf_length],edx mov [timeout],byte 80 ; call x_flush jmp short data_waiting ;; x_read_socket3: mov eax,[socket_fd] mov edx,[poll_timeout] ; call poll_socket jnz data_waiting mov eax,-4 ; jmp x_read_socket_exit data_waiting: mov ebx, [socket_fd] mov eax,3 ; __NR_read mov ecx,[pkt_buf] mov edx,32 ;standard read size int byte 80h cmp eax,-11 ;try again? jne x_read_socket4 ;jmp if possible good read dec dword [timeout] mov eax,[timeout] or eax,eax jnz x_read_socket3 ;loop back = retry mov eax,-1 jmp short x_read_socket_exit ;check if good read x_read_socket4: or eax,eax js x_read_socket_exit ;exit if error jnz x_read_socket4a ;jmp if socket data read mov eax,-6 ;eax=0, socket dead, exit jmp short x_read_socket_exit x_read_socket4a: cmp byte [ecx],0 ;error packet? jne x_read_socket5 ;jmp if not error packet ;; note; do we need to pop possible reply packet here? mov eax,-2 ;get code = error packet jmp short x_read_socket_exit ;check if waiting for reply, eax=read cnt, ecx=buf ptr x_read_socket5: mov edx,list_block push eax call list_check_front ;point at seq# on top of list pop eax ;restore read count js x_read_socket_exit ;exit if not reply (expected event?) ;verify this is a reply cmp byte [ecx],1 ;reply packet jne x_read_socket5a ;jmp if not replay ;this should be reply event,check seq#, esi=event ptr mov bx,[ecx+2] ;get seq# from reply cmp bx,[esi] ;check against list je x_read_socket7 ;jmp if sequence# match, expected pkt ;this is unexpected packet,check if event or reply x_read_socket5a: mov eax,-5 jmp short x_read_socket_exit x_read_socket6: mov eax,-3 ;reply out of sequence jmp short x_read_socket_exit ;we have expected reply,pop list, read tail if more data x_read_socket7: push eax call list_get_from_front pop eax ;restore read length mov edx,[ecx+4] ;get remaining pkt data count or edx,edx jz x_read_socket_exit ;jmp if all pkt data read add ecx,32 ;advance buffer ptr shl edx,2 ;convert to byte count ;read rest of packet mov ebx, [socket_fd] mov eax,3 ; __NR_read int byte 80h or eax,eax js x_read_socket_exit add eax,32 ;restore correct packet length sub ecx,32 ;restore buffer start x_read_socket_exit: or eax,eax ret ;-------------------------- [section .data] pkt_buf dd 0 pkt_buf_length dd 0 poll_timeout dd 0 timeout: dd 0 ;used if server says try again later [section .text] ;--------------------- ; list_get_from_front - return entry from top of list ; INPUTS ; edx = list control block ; struc list ; .list_buf_top_ptr resd 1 ; .list_buf_end_ptr resd 1 ; .list_entry_size resd 1 ; .list_start_ptr resd 1 ; .list_tail_ptr resd 1 ; endstruc ; ; OUTPUT: ; flag set (jns) if success ; esi = ptr to data ; edx,ebp unchanged ; flag set (js) if no data on list ; edx,ebp unchanged ; ; NOTES ; source file: list_get_from_front.asm ; A full list will have a one entry gap ; between the list_start_ptr and list_tail_ptr. ; The list pointers cycle around the buffer ; and entries can be removed from start or ; end of list. ; * ---------------------------------------------- list_get_from_front: mov esi,[edx+list.list_start_ptr] cmp esi,[edx+list.list_tail_ptr] jne have_data2 mov eax,-1 jmp short list_get_from_front_exit have_data2: ;move pointer forward to next entry mov eax,esi add eax,[edx+list.list_entry_size] cmp eax,[edx+list.list_buf_end_ptr] jb update_start_ptr ;jmp if not at end mov eax,[edx+list.list_buf_top_ptr] ;start at top update_start_ptr: mov [edx+list.list_start_ptr],eax xor eax,eax ;set success flag list_get_from_front_exit: or eax,eax ret ;---------------------------------------------------- ; crt_write - display block of data ; INPUTS ; ecx = ptr to data ; edx = length of block ; OUTPUT ; uses current color, see crt_set_color, crt_clear ; * --------------------------------------------------- crt_write: mov eax, 0x4 ; system call 0x4 (write) mov ebx,1 ; stdout ; file desc. is stdout int byte 0x80 ret ;-code end- |