Re: [Nasm-users] Working with pointers
Frank Kotler <fbkotler <at> zytor.com>
2010-12-20 20:36:36 GMT
Littlefield, Tyler wrote:
> Rather than filling everyone's inbox replying to all of these, just
> wanted to say thanks for all the help.
Hi Tyler,
You're welcome. I'm going to undo your consideration and fill up
everybody's mailbox, though, 'cause I think your questions are
interesting, and might lead to some discussion. If anyone thinks this
list is generating too much traffic, they can complain... or just
unsubscribe. :)
> It helped. I have two more
> questions. First, I'm working with Unix systems. How would I go about
> creating a socket, closing the socket, etc?
ASSuming you want to do this via the int 80h interface, there's really
only one sys_socketcall (102). This is usually "wrapped" to socket
(create), connect, bind, listen, etc. Even Konstantin's "asmutils"
provides macros for sys_socket, etc. But the "real" interface is just
sys_socketcall, with the subfunctions or "commands" in ebx - ecx points
to remaining parameters. In order to not "hide" anything, I like to do
it that way, although we're "supposed" to use the C library interface
(they make me say that). There are "send" and "recv" commands, but
sys_write/sys_read seem to work - sys_close seems to work - just like
any other file descriptor.
> Last, do we have some sort
> of method for using malloc? I don't think it's an actual syscall, but I
> need to be able to allocate memory.
Well, "just call malloc". There are a couple of system calls that will
get us a chunk of memory - sys_mmap (or mmap2?) and sys_brk. These get
us a minimum of 4096 bytes. To "malloc" smaller pieces, we're on our
own. I think Jonathan Bartlett's "PGU" has an example. I think sys_mmap
gets us memory starting about 40000000h, sys_brk gives us memory
contiguous with the end of our existing memory, which may be an
advantage(?). As I recall, "man 2 brk" isn't too helpful (unusually).
xor ebx, ebx
mov eax, 45
int 80h
; check for error - shouldn't be any(?)
mov [orig_break], eax
mov ebx, eax
add ebx, 4096 ; or some multiple
mov eax, 45
int 80h
; check for error - might be out of memory
Now eax should have our new "break" (where memory ends for our process).
We can use memory between "orig_break" and "new_break". To "free" it:
mov ebx, [orig_break]
mov eax, 45
int 80h
Now we should be back where we were. I think that works...
Getting back to sockets, here's my adaptation of Scott Lanning's
"daytime_cli.s" (available at Konstantin's linuxassembly.org, or
http://asm.sf.net somewhere):
;-----------------------------
; daytime client in Linux asm, syscalls only
; loosely based on daytime_cli.s from Scott Lanning
;
; nasm -f elf32 daytime.asm
; ld -o daytime daytime.o
global _start
struc sockaddr_in
.sin_family resw 1
.sin_port resw 1
.sin_addr resd 1
.sin_zero resb 8
endstruc
_ip equ 0x7F000001 ; loopback - 127.0.0.1
_port equ 13
; Convert numbers to network byte order
IP equ ((_ip & 0xFF000000) >> 24) | ((_ip & 0x00FF0000) >> 8) | ((_ip &
0x0000FF00) << 8) | ((_ip & 0x000000FF) << 24)
PORT equ ((_port >> 8) & 0xFF) | ((_port & 0xFF) << 8)
AF_INET equ 2
SOCK_STREAM equ 1
BUFLEN equ 0x80
STDIN equ 0
STDOUT equ 1
__NR_exit equ 1
__NR_read equ 3
__NR_write equ 4
__NR_socketcall equ 102
SYS_SOCKET equ 1
SYS_CONNECT equ 3
section .data
my_sa istruc sockaddr_in
at sockaddr_in.sin_family, dw AF_INET
at sockaddr_in.sin_port, dw PORT
at sockaddr_in.sin_addr, dd IP
at sockaddr_in.sin_zero, dd 0, 0
iend
socket_args dd AF_INET, SOCK_STREAM, 0
; first of these wants to be socket descriptor
; we fill it in later...
connect_args dd 0, my_sa, sockaddr_in_size
section .bss
my_buf resb BUFLEN
sock_desc resd 1
section .text
_start:
; socket(AF_INET, SOCK_STREAM, 0)
mov ecx, socket_args ; address of args structure
mov ebx, SYS_SOCKET ; subfunction or "command"
mov eax, __NR_socketcall ;c.f. /usr/src/linux/net/socket.c
int 80h
cmp eax, -4096
ja exit
mov [sock_desc], eax
; and fill in connect_args
mov [connect_args], eax
; connect(sock, (struct sockaddr *)&sa, sizeof(struct sockaddr))
mov ecx, connect_args
mov ebx, SYS_CONNECT ; subfunction or "command"
mov eax, __NR_socketcall
int 80h
cmp eax, -4096
ja exit
; read(sock, buf, len)
mov edx, BUFLEN ; arg 3: max count
mov ecx, my_buf ; arg 2: buffer
mov ebx, [sock_desc] ; arg 1: fd
mov eax, __NR_read ; sys_read
int 80h
cmp eax, -4096
ja exit
; write(stdout, buf, len)
mov edx, eax ; length read is length to write
mov ecx, my_buf
mov ebx, STDOUT
mov eax, __NR_write
int 80h
xor eax, eax ; success
exit:
mov ebx, eax ; exitcode
mov eax, __NR_exit
int 80h
;----------------------
That probably won't do anything, unless you've already got a "daytime"
server running. Edit (as root) /etc/inetd.conf and uncomment the
"daytime" line. Do "ps x" to get the ID for inetd, and "kill -HUP xxxx".
Works for me. If your system is different, enlighten me!
I have a couple other examples... an "echo" (or echo-like) client and
server (not a very good "server"). I also have a couple examples Nathan
Baker sent me - Windows programs using the NASMX package. I've written a
"fakeapi.asm" containing functions with the same names and parameters as
the Windows APIs, that do "approximately" the same thing. Linking
(statically) against this allows the same programs to run in Linux. This
is just a novelty, and will *not* work in the "general case", but I
thought it was amusing...
If anyone wants to see any of these, give a yell.
Best,
Frank
------------------------------------------------------------------------------
Lotusphere 2011
Register now for Lotusphere 2011 and learn how
to connect the dots, take your collaborative environment
to the next level, and enter the era of Social Business.
http://p.sf.net/sfu/lotusphere-d2d