Calling libraries from assembler. - Linux
This is a discussion on Calling libraries from assembler. - Linux ; Hello!
I have tried how simple it is to use
system calls in Linux from assembler.
Setting parameters in the registers
eax/edx and then "int 0x80".
I would like to know it there
is a similar, easy way of calling
...
-
Calling libraries from assembler.
Hello!
I have tried how simple it is to use
system calls in Linux from assembler.
Setting parameters in the registers
eax/edx and then "int 0x80".
I would like to know it there
is a similar, easy way of calling
other libraries (specially X windows).
It should be as simple as giving
the function name in ASCII ! 
Thanks,
Herman Samso
-
Re: Calling libraries from assembler.
>I have tried how simple it is to use
>system calls in Linux from assembler.
>Setting parameters in the registers
>eax/edx and then "int 0x80".
You are not calling a library. You are calling the kernel.
There's a difference.
>I would like to know it there
>is a similar, easy way of calling
>other libraries (specially X windows).
>
>It should be as simple as giving
>the function name in ASCII ! 
Look at how the C compiler calls C functions. Write a simple
function that does some calls, gcc -S foo.c, and examine foo.s .
Generally, you push a bunch of arguments on to the stack, use a
call instruction to call the function, and adjust the stack to
remove the stuff you pushed on. You need to make the target symbol
an external symbol (e.g. .globl). This should work for both
static-linked libraries and dynamic-linked libraries, but not
dlopen()ed libraries.
And no, you don't use the function name in ASCII, and you can't
use the above method to call a variable-named function based on
an ASCII string.
For example, call.c:
int a()
{
foo(1, 2, 3, 4);
bar(4, 3, 2, 1);
}
Compiles into this (this is on FreeBSD, not Linux, but I believe
the linkages are essentially the same):
.file "call.c"
.text
.p2align 2,,3
...globl a
.type a, @function
a:
pushl %ebp
movl %esp, %ebp
subl $8, %esp
pushl $4
pushl $3
pushl $2
pushl $1
call foo
addl $16, %esp
pushl $1
pushl $2
pushl $3
pushl $4
call bar
addl $16, %esp
leave
ret
.size a, .-a
.ident "GCC: (GNU) 3.4.6 [FreeBSD] 20060305"
-
Re: Calling libraries from assembler.
SoLo2 wrote:
> Hello!
>
> I have tried how simple it is to use
> system calls in Linux from assembler.
> Setting parameters in the registers
> eax/edx and then "int 0x80".
>
> I would like to know it there
> is a similar, easy way of calling
> other libraries (specially X windows).
I don't know how "similar" you'd call it, or "easy"... but yes, we
certainly can do that. At some point, there isn't much "advantage" to
using asm...
Might be better to start with a simpler "just call printf" example, but
since you ask about X, I'll append a simple "hello X".
> It should be as simple as giving
> the function name in ASCII ! 
Well... it won't work in Egyptian hieroglyphics (unless you've got an
Egyptian assembler)... I have seen stuff like:
button db "button", 0
.... mostly in "helper" libraries, not in Xlib itself. I don't know when
or why we have to do that. Mostly it's just "extern XFoo"...
This example links directly with ld. It strikes me that it might be
"dangerous" to be using C library code, without linking in the C startup
code. It "seems to work". I haven't had any trouble with it... (we *do*
need to tell ld which interpreter/dynamic linker to use - ld gets it
wrong by default! gcc knows...) Replace "_start" with "main", if you
want to do it that way...
I have other examples... including accessing Xwindows *without*
libraries - just using the int 80h interface - and even examples that
avoid using ld - creating a "ready to run" executable using Nasm's "-f
bin" mode. How "raw" would you like to get? 
I'm replying from comp.lang.asm.x86 - I doubt if these other groups are
interested in doing it in assembly language (or are they???). Should
probably trim followups, at some point. There is also interest in this
subject on the news:alt.lang.asm newsgroup...
Best,
Frank
; rudimentary "hello world" for Xwindows
; nasm -f elf -O999 x1.asm
; add the "-g" switch for debugging info - good luck!
;
; sorry 'bout this one...
; ld -o x1 x1.o -I/lib/ld-linux.so.2 -L/usr/X11R6/lib -lX11
;
; if you want it small:
; strip -R .comment x1
;
; after all that, we still have to tell ld where the fun begins:
global _start
; inform Nasm that ld knows where to find this stuff (we hope!)
extern XOpenDisplay
extern XDefaultRootWindow
extern XCreateSimpleWindow
extern XNextEvent
extern XDestroyWindow
extern XCloseDisplay
extern XMapRaised
extern XSelectInput
extern XStoreName
extern XCreateGC
extern XFreeGC
extern XDrawImageString
extern XSetForeground
extern XSetBackground
; we'll be needing lots more of these...
KeyPressMask equ 1 ; mask for XSelectInput
KeyPress equ 2 ; the "type" of event (offset 0 in "glob of bytes")
ExposeMask equ 1 << 15
ExposeEvent equ 12
event_size equ 20h ; ??? max size of several different structs
;------------------------------------------
section .data
StringOpenFailed db "Can't Open X display!", 10
StringOpenFailed_len equ $ - StringOpenFailed
caption db 'A Window', 0
string db ' Greetings from X, Earthling! '
string_len equ $ - string
;-----------------------------------------
;-----------------------------------------
section .bss
Display resd 1
Window resd 1
GC resd 1
event resd event_size
;-------------------------------------
;-------------------------------------
section .text
_start: ; let the ritual begin.
; nop ; parking place for gdb
; open a connection to the server.
; pushing 0 uses the "DISPLAY" environment variable
; or defaults to local machine.
push 0
call XOpenDisplay
add esp, 4
or eax, eax
je OpenFailed
mov dword [Display], eax
push dword [Display]
call XDefaultRootWindow
add esp, 4
; error?
push 0 ; background colour
push 0 ; border colour
push 0 ; border width
push 300 ; height
push 400 ; width
push 50 ; top co-ord
push 50 ; left co-ord
push eax ; XDefaultRootWindow, from above
push dword [Display] ; display handle
call XCreateSimpleWindow
add esp, 36 ; C clean-up parameters stuff
or eax, eax
je CreateFailed
mov dword [Window], eax
; this is one Windows doesn't do. if we don't specify
; what events (messages) we want to receive, we don't get any.
push KeyPressMask | ExposeMask
; "or" this with other events to recv!
; don't forget to handle 'em!
push dword [Window]
push dword [Display]
call XSelectInput
add esp, 12
; error?
; give the baby a name
push caption
push dword [Window]
push dword [Display]
call XStoreName
add esp, 12
; error?
; make our window visible.
push dword [Window]
push dword [Display]
call XMapRaised
add esp, 8
; error?
push 0 ; values?
push 0 ; valuemask?
push dword [Window]
push dword [Display]
call XCreateGC
add esp, 16
;error?
mov dword [GC], eax
; Mmmm, looks like 16-bit color, 5-6-5, on my machine.
; Bet we can't count on it!
; push 65535 ; white
push 1111100000000000b ; red
push dword [GC]
push dword [Display]
call XSetForeground
add esp, 12
; error?
; push 0 ; black
push 0000011111100000b ; green
push dword [GC]
push dword [Display]
call XSetBackground
add esp, 12
; error?
Eventloop:
push event
push dword [Display]
call XNextEvent
add esp, 8
; error?
cmp dword [event], ExposeEvent
jnz not_expose
call drawscreen
jmp Eventloop
not_expose:
cmp dword [event], KeyPress
jne Eventloop
; exit gracefully if key pressed
push dword [GC]
push dword [Display]
call XFreeGC
add esp, 8
push dword [Window]
push dword [Display]
call XDestroyWindow
add esp, 8
CreateFailed:
push dword [Display]
call XCloseDisplay
add esp, 4
jmp Terminate
OpenFailed:
mov eax, 4 ; __NR_write
mov ebx, 2 ; stderr
mov ecx, StringOpenFailed ; buffer
mov edx, StringOpenFailed_len ; count
int 80h
Terminate:
mov eax, 1 ; function (sys_exit)
xor ebx, ebx ; exit code
int 80h ; make Linux system call
;-------------------------------------------
;-------------------------------------------
drawscreen:
push string_len
push string
push 140 ; y pos
push 155 ; x pos
push dword [GC]
push dword [Window]
push dword [Display]
call XDrawImageString
add esp, 28
; error?
ret
;---------------------------------------------
-
Re: Calling libraries from assembler.
SoLo2 wrote:
> I have tried how simple it is to use
> system calls in Linux from assembler.
> Setting parameters in the registers
> eax/edx and then "int 0x80".
>
> I would like to know it there
> is a similar, easy way of calling
> other libraries (specially X windows).
If you like the "int 80" interface, then there is
no need to use libraries for graphics in X Windows.
You need the kernel but you never need code in any
library. Here an example of a simple graphics demo
(for NASM). You will find a few more demos in
ftp://137.193.64.130/pub/assembler/xlinux.zip
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;
;; annie.mac:simple Linux/X graphics demo ;;
;; ;;
;; X code based on examples by Frank Kotler ;;
;; ;;
;; display a flying heart, press any key to exit ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;
; nasm -O99 -f bin -o annie annie.asm
%include "mac.inc" ; ftp://137.193.64.130/pub/assembler/xlinux.zip
;================================================= ==========================
seg 32
orig equ $08048000
code_addr equ orig
code_offset equ 0
section .text vstart=code_addr
;--------------------------- ELF header -----------------------------------
dc.l $464c457f,$00010101,0,0,$00030002,1,main,$34,0,0,$ 00200034,2,0
dc.l 1,code_offset,code_addr,code_addr,code_filez,code_ memsz,5,4096
dc.l 1,data_offset,data_addr,data_addr,data_filez,data_ memsz,6,4096
;--------------------------- code ------------------------------------------
main: move.l r7,[stack_ptr] ; save initial stack pointer
; ******************** get socket handle ***************************
moveq.l 0,-[sp] ; no protocol specified
moveq.l 1,-[sp] ; 1: SOCK_STREAM (/usr/include/linux/net.h)
moveq.l 1,-[sp] ; 1: AF_UNIX, AF_LOCAL (/usr/include/linux/socket.h)
move.l r7,r2 ; pointer to parameter for "socket"
move.l 1,r3 ; "socket" (/usr/include/linux/net.h)
move.l 102,r0 ; socketcall (/usr/include/asm/unistd.h)
trap $80
addq.l 3*4,r7 ; free space for parameters
cmp.l -4095,r0 ; ERROR
bhs.l err
move.l r0,[x_handle]
; ********** connect socket to /tmp/.X11-unix/X0" ******************
moveq.l sockaddr_un_l,-[sp]
move.l sockaddr_un,-[sp] ; (/usr/include/linux/un.h)
move.l [x_handle],-[sp] ; socket handle
move.l r7,r2 ; pointer to parameter for "connect"
move.l 3,r3 ; "connect" (/usr/include/linux/net.h)
move.l 102,r0 ; socketcall (/usr/include/asm/unistd.h)
trap $80
addq.l 3*4,r7 ; free space for parameters
cmp.l -4095,r0 ; ERROR
bhs.l err
; *************** make socket read non blocking *******************
move.l [x_handle],r3 ; socket handle
move.l 3,r2 ; F_GETFL (/usr/include/asm/fcntl.h)
move.l 55,r0 ; fcntl (/usr/include/asm/unistd.h)
trap $80
cmp.l -4095,r0 ; ERROR
bhs.l err
move.l [x_handle],r3 ; socket handle
move.l 4,r2 ; F_SETFL (/usr/include/asm/fcntl.h)
move.l r0,r1
or.l $800,r1 ; O_NONBLOCK (/usr/include/asm/fcntl.h)
move.l 55,r0 ; fcntl (/usr/include/asm/unistd.h)
trap $80
cmp.l -4095,r0 ; ERROR
bhs.l err
; ******************* send connect message *************************
move.l send1,r0 ; pointer to connect message
move.l send1l,r1
bsr.l get_xauth ; try to read .Xauthority
bcs.b .11 ; no success, let's try without auth.
move.w r3,[send1+6] ; insert name length
move.w r5,[send1+8] ; insert data length
bsr.l x_send ; send header
move.l r2,r0 ; pointer to name
lea.l [r3 +3],r1 ; pad to a multiple of 4
andq.l $0fffffffc,r1
bsr.l x_send ; send name
move.l r4,r0 ; pointer to data
lea.l [r5+3],r1 ; pad to a multiple of 4
andq.l $0fffffffc,r1
.11: bsr.l x_send ; send data
eor.l r4,r4 ; number of total bytes read
move.l buf2,r5 ; pointer to buffer for next read
move.l buf2l,r6 ; max. bytes to read
.10: move.l r5,r0
move.l r6,r1
bsr.l x_receive_raw
beq.b .10 ; but we need a reply
cmp.b 1,[buf2] ; success
bne.l err ; something went wrong
add.l r0,r4 ; total read bytes
add.l r0,r5 ; pointer to buffer for next read
sub.l r0,r6 ; max. bytes to read
cmpq.l 8,r4 ; at least 8 bytes read?
blo.b .10 ; no, get more
movu.wl [buf2+6],r3 ; additional data in 4 bytes
lea.l [r3*4+8],r3 ; total size in bytes
cmp.l r3,r4 ; all read
blo.b .10 ; no, get more
; ******************* calculate id's *******************************
move.l buf2,r5
move.l [r5+$0c],r0 ; resource_id_base
move.l [r5+$10],r1 ; resource_id_mask
move.l r1,r2
neg.l r2
and.l r2,r1 ; resource_id_incr
move.l r0,[s2a] ; wid for CreateWindow
move.l r0,[s3a] ; wid for MapWindow
move.l r0,[s4a] ; wid for CreateDC
move.l r0,[s5a] ; wid for CreateDC
move.l r0,[s6a] ; wid for SetInputFocus
add.l r1,r0 ; next id
move.l r0,[s4b] ; cid for CreateDC
move.l r0,[s5b] ; cid for CreateDC
add.l r1,r0 ; next id
; move.l r0,[resource_id_next] ; maybe we need more id's later
; move.l r1,[resource_id_incr] ; maybe we need more id's later
; ******************* get root window id ***************************
movu.wl [r5+$18],r0 ; length of vendor string
addq.l $28+3,r0 ; const header length + round vendor length
and.b $0fc,r0 ; round to 4 bytes
movu.bl [r5+$1d],r1 ; number of FORMATs
lsl.l 3,r1 ; 8 byte for each FORMAT entry
add.l r0,r1 ; offset to root WINDOW id
move.l [r5+r1],r0 ; root window
move.l r0,[s2b] ; CreateWindow needs root window id
move.l [r5+r1+20],r0 ; width/hight of root window
move.l r0,[s2x] ; create window full size
sub.l (200<<16)+320,r0
lsr.l 1,r0
and.l $0ffff7fff,r0
move.l r0,[s5x] ; center drawing
; ******************* send CreatWindow request *********************
move.l send2,r0
move.l send2l,r1
bsr.l x_send
; ******************* send MapWindow request ***********************
move.l send3,r0
move.l send3l,r1
bsr.l x_send
; ******************* send CreatDC request *************************
move.l send4,r0
move.l send4l,r1
bsr.l x_send
; ******************* send SetInputFocust *************************
move.l send6,r0
move.l send6l,r1
bsr.l x_send
bsr.l init_color ; init 64 VGA colors
; ******************** main loop ***************************
.50: bsr.l annie ; generate next picture
bsr.l display
bsr.l x_receive
beq.b .50 ; no message is a good message
cmp.b 0,[r0.l] ; error message
beq.b err
cmp.b 2,[r0.l] ; key press
beq.b ende
cmp.b 4,[r0.l] ; button press
bne.b .50
err:
ende: move.l 0,r3 ; return code
move.l 1,r0 ; exit
trap $80
;------------------------------------------
display:
move.l screen,r5
move.l 20,r2 ; we use 20 parts to make each less than 16k
..10
move.l send5,r0
move.l send5l,r1
bsr.l x_send
move.l r5,r0
move.l 320*10*4,r1 ; size of one part
bsr.l x_send
add.w 10,[s5y] ; update y pos for next part
add.l 320*10*4,r5 ; update source pointer for next part
dbf.l r2,.10
sub.w 20*10,[s5y] ; restore original y position
rts.l
;-----------------------------------------
; ********* Annie's code to draw a heart ****************
annie: movem.l r0-r7,-[sp]
eor.l r3,r3
.10: inc.l [annie1]
move.l 320*200,r2
eor.l r6,r6
.20: move.l r6,r0 ; byte pos in screen
eor.l r1,r1
move.l 320,r3 ; 320 lines
divu.l r3,r1|r0 ; eax: line 0-199 edx: column 0-319
sub.l 120,r0 ; center y=120 (-120 .. +79)
sub.l 160,r1 ; x=160 (-160 .. +159)
bgt.b .30
neg.l r1 ; symmetric in x (0 .. 160)
.30: move.l r0,r3
muls.l r3,r3,r3 ; ebx = x*x
add.l r1,r0 ; eax = x*x+y
muls.l r0,r0,r1|r0 ; eax = (x*x+y)**2 mod 2*16
add.l r0,r3
beq.b .40
eor.l r1,r1
move.l 600000,r0
divu.l r3,r1|r0
.40: add.l [annie1],r0 ; change color
lsr.b 2,r0
movu.bl r0.b,r0
move.l [color+r0*4],r0
move.l r0,[screen+edi*4]
inc.l r6
dbf.l r2,.20
movem.l [sp]+,r0-r7
rts.l
; ****************** initialize 64 VGA colors *********************
init_color:
movem.l r0-r7,-[sp]
move.l color,r5
move.l 0,r0 ; sic
move.l 64,r2
_01: move.l r0,[r5]
add.l 4,r5
add.b $10,r0
add.w $800,r0
add.l $40000,r0
dbf.l r2,_01
movem.l [sp]+,r0-r7
rts.l
;************************************************* *********
;******** read cookie from $home/.Xauthority **************
;************************************************* *********
; *
; input: stack_ptr: original sp at program start *
; output: C=0: cookie found in $home/.Xauthority *
; r2: pointer to protocol name *
; r3: length of protocol name *
; r4: pointer to protocol data *
; r5: length of protocol data *
; C=1: nothing found *
; r2/r3/r4/r5 undefined *
; *
; typedef struct xauth { *
; unsigned short family; *
; unsigned short address_length; *
; char *address; *
; unsigned short number_length; *
; char *number; *
; unsigned short name_length; *
; char *name; *
; unsigned short data_length; *
; char *data; *
; } Xauth; *
;************************************************* *********
get_xauth:
move.l r0,-[sp]
move.l r1,-[sp]
move.l r6,-[sp]
move.l [stack_ptr],r6 ; original stack pointer at program start
move.l [r6],r0 ; number of arguments
lea.l [r6+r0*4+8],r6 ; skip arguments + trailing null pointer
.20: move.l [r6],r5 ; pointer to next env variable
addq.l 4,r6
tst.l r5,r5 ; no more env variables
beq.l .notfound
cmp.l 'HOME',[r5] ; HOME found?
bne.b .20 ; no, try next
cmp.b '=',[r5.l+4] ; HOME= found?
bne.b .20 ; no, try next
addq.l 5,r5 ; start of HOME path
orq.l -1,r2
.30: inc.l r2 ; count length of HOME path
cmp.b 0,[r5.l+r2.l]
bne.b .30
or.l r2,r2 ; at least one char long?
beq.l .notfound ; no, HOME is empty
cmp.l 256,r2 ; more than 256 charcters
bhi.b .notfound ; somebody tries a buffer overflow
move.l fname,r6 ; buffer for filename
rep_r2 move.b [r5]+-,[r6]+-{s1} ; copy HOME path
move.l '/.Xa',r0 ; add .Xauthority
move.l r0,[r6]+-{s1}
move.l 'utho',r0
move.l r0,[r6]+-{s1}
move.l 'rity',r0
move.l r0,[r6]+-{s1}
move.b 0,[r6.l] ; and a trailing 0
move.l fname,r3
eor.l r2,r2 ; readonly
move.l 5,r0 ; open
trap $80
cmp.l -4095,r0 ; file open error?
bhs.b .notfound ; yes
move.l r0,r3 ; file handle
move.l buf2,r2
move.l buf2l,r1 ; read 1024 byte
move.l 3,r0 ; read
trap $80
cmp.l buf2l,r0
bhs.l err ; .Xauthority >= 1024 byte
move.l r0,r4 ; bytes read
move.l 6,r0 ; close
trap $80
tst.l r4,r4 ; file empty
beq.b .notfound
move.l buf2,r5
add.l r5,r4 ; end of read data
eor.l r0,r0 ; delete upper 16 bit of r0
.60: move.w [r5]+-,r0 ; family
dec.w r0
beq.b .40 ; 1=FamilyLocal
move.l 4,r2 ; skip entry
.50: move.w [r5]+-,r0
ror.w 8,r0 ; big -> little endian
add.l r0,r5
dbf.l r2,.50
cmp.l r4,r5 ; more data
blo.b .60 ; try next entry
..notfound:
bset.w 0,sr ; set Carry
br.b .70
.40: move.l 2,r2
move.l r2,r3
.41: move.w [r5]+-,r0 ; size of data
ror.w 8,r0 ; big endian <-> little endian
add.l r0,r5 ; skip address/number
dbf.l r2,.41
.42: move.w [r5]+-,r0 ; size of protocol name
ror.w 8,r0 ; big endian <-> little endian
move.l r5,r2 ; pointer to protocol name
move.l r0,r3 ; size of protocol name
add.l r3,r5 ; skip name
move.w [r5]+-,r0 ; size of protocol data
ror.w 8,r0 ; big endian <-> little endian
move.l r5,r4 ; pointer to protocol data
move.l r0,r5 ; size of protocol data
bclr.w 0,sr ; clear carry
.70: move.l [sp]+,r6
move.l [sp]+,r1
move.l [sp]+,r0
rts.l
;************************************************* *********
;******** send message to X server **************
;************************************************* *********
; input: r0: pointer to message *
; r1: length of message *
;************************************************* *********
x_send: movem.l r0-r7,-[sp]
move.l r0,r4 ; pointer to next byte of message
move.l r1,r5 ; remaining bytes to send
.20: moveq.l 0,-[sp] ; flags
move.l r5,-[sp] ; length
move.l r4,-[sp] ; pointer to data
move.l [x_handle],-[sp]; socket handle
move.l r7,r2 ; pointer to parameter for "send"
move.l 9,r3 ; "send" (/usr/include/linux/net.h)
move.l 102,r0 ; socketcall (/usr/include/asm/unistd.h)
trap $80
addq.l 4*4,r7 ; free space for parameters
cmpq.l -11,r0 ; EAGAIN:
beq.b .20 ; message couldn't be sent, try again
cmp.l -4095,r0 ; ERROR
bhs.l err
sub.l r0,r5 ; remaining bytes to send
beq.b .30 ; nothing, all sent
add.l r0,r4 ; pointer to remaining message
br.b .20 ; send rest of message
.30: movem.l [sp]+,r0-r7
rts.l
;************************************************* *********
;******** receive ONE message from X server **********
;************************************************* *********
; input: none *
; output: Z=1: no complete message available *
; r0/r1 undefined *
; Z=0: r0: pointer to message data *
; r1: size of data *
;************************************************* *********
x_receive:
move.l r2,-[sp]
move.l r5,-[sp]
move.l r6,-[sp]
.00: move.l [buf2_rest],r0 ; still something in read buffer?
cmpq.l 32,r0 ; a message has at least 32 bytes
bhs.b .10 ; maybe it is a complete message
.30: move.l [buf2_ptr],r5 ; start of message
move.l buf2,r6 ; start of buffer
move.l r6,[buf2_ptr] ; we copy message to top of buffer
cmp.l r5,r6 ; already at top of buffer
beq.b .50 ; then nothing to copy
or.l r0,r0 ; nothing in buffer
beq.b .50 ; then also nothing to copy
move.l r0,r2 ; copy to top of buffer
rep_r2 move.b [r5]+-,[r6]+-{s1}
.50: move.l buf2l,r1 ; let's try to get some more data
sub.l r0,r1 ; not more bytes than space is left in the buf
lea.l [r0+buf2],r0 ; append it here
bsr.l x_receive_raw
bne.b .20 ; we could read something
br.b .100 ; return with Z=1
.20: add.l r0,[buf2_rest] ; now we have a few more bytes in the buffer
br.b .00 ; let's try again
.10: move.l [buf2_ptr],r5 ; let's test if it is a complete meesage
move.l 32,r1 ; error/reply/event base length
cmp.b 1,[r5.l] ; reply message
bne.b .40 ; no, then event/error messages (always 32 byte)
add.l [r5+4],r1 ; + additional data for reply
add.l [r5+4],r1 ; + additional data for reply
add.l [r5+4],r1 ; + additional data for reply
add.l [r5+4],r1 ; + additional data for reply
cmp.l r1,r0 ; complete reply in buffer
blo.b .30 ; no, let's try to get more
.40: move.l r5,r0 ; pointer to data
sub.l r1,[buf2_rest] ; new rest
add.l r1,[buf2_ptr] ; pointer to next data; clear Z flag
.100: move.l [sp]+,r6
move.l [sp]+,r5
move.l [sp]+,r2
rts.l
;************************************************* *********
;******** read data from X server **********
;************************************************* *********
; input: r0: pointer to read buffer *
; r1: size of buffer *
; output: Z=1: nothing to read *
; Z=0: r0 bytes read *
;************************************************* *********
x_receive_raw:
move.l r2,-[sp]
move.l r3,-[sp]
moveq.l 0,-[sp] ; flags
move.l r1,-[sp] ; number of bytes to read
move.l r0,-[sp] ; pointer to buffer
move.l [x_handle],-[sp]; socket handle
move.l r7,r2 ; pointer to parameter for "recv"
move.l 10,r3 ; "recv" (/usr/include/linux/net.h)
move.l 102,r0 ; socketcall (/usr/include/asm/unistd.h)
trap $80
addq.l 4*4,r7 ; free space for parameters
move.l [sp]+,r3
move.l [sp]+,r2
cmpq.l -11,r0 ; EAGAIN: no message available -> Z=1
beq.b .10
cmp.l -4095,r0 ; ERROR
bhs.l err
tst.l r0,r0 ; 0: NULL message -> Window close?
beq.l ende
.10: rts.l
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;
;--------------------------- constant data ---------------------------------
align 4
sockaddr_un:
dc.w 1 ; 1: AF_UNIX, AF_LOCAL (/usr/include/linux/socket.h)
dc.b "/tmp/.X11-unix/X0"
sockaddr_un_l equ $-sockaddr_un
align 4
;---------------------------------------------------------------------------
align 4
code_memsz equ $-$$
code_filez equ code_memsz
data_addr equ (orig+code_memsz+4095)/4096*4096 + (code_filez % 4096)
data_offset equ code_filez
section .data vstart=data_addr
;--------------------------- initialized data ------------------------------
buf2_ptr: dc.l buf2
buf2_rest: dc.l 0
; Connection Setup
send1: dc.b $6c,0 ; LSB first
dc.w 11,0 ; major/minor version
dc.w 0,0 ; length of protocol name/data
dc.w 0 ; unused
send1l equ $-send1
; Create Window
send2: dc.b 1 ; opcode for Create Window
dc.b 0 ; depth from parent
dc.w send2l/4; request length
s2a: dc.l 0 ; wid (has to be calculated)
s2b: dc.l 0 ; parent (has to be calculated)
dc.w 0 ; x
dc.w 0 ; y
s2x: dc.w 640 ; with
s2y: dc.w 400 ; higth
dc.w 0 ; border-width
dc.w 0 ; class: CopyFromParent
dc.l 0 ; visual: CopyFromParent
dc.l $0a02 ; value-mask: background-pixel 2
; + override-redirect 200
; + event-mask 800
dc.l $000000 ; background: black
dc.b 1 ; override-redirect = true
dc.b 0,0,0 ; pad
dc.l $05 ; event_mask: KeyPress 1
; +ButtenPress 4
; +PointerMotion 40
send2l equ $-send2
; Map Window
send3: dc.b 8 ; opcode for Map Window
dc.b 0 ; unused
dc.w send3l/4; request length
s3a: dc.l 0 ; wid (has to be calculated)
send3l equ $-send3
; Create GC
send4: dc.b 55 ; opcode for CreateGC
dc.b 0 ; unused
dc.w send4l/4; request length
s4b: dc.l 0 ; cid (has to be calculated)
s4a: dc.l 0 ; wid (has to be calculated)
dc.l 1+4+8 ; function+foreground+background
dc.l 3 ; function=copy
dc.l $0ffffff; foreground: white
dc.l $0080ff ; background: light blue
send4l equ $-send4
; Put Image
send5: dc.b 72 ; opcode for PutImage
dc.b 2 ; ZPixmap
dc.w send5l/4+320*10*4/4; request length
s5a: dc.l 0 ; wid (has to be calculated)
s5b: dc.l 0 ; cid (has to be calculated)
dc.w 320 ; width
dc.w 200/20 ; hight; we send 20 parts each 12800 byte (<16k)
s5x: dc.w 0 ; dest-x (inserted later)
s5y: dc.w 0 ; dest-y (inserted later)
dc.b 0 ; left-pad
dc.b 24 ; depth
dc.w 0 ; unused
send5l equ $-send5
; Set Input Focus
send6: dc.b 42 ; opcode for SetInputFocus
dc.b 0 ; revert-to None
dc.w send6l/4; request length
s6a: dc.l 0 ; wid (has to be calculated)
dc.l 0 ; timestamp CurrentTime
send6l equ $-send6
;---------------------------------------------------------------------------
idat_memsz equ $-$$
bss_addr equ data_addr+ ($-$$)
section .bss vstart=bss_addr
;--------------------------- uninitialized data ----------------------------
screen: blk.l 320*200 ; bitmap
stack_ptr: blk.l 1
x_handle: blk.l 1
annie1: blk.l 1
color: blk.l 64
fname: blk.b 256+32
buf2: blk.b 16*1024
buf2l equ $-buf2
;---------------------------------------------------------------------------
udat_memsz equ $-$$
data_memsz equ idat_memsz + udat_memsz
data_filez equ idat_memsz
;================================================= ==========================
-
Re: Calling libraries from assembler.
On Apr 19, 8:29 am, Frank Kotler wrote:
> SoLo2 wrote:
> > Hello!
>
> > I have tried how simple it is to use
> > system calls in Linux from assembler.
> > Setting parameters in the registers
> > eax/edx and then "int 0x80".
>
> > I would like to know it there
> > is a similar, easy way of calling
> > other libraries (specially X windows).
>
> I don't know how "similar" you'd call it, or "easy"... but yes, we
> certainly can do that. At some point, there isn't much "advantage" to
> using asm...
>
> Might be better to start with a simpler "just call printf" example, but
> since you ask about X, I'll append a simple "hello X".
>
> > It should be as simple as giving
> > the function name in ASCII ! 
>
> Well... it won't work in Egyptian hieroglyphics (unless you've got an
> Egyptian assembler)... I have seen stuff like:
>
> button db "button", 0
>
> ... mostly in "helper" libraries, not in Xlib itself. I don't know when
> or why we have to do that. Mostly it's just "extern XFoo"...
>
> This example links directly with ld. It strikes me that it might be
> "dangerous" to be using C library code, without linking in the C startup
> code. It "seems to work". I haven't had any trouble with it... (we *do*
> need to tell ld which interpreter/dynamic linker to use - ld gets it
> wrong by default! gcc knows...) Replace "_start" with "main", if you
> want to do it that way...
>
> I have other examples... including accessing Xwindows *without*
> libraries - just using the int 80h interface - and even examples that
> avoid using ld - creating a "ready to run" executable using Nasm's "-f
> bin" mode. How "raw" would you like to get? 
>
> I'm replying from comp.lang.asm.x86 - I doubt if these other groups are
> interested in doing it in assembly language (or are they???). Should
> probably trim followups, at some point. There is also interest in this
> subject on the news:alt.lang.asm newsgroup...
>
> Best,
> Frank
>
> ; rudimentary "hello world" for Xwindows
>
> ; nasm -f elf -O999 x1.asm
> ; add the "-g" switch for debugging info - good luck!
> ;
> ; sorry 'bout this one...
> ; ld -o x1 x1.o -I/lib/ld-linux.so.2 -L/usr/X11R6/lib -lX11
> ;
> ; if you want it small:
> ; strip -R .comment x1
> ;
> ; after all that, we still have to tell ld where the fun begins:
>
> global _start
>
> ; inform Nasm that ld knows where to find this stuff (we hope!)
>
> extern XOpenDisplay
> extern XDefaultRootWindow
> extern XCreateSimpleWindow
> extern XNextEvent
> extern XDestroyWindow
> extern XCloseDisplay
> extern XMapRaised
> extern XSelectInput
> extern XStoreName
> extern XCreateGC
> extern XFreeGC
> extern XDrawImageString
> extern XSetForeground
> extern XSetBackground
>
> ; we'll be needing lots more of these...
>
> KeyPressMask equ 1 ; mask for XSelectInput
> KeyPress equ 2 ; the "type" of event (offset 0 in "glob of bytes")
>
> ExposeMask equ 1 << 15
> ExposeEvent equ 12
>
> event_size equ 20h ; ??? max size of several different structs
>
> ;------------------------------------------
> section .data
> StringOpenFailed db "Can't Open X display!", 10
> StringOpenFailed_len equ $ - StringOpenFailed
>
> caption db 'A Window', 0
>
> string db ' Greetings from X, Earthling! '
> string_len equ $ - string
> ;-----------------------------------------
>
> ;-----------------------------------------
> section .bss
>
> Display resd 1
> Window resd 1
> GC resd 1
>
> event resd event_size
> ;-------------------------------------
>
> ;-------------------------------------
> section .text
>
> _start: ; let the ritual begin.
>
> ; nop ; parking place for gdb
>
> ; open a connection to the server.
> ; pushing 0 uses the "DISPLAY" environment variable
> ; or defaults to local machine.
>
> push 0
> call XOpenDisplay
> add esp, 4
>
> or eax, eax
> je OpenFailed
>
> mov dword [Display], eax
>
> push dword [Display]
> call XDefaultRootWindow
> add esp, 4
> ; error?
>
> push 0 ; background colour
> push 0 ; border colour
> push 0 ; border width
> push 300 ; height
> push 400 ; width
> push 50 ; top co-ord
> push 50 ; left co-ord
> push eax ; XDefaultRootWindow, from above
> push dword [Display] ; display handle
> call XCreateSimpleWindow
> add esp, 36 ; C clean-up parameters stuff
>
> or eax, eax
> je CreateFailed
>
> mov dword [Window], eax
>
> ; this is one Windows doesn't do. if we don't specify
> ; what events (messages) we want to receive, we don't get any.
>
> push KeyPressMask | ExposeMask
> ; "or" this with other events to recv!
> ; don't forget to handle 'em!
> push dword [Window]
> push dword [Display]
> call XSelectInput
> add esp, 12
> ; error?
>
> ; give the baby a name
>
> push caption
> push dword [Window]
> push dword [Display]
> call XStoreName
> add esp, 12
> ; error?
>
> ; make our window visible.
>
> push dword [Window]
> push dword [Display]
> call XMapRaised
> add esp, 8
> ; error?
>
> push 0 ; values?
> push 0 ; valuemask?
> push dword [Window]
> push dword [Display]
> call XCreateGC
> add esp, 16
> ;error?
> mov dword [GC], eax
>
> ; Mmmm, looks like 16-bit color, 5-6-5, on my machine.
> ; Bet we can't count on it!
>
> ; push 65535 ; white
> push 1111100000000000b ; red
> push dword [GC]
> push dword [Display]
> call XSetForeground
> add esp, 12
> ; error?
>
> ; push 0 ; black
> push 0000011111100000b ; green
> push dword [GC]
> push dword [Display]
> call XSetBackground
> add esp, 12
> ; error?
>
> Eventloop:
> push event
> push dword [Display]
> call XNextEvent
> add esp, 8
> ; error?
>
> cmp dword [event], ExposeEvent
> jnz not_expose
> call drawscreen
> jmp Eventloop
> not_expose:
>
> cmp dword [event], KeyPress
> jne Eventloop
>
> ; exit gracefully if key pressed
>
> push dword [GC]
> push dword [Display]
> call XFreeGC
> add esp, 8
>
> push dword [Window]
> push dword [Display]
> call XDestroyWindow
> add esp, 8
>
> CreateFailed:
> push dword [Display]
> call XCloseDisplay
> add esp, 4
> jmp Terminate
>
> OpenFailed:
> mov eax, 4 ; __NR_write
> mov ebx, 2 ; stderr
> mov ecx, StringOpenFailed ; buffer
> mov edx, StringOpenFailed_len ; count
> int 80h
>
> Terminate:
> mov eax, 1 ; function (sys_exit)
> xor ebx, ebx ; exit code
> int 80h ; make Linux system call
> ;-------------------------------------------
>
> ;-------------------------------------------
> drawscreen:
> push string_len
> push string
> push 140 ; y pos
> push 155 ; x pos
> push dword [GC]
> push dword [Window]
> push dword [Display]
> call XDrawImageString
> add esp, 28
> ; error?
> ret
> ;---------------------------------------------
Hello!
Thanks to Frank Kotler for his
excellent example of assembler
i86 and X.
[ Also Kleebauer's with the
Motorola 68millions version. ]
I would like to see that the dynamic
libraries are not very dynamic,
if the higher abstraction of using an
ASCII function name is not used.
This is the case as the compilation
of the program requires naming and
linking some "dynamic" libraries.
The program system or programmer
could use an "INT 80" with the ASCII
library name and then the interrupt
delivers the actual method pointer that
is faster to use for further calls.
Wasn't this already for Linux?
Where is this beautifull idea gone?
Java? :-)
Someone points out that there is
doubt a compiler would reach such
clean code for an X program as this
shown by Mr. Kotler.
Greetings,
H.Samso
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
http://bits.atari.org
http://biis.tripod.com
http://so_o2.tripod.com
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
Re: Calling libraries from assembler.
An interesting point in Frank Kotler's posting, is who gets to clean
up the stack.
Here Frank is doing it in the main program (obviously because the
called rountines don't do this for him).
But I was "brought up" on the Microsoft standard of the CALLED
subprogram doing a RET N operation to clear the stack. All my hand-
wriiten subroutine include this, beuase my main program is a Microsoft
Fortran program which folows my description of the stack
responsibility.
So I assume Miscroft chnaged it's mind at some point in time, because
obvious again, the referred called services aboove are Microsoft-
written Windows service.
-
Re: Calling libraries from assembler.
Terence wrote:
> An interesting point in Frank Kotler's posting, is who gets to clean
> up the stack.
> Here Frank is doing it in the main program (obviously because the
> called rountines don't do this for him).
> But I was "brought up" on the Microsoft standard of the CALLED
> subprogram doing a RET N operation to clear the stack. All my hand-
> wriiten subroutine include this, beuase my main program is a Microsoft
> Fortran program which folows my description of the stack
> responsibility.
>
> So I assume Miscroft chnaged it's mind at some point in time, because
> obvious again, the referred called services aboove are Microsoft-
> written Windows service.
???
You'll have to point out the Microsoft written services to me. I missed
'em. Is this what the lawsuit's about??? 
Best,
Frank
-
Re: Calling libraries from assembler.
Terence wrote:
> An interesting point in Frank Kotler's posting, is who gets to clean
> up the stack.
> Here Frank is doing it in the main program (obviously because the
> called rountines don't do this for him).
> But I was "brought up" on the Microsoft standard of the CALLED
> subprogram doing a RET N operation to clear the stack. All my hand-
> wriiten subroutine include this, beuase my main program is a Microsoft
> Fortran program which folows my description of the stack
> responsibility.
>
> So I assume Miscroft chnaged it's mind at some point in time, because
> obvious again, the referred called services aboove are Microsoft-
> written Windows service.
No, the program is for X Windows, whose interface uses the so called "C
calling convention", where it's the caller's job to clean-up the stack.
-
Re: Calling libraries from assembler.
In alt.lang.asm Terence wrote in part:
> An interesting point in Frank Kotler's posting, is who gets to
> clean up the stack. Here Frank is doing it in the main program
> (obviously because the called rountines don't do this for him).
> But I was "brought up" on the Microsoft standard of the CALLED
> subprogram doing a RET N operation to clear the stack. All my
> hand- wriiten subroutine include this, beuase my main program is
> a Microsoft Fortran program which folows my description of the
> stack responsibility.
It is much easier to do caller-cleanup (whence the RET N
instruction) in FORTRAN with fixed param lists than in C
which allows a variable number of params e.g. printf()
-- Robert
-
Re: Calling libraries from assembler.
On Apr 20, 5:33*pm, Terence wrote:
> An interesting point in Frank Kotler's posting, is who gets to clean
> up the stack.
> Here Frank is doing it in the main program (obviously because the
> called rountines don't do this for him).
> But I was "brought up" on the Microsoft standard of the CALLED
> subprogram doing a RET N operation to clear the stack. All my hand-
> wriiten subroutine include this, beuase my main program is a Microsoft
> Fortran program which folows my description of the stack
> responsibility.
>
> So I assume Miscroft chnaged it's mind at some point in time, because
> obvious again, the referred called services aboove are Microsoft-
> written Windows service.
Win16 has always used what MS has called the Pascal calling
convention, and Win32 uses stdcall. Both of those are callee cleanup,
but stdcall passes parameters right-to-left (like cdecl), unlike
Pascal (which is left-to-right). C compilers use cdecl (which is
right-to-left and caller cleanup) by default. Left-to-right and
callee cleanup are both problems for C-style variable argument lists.
It is fairly conventional in Windows to make all API-style functions
(including most things exported from DLLs) use Pascal or stdcall as
appropriate for the system, although there is absolutely nothing
enforcing that, and in fact, the shared (DLL) versions of the CRT
supplied by MS use cdecl conventions for the C library functions.
Win64 uses a variation of the old fastcall convention for both intra-
program calls and API calls, which is also the case for most *nix
systems (IOW, the same calling convention is used intra- and inter-
program, but it’s not the same as the Win64 conventions). That does
simplify things.
And the convention moves around a bit for non-x86 platforms.
-
Re: Calling libraries from assembler.
A misunderstanding Frank!
I know the posting is about the use of Linux.
And an ASM program written as a main can call named sub-programs,
whether service or otherwise.
But this same main program can be used with Windows as long as what
its calls are valid for a Windows environment.
And here is the point.
When you write a 32-bit algorithm in ASM for an Intel chip, the main
code is valid whether for Windows or Linux, EXCEPT the calls to
services.
And I write for DOS and Windoss and change the subprogram library I
link with to match.
But I have also to match the calling convention or use a common one.
And FOrytran and C, as example, use different stack conventions.
In Linux the usage is to push parameters to the stack and call a
subprogram service, and on return, to clear the stack space used.
Microsoft's original preffered scheme was to have the called
subprogram clear the stackk on return.
-
Re: Calling libraries from assembler.
Terence wrote:
> A misunderstanding Frank!
> I know the posting is about the use of Linux.
> And an ASM program written as a main can call named sub-programs,
> whether service or otherwise.
>
> But this same main program can be used with Windows as long as what
> its calls are valid for a Windows environment.
>
> And here is the point.
> When you write a 32-bit algorithm in ASM for an Intel chip, the main
> code is valid whether for Windows or Linux, EXCEPT the calls to
> services.
>
> And I write for DOS and Windoss and change the subprogram library I
> link with to match.
> But I have also to match the calling convention or use a common one.
> And FOrytran and C, as example, use different stack conventions.
I'm not familiar with Fortran. How do they do it?
> In Linux the usage is to push parameters to the stack and call a
> subprogram service, and on return, to clear the stack space used.
> Microsoft's original preffered scheme was to have the called
> subprogram clear the stackk on return.
Right... AFAIK, they still do it that way, with a couple exceptions -
"wsprintf", I think... probably more...
Unless I'm mistaken, changing ".model flat stdcall" to ".model flat C"
would automatically adjust your code... with certain assemblers...
Best,
Frank
-
Re: Calling libraries from assembler.
(Gordon Burditt) wrote:
>> I have tried how simple it is to use
>> system calls in Linux from assembler.
>> Setting parameters in the registers
>> eax/edx and then "int 0x80".
>
> You are not calling a library. You are calling the kernel.
> There's a difference.
>
>> I would like to know it there
>> is a similar, easy way of calling
>> other libraries (specially X windows).
>>
>> It should be as simple as giving
>> the function name in ASCII ! 
>
> Look at how the C compiler calls C functions. Write a simple
> function that does some calls, gcc -S foo.c, and examine foo.s .
> Generally, you push a bunch of arguments on to the stack, use a
> call instruction to call the function, and adjust the stack to
> remove the stuff you pushed on.
Be careful: this applies only to a certain version of a certain compiler
suite on a certain machine architecture.
E.g. when compiling on an x86_64 architecture, I find that it passes the
first 6 arguments in registers rdi, rsi, rdx, rcx(*), r8, and r9 (or
their 32-bit counterparts). The rest is passed on the stack.
(*) The fourth argument of a system call is passed in r10 instead of rcx!
BTW As a caller, you don't have to be aware of a varargs function, e.g.
printf: just pass the arguments as you would for a fixed-argument function.
--
These are my personal views and not those of Fujitsu Siemens Computers!
Josef Möllers (Pinguinpfleger bei FSC)
If failure had no penalty success would not be a prize (T. Pratchett)
Company Details: http://www.fujitsu-siemens.com/imprint.html
-
Re: Calling libraries from assembler.
Frank Kotler wrote:
> Terence wrote:
>> A misunderstanding Frank!
>> I know the posting is about the use of Linux.
>> And an ASM program written as a main can call named sub-programs,
>> whether service or otherwise.
>>
>> But this same main program can be used with Windows as long as what
>> its calls are valid for a Windows environment.
>>
>> And here is the point.
>> When you write a 32-bit algorithm in ASM for an Intel chip, the main
>> code is valid whether for Windows or Linux, EXCEPT the calls to
>> services.
>>
>> And I write for DOS and Windoss and change the subprogram library I
>> link with to match.
>> But I have also to match the calling convention or use a common one.
>> And FOrytran and C, as example, use different stack conventions.
>
> I'm not familiar with Fortran. How do they do it?
Neither am I. But I recall that for one, Fortran doesn't support
recursion, and, as Robert pointed out, not all early machines had a
proper stack, parameters might be passed in a fixed location.
The best thing to do would be to compile a Fortran program and look at
the object code.
--
These are my personal views and not those of Fujitsu Siemens Computers!
Josef Möllers (Pinguinpfleger bei FSC)
If failure had no penalty success would not be a prize (T. Pratchett)
Company Details: http://www.fujitsu-siemens.com/imprint.html
-
Re: Calling libraries from assembler.
Robert Redelmeier wrote:
> In alt.lang.asm Frank Kotler wrote in part:
>> I'm not familiar with Fortran. How do they do it?
>
> FORTRAN (FORmula TRANslation) is the oldest wide-spread HLL,
> dating from 1957. It is still used for scientific coding.
>
>>From an ASM PoV, FORTRAN is call-by-address (not the `c` call
> by value)
AFAIR you could manage to "change the value of 5"(*) on some early
compilers by calling a function which modifies one of its arguments,
with the constant as an argument ;-)
(*) A question from the "Hacker Test". No, I never did that, but I did
program while intoxicated ;-)
--
These are my personal views and not those of Fujitsu Siemens Computers!
Josef Möllers (Pinguinpfleger bei FSC)
If failure had no penalty success would not be a prize (T. Pratchett)
Company Details: http://www.fujitsu-siemens.com/imprint.html
-
Re: Calling libraries from assembler.
On Apr 22, 5:42*pm, Josef Moellers wrote:
>.... But I recall that for one, Fortran doesn't support
> recursion, and, as Robert pointed out, not all early machines had a
> proper stack, parameters might be passed in a fixed location.
>
> The best thing to do would be to compile a Fortran program and look at
> the object code.
>
Oh NO!, Fortran DOES support recursion!
-
Re: Calling libraries from assembler.
On Tue, 22 Apr 2008 15:18:31 -0700 (PDT), Terence
wrote:
> On Apr 22, 5:42*pm, Josef Moellers wrote:
>
> >.... But I recall that for one, Fortran doesn't support
> > recursion, and, as Robert pointed out, not all early machines had a
> > proper stack, parameters might be passed in a fixed location.
> >
> > The best thing to do would be to compile a Fortran program and look at
> > the object code.
> >
For the particular compiler(s?), and possibly options, of interest.
>
> Oh NO!, Fortran DOES support recursion!
Since 1990, but it's still not the default. Compilers legally _can_
still use single-copy (static) storage for routines not attributed
RECURSIVE. But since most CPUs nowadays support stack access at least
as efficient as static, there's rarely any longer a benefit to it.
Also variables declared with initialization are implicitly attributed
(also) SAVE, meaning single-copy even in a RECURSIVE routine. To have
'local' (per invocation) variables, you must use assignment instead.
This is a FAQ on c.l.fortran.
- formerly david.thompson1 || achar(64) || worldnet.att.net
-
Re: Calling libraries from assembler.
SoLo2 wrote:
> Hello!
>
>
> I have tried how simple it is to use
> system calls in Linux from assembler.
> Setting parameters in the registers
> eax/edx and then "int 0x80".
>
> I would like to know it there
> is a similar, easy way of calling
> other libraries (specially X windows).
>
> It should be as simple as giving
> the function name in ASCII ! 
>
On 32-bit x86:
/* foo = func(arg1, arg2, arg3) */
push arg3
push arg2
push arg1
call func
mov %eax,foo
On 64-bit x86:
mov arg3,%rdx
mov arg2,%rsi
mov arg1,%rdi
call func
mov %rax,foo
-hpa
-
Re: Calling libraries from assembler.
"H. Peter Anvin" writes:
>SoLo2 wrote:
>> Hello!
>>
>>
>> I have tried how simple it is to use
>> system calls in Linux from assembler.
>> Setting parameters in the registers
>> eax/edx and then "int 0x80".
>>
>> I would like to know it there
>> is a similar, easy way of calling
>> other libraries (specially X windows).
>>
>> It should be as simple as giving
>> the function name in ASCII ! 
>>
>
>On 32-bit x86:
>
> /* foo = func(arg1, arg2, arg3) */
>
> push arg3
> push arg2
> push arg1
> call func
> mov %eax,foo
>
>On 64-bit x86:
>
> mov arg3,%rdx
> mov arg2,%rsi
> mov arg1,%rdi
> call func
> mov %rax,foo
>
> -hpa
>
Although the x86 part does get a bit more complicated after the first 6 args,
for floating args, and for arguments that don't fit in a 64-bit register.
See the x86_64 processor ABI for full details.
scott
-
Re: Calling libraries from assembler.
(Scott Lurndal) wrote:
>>
>> On 64-bit x86:
>>
>> mov arg3,%rdx
>> mov arg2,%rsi
>> mov arg1,%rdi
>> call func
>> mov %rax,foo
>>
>> -hpa
>>
>
> Although the [x86-64] part does get a bit more complicated after the first 6 args,
> for floating args, and for arguments that don't fit in a 64-bit register.
>
Right. I also didn't mention that the caller needs to clean up any
stack arguments:
[32 bit code]
>> /* foo = func(arg1, arg2, arg3) */
>>
>> push arg3
>> push arg2
>> push arg1
>> call func
add $3*4,%esp
>> mov %eax,foo
-hpa