Post by Chuck CrayneMuch as I hate to suggest that my teammate Frank was smoking something
when he wrote that reply, the fact is that NASM creates elf object
files, which must be linked before they can be executed.
Fact is that NASM can write any of the 256 possible bytes to the output file
and therefore doesn't need any linker to generate an executable binary. Not
even for graphics programs:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; 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"
;===========================================================================
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 8*1024
buf2l equ $-buf2
;---------------------------------------------------------------------------
udat_memsz equ $-$$
data_memsz equ idat_memsz + udat_memsz
data_filez equ idat_memsz
;===========================================================================