Statistics

Members: 1925
News: 293
Web Links: 1
Visitors: 3826361

Who's Online

Damn Vulnerable LinuxDamn Vulnerable Linux (DVL) is a Linux-based (modified Damn Small Linux) tool for IT-Security & IT-Anti- Security and Attack & Defense. [CLICK HERE FOR MORE INFOS! ]

Featured Conference Video

T16-Recon2006-Joe_Stewart-OllyBonE.gif OllyBone - Semi-Automatic Unpacking on IA-32. View the conference video here!
Home arrow Articles - Programming arrow Assembly arrow X-Windows in Assembly Language: Part II
X-Windows in Assembly Language: Part II
User Rating: / 0
PoorBest 
Written by Mammon   


OK, let's face it: you've seen the tedium of XLib, one has to use widgets in order to get any programming done in XWindows. 'But this is assembly langauge', the masochist might point out. 'Aren't widgets a little Visual-Basicy?'

Not in the slightest. A widget is simply a C++ class exported for use --much like the windows API functions, only a little more object oriented...maybe a good comparison would be MFC or VCL. Xt, or 'X toolkit Intrinsics', is the interface that widget sets [such as Athena, Qt or GTK] use to interface with XLib. The Xt include files are in /usr/X11R6/include/X11, its libraries are in /usr/X11R6/lib, and its exported functions are all prefixed with "Xt".

 

 

For the following examples I will be using the Atehna widget set, which is supplied with XFree86. The include files for Athena are in /usr/X11R6/include/Xaw and the libraries are in /usr/X11R6/lib.

A barebones Xt/Athena app in C would run as follows: //====================================================================-xthell.c

#include
#include
#include

void Quit(w, client_data, call_data) //CallBack function Widget w;
XtPointer client_data, call_data;
{

exit(0);
}

main(argc,argv)
int argc;
char **argv;
{

XtAppContext app_context;
Widget ShellWidge, ButtnWidge;
ShellWidge = XtVaAppInitialize( &app_context, "toplevel", NULL, 0, &argc, \

argv, NULL, NULL);
ButtnWidge = XtVaCreateManagedWidget("hellbutton", commandWidgetClass, \

ShellWidge, NULL);
XtAddCallback(ButtnWidge, XtNcallback, Quit, 0); XtRealizeWidget(ShellWidge);

XtAppMainLoop(app_context);
}
// compile with cc -o xthell xthello.c -lXmu -lXaw -lXt -lX11 -L/usr/X11R6/lib //=========================================================================-EOF

Pretty ugly, eh? This boils down to the following steps:

  1. Create the top-level 'Canvas' widget [the window] ShellWidge = XtVaAppInitialize( &app_context, "toplevel", ..... )
  2. Create the button widget ButtnWidge = XtVaCreateManagedWidget("hellbutton", ..... )
  3. Register a callback for the button XtAddCallback(ButtnWidge, XtNcallback, Quit, 0);
  4. Show the top-level widget XtRealizeWidget(ShellWidge);
  5. Transfer control to the Xt message loop XtAppMainLoop(app_context); The most interesting thing about Xt programming is in fact the callbacks. Instead of writing a message processing loop, you register a callback function for each widget and then pass control to Xt, which processes the messages for you and dispatches each message to the appropriate callback function. The call- back receives a pointer to the widget that sent the message [the same argument as passed to XtAddCallback], a client_data pointer [the last argument passed to XtAddCallback, used to pass data from the main routine to the callback], and a call_data pointer, which contains information from the message [such as cursor or scrollbar position].

The calls themselves are pretty straightforward: XtVaAppInitialize initializes [sic] the X app and takes as its arguments a pointer to an XtAppContext structure, the class name of the application, application-specific command line options {args 3 and 4], argc, argv, a default resource-settings file, and a NULL to terminate the arguments list [the XtVaAppInitialize function actually takes a number of different parameters]; it returns a handle to the 'canvas' or 'top-level' widget, on which all other widgets will be painted.

XtVaCreateManagedWidget is used to create any of the Xt widgets [Athena, GTK, etc], and takes as its parameters the instance name, the widget class, the parent widget, and a NULL to terminate the arguments list; it returns a pointer to the created widget.

XtAddCallback is used to register a callback function with a specific widget; it takes as its parameters a pointer to the Widget, the callback type, the function being registered, and a pointer to client_data which will be passed to the callback.

XtRealizeWidget is simply used like ShowWindow in Windows; it takes a single parameter which is the widget to 'show'; it displays that widget and its children.

XtAppMainLoop takes the current application context [which was filled with the XtVaAppInitialize call] and turns control over to the Xt message processing loop. Note that the program does not have to return; in this example, the exit call is placed in the callback function.

Here is the same application written for NASM: ;===================================================================-xthell.asm BITS 32
GLOBAL main
GLOBAL bail
EXTERN XtVaAppInitialize
EXTERN XtVaCreateManagedWidget
EXTERN XtAddCallback
EXTERN XtRealizeWidget
EXTERN XtAppMainLoop
EXTERN commandWidgetClass
EXTERN exit

SECTION .data

AppContext      DD      0
ShellWidge      DD      0
ButtnWidge      DD      0
ARGC    times 128       DB      0
ClassName   DB  "toplevel",0
ButtnName       DB      "hellbutton",0

XtNcallback DB "callback",0 ;XtNcallback

SECTION .text
bail:

        pop eax      ; Xt_Pointer call_data
pop ebx      ; Xt_Pointer client_data
pop ecx      ; Xt_Pointer widget
push dword 0
call exit

;-------------------------- main
main:

         mov eax, esp
push dword 0               ;Number of Args
push dword 0               ;Args
push dword 0               ;Fallback Resources
push dword 0               ;argv
push dword ARGC            ;&argc
push dword 0               ;Number of Options
push dword 0               ;Options Array
push dword ClassName           ;Class Name (String)            
push dword AppContext          ;Application Context (Ptr)
call XtVaAppInitialize
add  esp, 36
mov  [ShellWidge], eax
push dword 0
push eax                        ;Button parent (ShellWidge)
push dword [commandWidgetClass] ;Button widget type
push dword ButtnName            ;Button class name
call XtVaCreateManagedWidget
add  esp, 16
mov  [ButtnWidge], eax
push dword 0                    ; client_data
push dword bail                 ;CallBack function
push dword XtNcallback          ; callback type
push eax                        ;CallBack widget (ButtonWidge)
call XtAddCallback
add  esp, 16
push dword [ShellWidge]         ;Widget Handle
call XtRealizeWidget
add  esp, 4
push dword [AppContext]
call XtAppMainLoop
add esp, 4
ret

;==========================================================================-EOF This can be compiled with the following commands:

nasm -f elf xthell.asm
gcc -o xthell xthell.o -lXaw -lXt -lX11 -L/usr/X11R6/lib

Most of the operation is the same as the C file; naturally you must push dword 0's instead of NULLs...and do not forget to push the arguments in reverse order and to clean up the stack afterwards; this is C after all and not stdcall is used in Windows.

You will have to study up on Athena to learn what the names of the various widgets are ... I found it helpful to use

grep extern /usr/X11R6/include/Xaw/* for a general overview. Note that the class names are strings in assembly; also each of the various 'handles' [widgets, contexts, etc] is simply defined with a DD 0 -- your generic 32-bit variable. The Callback type turned out to be a string defined in the Xt header files; I simply recreated it above.

Another interesting gemis the need to call 'exit' rather than simply using a 'ret' as you would in console mode; the latter causes segmentation faults, most likely due to the XtAppMainLoop call. In addition you must provide a pointer to ARGC whether you check the command line or not; hence the 'ARGC: DB 128'.

In case you didn't notice, the Xt asm example is huge and clunky, with a lot of not-so-obvious variable definitions. Having included a lengthy introduction to NASM macros in this issue, I took the opportunity to create an xt.mac file which will take some of the burden off of experimenting with small Xt apps. The InitXt and RegisterCallback macros probably are not ready for prime-time just yet, but they will do for testing purposes.

;=======================================================================-xt.mac %macro CLASS 2
%1: DB %2,0
%endmacro
%macro WDGTPTR 1
%1: DD 0
%endmacro
%macro CONTEXT 1
%1: DD 0
%endmacro
%macro CHARSTR 2
%1: DB %2,0
%endmacro
%define WIDGET EXTERN
%define XLibAPI EXTERN
%define XtAPI EXTERN
%define PUBLIC GLOBAL
%define NULL dword 0
%define TERM_VARARGS dword 0
%macro InitXt 2
SECTION .data
CONTEXT AppContext
CLASS XtShell, "XtShell"
SECTION .text
EXTERN XtVaAppInitialize

         push dword 0           ;Number of Args
push dword 0           ;Args
push dword 0           ;Fallback Resources
push dword 0           ;argv
push dword %2          ;&argc
push dword 0           ;Number of Options
push dword 0           ;Options Array
push dword XtShell             ;Class Name (String)            
push dword AppContext          ;Application Context (Ptr)
call XtVaAppInitialize
add  esp, 36
mov  [%1], eax

%endmacro
%macro XtMsgLoop 0
EXTERN XtAppMainLoop

        push dword [AppContext]
call XtAppMainLoop
add esp, 4

%endmacro
%macro RegisterCallback 1
SECTION .data
CBType: DB "callback",0
SECTION .code

        push NULL                       ;
push dword %1                   ;CallBack function
push dword CBType               ;
push eax                        ;CallBack parent (ButtonWidge)
call XtAddCallback
add  esp, 16

%endmacro
%macro CALLBACK 1
SECTION .data

Call_Data_%1:   DD      0
Client_Data_%1: DD      0
Widget_%1:      DD      0

GLOBAL %1
SECTION .text
%1:

        pop eax
mov [Call_Data_%1], eax
pop ebx
mov [Client_Data_%1], ebx
pop ecx
mov [Widget_%1], ecx

%endmacro
%define ENDCALLBACK nop
%macro ENTRYPOINT 1
GLOBAL %1
%1:
%endmacro
;==========================================================================-EOF Most of the macro file should be readily apparent if you are familiar with the NASM macro facility. I did take the opportunity to clean up the callback function, so that the parameters to the callback are saved in variables, but for the most part it does the same as the equivalent code in the preceding asm example.

Now the xthell.asm sample will look as follows:

;===================================================================-xthell.asm BITS 32
%INCLUDE "xt.mac"
;========================================================XTRN===== XtAPI XtVaCreateManagedWidget
XtAPI XtAddCallback
XtAPI XtRealizeWidget
WIDGET commandWidgetClass
EXTERN exit

;========================================================DATA===== SECTION .data
;------------
WDGTPTR ptrShell
WDGTPTR ptrButton
CLASS XHELL, "XHell"
CLASS HellButton, "HellButton"
CallbackType DB "callback",0 ;XtNcallback ARGC times 128 DB 0 ;========================================================CODE===== SECTION .text
;------------
CALLBACK bail

        push dword 0
call exit

ENDCALLBACK

ENTRYPOINT main

InitXt ptrShell, ARGC

        push TERM_VARARGS
push eax                        ;Button parent (ShellWidge)
push dword [commandWidgetClass] ;Button widget type
push dword HellButton           ;Button class name
call XtVaCreateManagedWidget
add  esp, 16
mov  [ptrButton], eax
RegisterCallback bail
push dword [ptrShell]           ;Widget Handle
call XtRealizeWidget
add  esp, 4
XtMsgLoop
ret

;==========================================================================-EOF Much prettier and hey, only twice as long as the C version! ;)

Next issue I will dwell on Xt/Athena a little longer and come up with some more practical methods of automating the coding process.