Calling libraries from assembler. - Unix

This is a discussion on Calling libraries from assembler. - Unix ; 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 ...

+ Reply to Thread
Results 1 to 20 of 20

Thread: Calling libraries from assembler.

  1. 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


  2. 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"


  3. 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
    ;---------------------------------------------


  4. 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
    ;================================================= ==========================

  5. 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
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


  6. 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.


  7. 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


  8. 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.


  9. 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


  10. 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.


  11. 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.


  12. 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


  13. 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


  14. 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


  15. 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


  16. 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!


  17. 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


  18. 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


  19. 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


  20. 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


+ Reply to Thread