Hi guys, how r u? I need your help. I am trying to write a program in gnu assembler in which I need to use the "wget" function. I think that its library in c language is: #include <stdio.h>, so I tried this in my code:
obviously, it returns to me this error
iplog.s: Assembler messages:
iplog.s:1: Error: missing string
Any ideas?
thanks in advance!
.include stdio.h
.section .data
.section .text
.globl _start
_start:
call wget
movl $1, %eax
movl $0, %ebx
int $0x80
obviously, it returns to me this error
iplog.s: Assembler messages:
iplog.s:1: Error: missing string
Any ideas?
thanks in advance!
wget is a linux program that you can execute from the shell. Are you trying to call it from your source???
Hi Marce,
I don't think wget is a "function" in a C library that you could "call" like that. I could be wrong. As P1ranha says, it's an executable. You could execute it from your program with sys_execve. That doesn't return, so if you wanted to have your program keep running after wget exited, you'd have to sys_fork first, and then execve wget in the "child". Probably better off to execve bash (or other shell), giving wget on the command line to bash. The C library provides system() that would do that.
Or you could "do it yourself" with socket(), connect(), send(), revc(), etc. If you want to do that with sys_calls, there's only one - sys_socketcall - and the various "commands" go in %ebx (pointer to an arguments structure in %ecx)...
You can get rid of the immediate "missing string" error by putting quotes around "stdio.h"... but then it's "not found". There are several versions of "stdio.h". "/usr/include/stdio.h" is apparently not the right one, as it generates a whole pantload of errors. I haven't tried anything beyond that, 'cause I'm not sure that "stdio.h" is what you want anyway...
I do have a "wget-like" program, written by Nathan Baker, using P1ranha's NASMX package(!). It is for Windows, and uses Windows APIs, but I've got a "fakeapi.asm" which I assemble to "fakeapi.o" and link against Nathan's Windows program, allowing it to run in Linux. Pretty cool... as far as it goes. I don't have a "sys_calls only" equivalent to gethostbyname(), so the IP has to be hard-coded in... which limits its usefulness considerably! :(
There's a "wget" in Konstantin's "asmutils" package, too. None of this is in (G)as syntax, but could be "translated" without "too" much trouble.
Easiest thing might be to run "wget" from the command line, and then process the resulting file(s) with your asm program. Depends on what you're trying to do...
In the more general case of calling C libraries from (G)as... we might be able to come up with an example...
Glad to see you're still doing assembly language!
Best,
Frank
I don't think wget is a "function" in a C library that you could "call" like that. I could be wrong. As P1ranha says, it's an executable. You could execute it from your program with sys_execve. That doesn't return, so if you wanted to have your program keep running after wget exited, you'd have to sys_fork first, and then execve wget in the "child". Probably better off to execve bash (or other shell), giving wget on the command line to bash. The C library provides system() that would do that.
Or you could "do it yourself" with socket(), connect(), send(), revc(), etc. If you want to do that with sys_calls, there's only one - sys_socketcall - and the various "commands" go in %ebx (pointer to an arguments structure in %ecx)...
You can get rid of the immediate "missing string" error by putting quotes around "stdio.h"... but then it's "not found". There are several versions of "stdio.h". "/usr/include/stdio.h" is apparently not the right one, as it generates a whole pantload of errors. I haven't tried anything beyond that, 'cause I'm not sure that "stdio.h" is what you want anyway...
I do have a "wget-like" program, written by Nathan Baker, using P1ranha's NASMX package(!). It is for Windows, and uses Windows APIs, but I've got a "fakeapi.asm" which I assemble to "fakeapi.o" and link against Nathan's Windows program, allowing it to run in Linux. Pretty cool... as far as it goes. I don't have a "sys_calls only" equivalent to gethostbyname(), so the IP has to be hard-coded in... which limits its usefulness considerably! :(
There's a "wget" in Konstantin's "asmutils" package, too. None of this is in (G)as syntax, but could be "translated" without "too" much trouble.
Easiest thing might be to run "wget" from the command line, and then process the resulting file(s) with your asm program. Depends on what you're trying to do...
In the more general case of calling C libraries from (G)as... we might be able to come up with an example...
Glad to see you're still doing assembly language!
Best,
Frank
Frank, first of all, i'm not doing assembly language, I am struggling with it! But, to be honest, I love it! it's so hard that I love it! it's so low level that I love it. I know it does not have any sense haah.
My idea of learning this language is developing several little programs. This one has the objective of checking computer's ip in www.whatismyip.com and save the new ip in some file called "iplog". It would be like carrying out an "ip log".
Well, your answer was very complete and now you cleared me up the idea. What do you think if I try to solve that with sockets...? Will be very difficult? I have developed socket with c once, but I think I have to revise the theory. You named "sys_socketcall ".. is there any documentation that you can recommend me? (meanwhile I'm searching on the Internet).
About the other suggestions, I am trying to learn GnuAssembler in Linux obviously.
well, thank you so much for your answer,
thank P1ranha as well !
Best,
Marce
My idea of learning this language is developing several little programs. This one has the objective of checking computer's ip in www.whatismyip.com and save the new ip in some file called "iplog". It would be like carrying out an "ip log".
Well, your answer was very complete and now you cleared me up the idea. What do you think if I try to solve that with sockets...? Will be very difficult? I have developed socket with c once, but I think I have to revise the theory. You named "sys_socketcall ".. is there any documentation that you can recommend me? (meanwhile I'm searching on the Internet).
About the other suggestions, I am trying to learn GnuAssembler in Linux obviously.
well, thank you so much for your answer,
thank P1ranha as well !
Best,
Marce
Ahhh... documentation... For an overview of what we're trying to do, "Beej's Guide to Network Programming" is good...
http://beej.us/guide/bgnet/
... not really directed at assembly language...
To get more specific, you could do "man 2 socketcall". That doesn't really tell us much. "man 2 socket", man 2 connect", etc. give more information. Not really aimed at asm either, of course...
I'm still at the earliest stages of figuring out what we want to do. If I use the "regular wget":
I end up with "index.html", which includes the IP we're looking for... and a lot of other stuff which isn't really helpful. Their page mentions another page for "automation":
http://automation.whatismyip.com/n09230945.asp
When I try "wget" on that, I get "ERROR 403: Forbidden". If I just "click on it", I get my IP without any surrounding cruft. I think that page may be "interesting", but I'm not sure how we want to use it...
The general idea, I think, will be sys_socket (or socket() if you like C libraries), sys_connect (or connect()). At this point, we'll need to know the IP for whatismyip.com or their automation page. gethostbyname() should do it. What I usually do is "ping thename" and copy down the "dotted quad" that it tells me. :) The actual parameter wants to be bigendian(!). Then we may need to send something - sys_socketcall with "send" as an argument, or just sys_write will work. Or maybe, if we hit that "automation" page, it'll send what we want without asking (we should be so lucky), and we can just "recv" (sys_socketcall with "recv" in ebx) or sys_read... Have to try it to see what happens...
I haven't written any code yet. If I can stay "focused", I will. I'll be doing it in Nasm, probably - first, to get it working, at least. Then I'll "translate" to (G)as - "objdump -d myprog" presents AT&T syntax, which will help...
I don't think it'll be too difficult, but I'm short of ambition lately (I've always been short of ambition, but it's getting worse!), so don't wait for me! Try out anything you can think of!
Later,
Frank
http://beej.us/guide/bgnet/
... not really directed at assembly language...
To get more specific, you could do "man 2 socketcall". That doesn't really tell us much. "man 2 socket", man 2 connect", etc. give more information. Not really aimed at asm either, of course...
I'm still at the earliest stages of figuring out what we want to do. If I use the "regular wget":
wget www.whatsmyip.com
I end up with "index.html", which includes the IP we're looking for... and a lot of other stuff which isn't really helpful. Their page mentions another page for "automation":
http://automation.whatismyip.com/n09230945.asp
When I try "wget" on that, I get "ERROR 403: Forbidden". If I just "click on it", I get my IP without any surrounding cruft. I think that page may be "interesting", but I'm not sure how we want to use it...
The general idea, I think, will be sys_socket (or socket() if you like C libraries), sys_connect (or connect()). At this point, we'll need to know the IP for whatismyip.com or their automation page. gethostbyname() should do it. What I usually do is "ping thename" and copy down the "dotted quad" that it tells me. :) The actual parameter wants to be bigendian(!). Then we may need to send something - sys_socketcall with "send" as an argument, or just sys_write will work. Or maybe, if we hit that "automation" page, it'll send what we want without asking (we should be so lucky), and we can just "recv" (sys_socketcall with "recv" in ebx) or sys_read... Have to try it to see what happens...
I haven't written any code yet. If I can stay "focused", I will. I'll be doing it in Nasm, probably - first, to get it working, at least. Then I'll "translate" to (G)as - "objdump -d myprog" presents AT&T syntax, which will help...
I don't think it'll be too difficult, but I'm short of ambition lately (I've always been short of ambition, but it's getting worse!), so don't wait for me! Try out anything you can think of!
Later,
Frank
Frank, thank you for the documentation!!!
Regarding to:
yes I knew that! I realised yesterday haha
I did that, without libraries and with syscalls :)
Now, I'm trying to figure out the "connect" function. We have int sys_connect(int fd, struct sockaddr *uservaddr, int addrlen). I have to "translate" the parameters into assembly.... (a challenge for me). After this, I'm going to follow your recommendations:
Thank u so much!!!!! ;)
p.s: I'm reading tcp/ip sockets in c second edition practical guide for programmers by Morgan Kaufman
Regarding to:
I end up with "index.html", which includes the IP we're looking for... and a lot of other stuff which isn't really helpful. Their page mentions another page for "automation":
http://automation.whatismyip.com/n09230945.asp
http://automation.whatismyip.com/n09230945.asp
yes I knew that! I realised yesterday haha
The general idea, I think, will be sys_socket (or socket() if you like C libraries), sys_connect (or connect())
I did that, without libraries and with syscalls :)
movl $2,(%esp) #af_inet
movl $1,4(%esp) #sock-stream
movl $6,8(%esp) #ipprotocp
movl $102,%eax #socketcall
movl $1,%ebx #socketcall_socket
movl %esp,%ecx
int $0x80
Now, I'm trying to figure out the "connect" function. We have int sys_connect(int fd, struct sockaddr *uservaddr, int addrlen). I have to "translate" the parameters into assembly.... (a challenge for me). After this, I'm going to follow your recommendations:
gethostbyname() should do it. What I usually do is "ping thename" and copy down the "dotted quad" that it tells me. :) The actual parameter wants to be bigendian(!). Then we may need to send something - sys_socketcall with "send" as an argument, or just sys_write will work. Or maybe, if we hit that "automation" page, it'll send what we want without asking (we should be so lucky), and we can just "recv" (sys_socketcall with "recv" in ebx) or sys_read... Have to try it to see what happens...
Thank u so much!!!!! ;)
p.s: I'm reading tcp/ip sockets in c second edition practical guide for programmers by Morgan Kaufman
Good start! I've got something similar - I've got 0 where you've got 6 - IPv4 vs IPv6, I suspect(?). Trying a similar idea with "connect" - arguments on the stack. I'm getting a plausible descriptor from "socket" and 0 from "connect", but "broken pipe" if I try to read/write. Just woke up from a nap realizing, "Wait a minute, 'port 80' is decimal!" I've been using 80 hex. :( Duh!
I really may have to RTFM on this. (it puts me to sleep, but if I can't stay awake anyway, might as well...) :)
Coffee first, then I'll get back into it...
Best,
Frank
I really may have to RTFM on this. (it puts me to sleep, but if I can't stay awake anyway, might as well...) :)
Coffee first, then I'll get back into it...
Best,
Frank
Hi Frank, yes I've got 6, I'm using IPv4. I have searched on the Internet some examples about "connect" function and I have some doubts. This is the code:
The questions are:
why do we move only a word in af_inet and port? I remember that in "socketcall function" I did that:
I moved a double word. I would like to understand in which occasion do we have to send 32 bits or 16 bits.
Besides I really don't know how can I calculate the size of the sock address. In the example I could see that
I follow the code to understand what it was looking for in 12(%esp).
It was looking for the af_inet. So, I concluded that it calculates the size through the address family, IPv4. However, I don't think that this represents the size the sock address at all.
what's your opinion?
Thanx in advance!
try italian coffee! ;) it's the best
movl $102 %eax #socketcall
movw $2, 12(%esp) #af_inet
movw $80, 14(%esp) #port
movl $0x48e959c7, 16(%esp) # ip
movl %eax, (%esp) #fd
...
..
The questions are:
why do we move only a word in af_inet and port? I remember that in "socketcall function" I did that:
movl $2,(%esp) #af_inet
I moved a double word. I would like to understand in which occasion do we have to send 32 bits or 16 bits.
Besides I really don't know how can I calculate the size of the sock address. In the example I could see that
leal 12(%esp),%ebx
movl %ebx,0x4(%esp)
I follow the code to understand what it was looking for in 12(%esp).
movw $2, 12(%esp)#af_inet
It was looking for the af_inet. So, I concluded that it calculates the size through the address family, IPv4. However, I don't think that this represents the size the sock address at all.
what's your opinion?
Thanx in advance!
try italian coffee! ;) it's the best
I should have had the Italian coffee! Instant with a bit of cocoa-mix, a spinkle of cinnamon, hot water from the tap, is quick, but didn't seem to do the trick. Changing "port" to 80 decimal didn't help. What I actually did was:
Supposed to be a word af_inet and a word (big-endian) port. Still got "broken pipe". So I backed up to something a little less "minimal" and used a static structure...
That's Nasm syntax, but I think you can see that "family" and "port" are words... and then there's some padding at the end, which makes the "size" 16 bytes. I think that's what we want to pass to "connect". It's supposed to be (the "original" structure) in "sys/socket.h" (which includes "bits/socket.h") but I can't find anything just like that...
I didn't actually use the Nasm "struc", since I don't know how to translate it to (G)as. Here's my code, so far. Note that this DOES NOT WORK:
That gets me as far as writing the "GET" message (apparently successfully(?), but the "read" doesn't read anything, just hangs there. Apparently I said something to offend the server...
I don't know what to try next. RTFM, if all else fails, I guess... :)
Best,
Frank
push 25000h
Supposed to be a word af_inet and a word (big-endian) port. Still got "broken pipe". So I backed up to something a little less "minimal" and used a static structure...
struc sockaddr_in
.sin_family resw 1
.sin_port resw 1
.sin_addr resd 1
.sin_zero resb 8
endstruc
That's Nasm syntax, but I think you can see that "family" and "port" are words... and then there's some padding at the end, which makes the "size" 16 bytes. I think that's what we want to pass to "connect". It's supposed to be (the "original" structure) in "sys/socket.h" (which includes "bits/socket.h") but I can't find anything just like that...
I didn't actually use the Nasm "struc", since I don't know how to translate it to (G)as. Here's my code, so far. Note that this DOES NOT WORK:
global _start
; Convert numbers (constants!) to network byte order
%define hton(x) ((x & 0xFF000000) >> 24) | ((x & 0x00FF0000) >> 8) | ((x & 0x0000FF00) << 8) | ((x & 0x000000FF) << 24)
%define htons(x) ((x >> 8) & 0xFF) | ((x & 0xFF) << 8)
section .data
iptext db "72.233.89.198", 0 ; www.whatismyip.com
; iptext db "198.89.233.72", 0 ; automation.whatismyip.com
iplittle dd 48E959C6h
ipbig dd 0C659E948h
; ipbig dd 48E959C6h
; copied from Nathan's (working) program
msg db"GET /index.html HTTP/1.1", 13, 10
db "Host: www.whatismyip.com", 13, 10
db "Connection: close", 13, 10
db "User-Agent: assembly language", 13, 10
msg_len equ $ - msg
sa:
dw 2 ; family
dw htons (80) ; port (big endian)
dd 0C659E948h ; address (big-endian)
dd 0, 0 ; zero
sa_size equ $ - sa
; first of these wants to be socket descriptor
; we fill it in later...
connect_args dd 0, sa, sa_size
section .bss
%define BUFSIZ 80h
buf resb BUFSIZ
sock_fd resd 1
section .text
_start:
nop
; socket
push 0
push 1
push 2
mov ecx, esp
mov ebx, 1
mov eax, 102
int 80h
add esp, 12
test eax, eax
js exit
mov , eax
mov , eax
; connect
mov ecx, connect_args
mov ebx, 3 ; connect
mov eax, 102
int 80h
add esp, 28
test eax, eax
js exit
; write
mov edx, msg_len
mov ecx, msg
mov ebx,
mov eax, 4
int 80h
test eax, eax
js exit
; read
mov edx, BUFSIZ
mov ecx, buf
mov ebx,
mov eax, 3
int 80h
test eax, eax
js exit
; write to stdout
mov edx, eax ; length from read
mov ecx, buf
mov ebx, 1
mov eax, 4
int 80h
exit:
mov ebx, eax
test ebx, ebx
jns goodexit
neg ebx
goodexit:
mov eax, 1
int 80h
That gets me as far as writing the "GET" message (apparently successfully(?), but the "read" doesn't read anything, just hangs there. Apparently I said something to offend the server...
I don't know what to try next. RTFM, if all else fails, I guess... :)
Best,
Frank
Copied incorrectly(!) from Nathan's code...
Supposed to be a space between "HTTP" and "/". This gets me to "Bad Request". Progress, of a sort...
Best,
Frank
msg db"GET /index.html HTTP/1.1", 13, 10
Supposed to be a space between "HTTP" and "/". This gets me to "Bad Request". Progress, of a sort...
Best,
Frank
Hi Frank, I understood everything but in connect() function something seems to be wrong. In eax register i found 0xffffff2. An error. And I don't know what it means.
Debugging I could see that in %eax register there is a 0xffffff2 number. It's a negative number, hence there is a problem.
I searched on the Internet what it could be, I did not get nothing.
ANY IDEAS?
Thanx in advance
.section .data
ErrorMsg: .asciz"socket() failed\n"
.section .text
.globl _start
_start:
#Creating a reliable, stream socket TCP
#parameters
movl $2, (%esp) #af_inet
movl $1, 4(%esp) #sock-stream
movl $6, 8(%esp) #ipprotocp
movl $102,%eax #socketcall
movl $1,%ebx #socketcall_socket
movl %esp,%ecx #A pointer to the syscall args is stored in %ecx.
int $0x80
cmpl $0, %eax
jl error
#Establish a connection to the server
# int fd, struct sockaddr *uservaddr, int addrlen
movl %eax, (%esp) #fd
movw $2, 12(%esp) #af_inet
movw $80, 14(%esp) #port
movl $48E959C6, 16(%esp) # ip 72.233.89.198 whatismyip
movl $16,8(%esp) # size
movl $102,%eax #socketcall
movl $3, %ebx #socketcall_connect
movl %esp, %ecx pointer to the syscall args is stored in %ecx.
int $0x80
cmpl $0, %eax
jl error
jmp endprogram
error: pushl $ErrorMsg
call printf
jmp endprogram
endprogram:
movl $1, %eax
movl $0, %ebx
int $0x80
Debugging I could see that in %eax register there is a 0xffffff2 number. It's a negative number, hence there is a problem.
I searched on the Internet what it could be, I did not get nothing.
ANY IDEAS?
Thanx in advance
I'm fast running out of ideas!
0xfffffff2, according to my half-fast arithmetic, should be -EFAULT ("bad address"). These parameters to "connect" are confusing! We want the address (and length) of this "sockaddr" structure... as a part of the "parameter structure" we put in %ecx. I made the following changes to your code, in order to attempt to do this...
This changes the error return (in %eax) to 0xffffff9f, which I decrypt as -97 or -EAFNOSUPPORT - "address family not supported by protocol".
I was getting this same error from my code when I was attempting to put all the parameters (the "sockaddr" structure, and the pointer/size to it... plus the fd) on the stack. When I changed this to a "static" sockaddr structure (as shown in the last code I posted above... in Nasm syntax), "connect" returned zero, as I understand it's supposed to do. However, when I attempted to "write" a "request" and "read" back the reply, either the "read" hangs and doesn't get anything, or if I change the "request" I'm writing I "read" back "ERROR 400: Bad Request...".
My "request":
As nearly as I can get from the RFC (2616? I forget the number), there isn't supposed to be a space in "HTTP(space?)/1.1". Without the space, the "read" hangs, and with the space, "bad request". Dunno what to try next.
I have some code which attempts to put those negative numbers into text (just the comments in errno.h). Sort of like "perror()"? I just cut-and-paste it into my code. I should attempt to assemble it into a freestanding .o file which could be linked with... your code, my code, anything. Haven't done so yet. It might help you with error returns from "connect", but it isn't any help with "bad request"!
I use it in a macro:
Where, if there's an error, it prints the text "we are here", then the text from errno.h and jumps to the second parameter - could be "retry" or something instead of "exit"...
I think this code has "promise", but it isn't really "finished" yet. I'll try to post it, in some form, soon(ish). It will/would be a PITA to translate to AT&T syntax, so might not be much help to you.
Other than that... no, I don't have any ideas...
Best,
Frank
0xfffffff2, according to my half-fast arithmetic, should be -EFAULT ("bad address"). These parameters to "connect" are confusing! We want the address (and length) of this "sockaddr" structure... as a part of the "parameter structure" we put in %ecx. I made the following changes to your code, in order to attempt to do this...
.section .data
ErrorMsg: .asciz"socket() failed\n"
.section .text
.globl _start
_start:
#Creating a reliable, stream socket TCP
#parameters
movl $2, (%esp) #af_inet
movl $1, 4(%esp) #sock-stream
# no help either way, here!
# movl $6, 8(%esp) #ipprotocp
movl $0, 8(%esp) #ipprotocp
movl $102,%eax #socketcall
movl $1,%ebx #socketcall_socket
movl %esp,%ecx #A pointer to the syscall args is stored in %ecx.
int $0x80
cmpl $0, %eax
jl error
#Establish a connection to the server
# int fd, struct sockaddr *uservaddr, int addrlen
movl %eax, (%esp) #fd
movw $2, 12(%esp) #af_inet
# attempt to do 80, big-endian
movw $0x5000, 14(%esp) #port
movl $0x48E959C6, 16(%esp) # ip 72.233.89.198 whatismyip
movl $16,8(%esp) # size
leal 8(%esp), %ecx # <-- addr of sockaddr
movl %ecx, 4(%esp) # <--
movl $102,%eax #socketcall
movl $3, %ebx #socketcall_connect
movl %esp, %ecx # pointer to the syscall args is stored in %ecx.
int $0x80
cmpl $0, %eax
jl error
jmp endprogram
error: pushl $ErrorMsg
call printf
jmp endprogram
endprogram:
movl $1, %eax
movl $0, %ebx
int $0x80
This changes the error return (in %eax) to 0xffffff9f, which I decrypt as -97 or -EAFNOSUPPORT - "address family not supported by protocol".
I was getting this same error from my code when I was attempting to put all the parameters (the "sockaddr" structure, and the pointer/size to it... plus the fd) on the stack. When I changed this to a "static" sockaddr structure (as shown in the last code I posted above... in Nasm syntax), "connect" returned zero, as I understand it's supposed to do. However, when I attempted to "write" a "request" and "read" back the reply, either the "read" hangs and doesn't get anything, or if I change the "request" I'm writing I "read" back "ERROR 400: Bad Request...".
My "request":
msg db"GET /index.html HTTP/1.1", 13, 10
db "Host: www.whatismyip.com", 13, 10
db "Connection: close", 13, 10
db "User-Agent: assembly language", 13, 10
msg_len equ $ - msg
As nearly as I can get from the RFC (2616? I forget the number), there isn't supposed to be a space in "HTTP(space?)/1.1". Without the space, the "read" hangs, and with the space, "bad request". Dunno what to try next.
I have some code which attempts to put those negative numbers into text (just the comments in errno.h). Sort of like "perror()"? I just cut-and-paste it into my code. I should attempt to assemble it into a freestanding .o file which could be linked with... your code, my code, anything. Haven't done so yet. It might help you with error returns from "connect", but it isn't any help with "bad request"!
I use it in a macro:
int 80h
checkerror "we are here", exit
Where, if there's an error, it prints the text "we are here", then the text from errno.h and jumps to the second parameter - could be "retry" or something instead of "exit"...
I think this code has "promise", but it isn't really "finished" yet. I'll try to post it, in some form, soon(ish). It will/would be a PITA to translate to AT&T syntax, so might not be much help to you.
Other than that... no, I don't have any ideas...
Best,
Frank
See if this will work for you...
In Nasm, we'd have to declare "extern report_error", but Gas seems to assume that, so just call it.
Since we're not calling printf anymore, the rest of the "ld cruft" is no longer required! Ain't that nice? :)
If it doesn't work, give a holler and we'll see if we can sort it out. (warning: unzips to current directory)
Best,
Frank
In Nasm, we'd have to declare "extern report_error", but Gas seems to assume that, so just call it.
as -o iplog2.o iplog2.s
ld -o iplog2 iplog2.o rpterror.o
Since we're not calling printf anymore, the rest of the "ld cruft" is no longer required! Ain't that nice? :)
If it doesn't work, give a holler and we'll see if we can sort it out. (warning: unzips to current directory)
Best,
Frank
The following C code shows how to set up sockaddr prior to successfully calling connect():
They key piece is the htons() macro which converts host endianess to network endianess. If you're writing an app on a PC the host endianess is little endian. Network endian is big endian.
Also, this is the correct command: GET /index.html HTTP/1.1
struct sockaddr_in sockAddr; /* socket address structure */
sockAddr.sin_family = AF_INET;
sockAddr.sin_port = htons(nProtocolPort);
sockAddr.sin_addr.s_addr = inet_addr(szHost);
They key piece is the htons() macro which converts host endianess to network endianess. If you're writing an app on a PC the host endianess is little endian. Network endian is big endian.
Also, this is the correct command: GET /index.html HTTP/1.1
Well... it's a million miles from "calling C libraries in Gas", but here's a NASMX program that works...
Actually, with the latest version of NASMX-1.0rc1, it throws a couple of errors. Works with an earlier version...
Best,
Frank
; wget-like thingy
; author: Nathan Baker
; written for Windows
; modified for Linux, too: fbk
;
; nasm -f win32 nbget -i path to NASMX\
; link "as usual"
;
; for Linux
; nasm -f elf nbget.asm -i path to NASMX/
; nasm -f elf fakeapi.asm
; ld -o get nbget.o get4lin.o -e main
; swap backslashes to slashes
; I *think* Windows will accept slashes, too(?)
%ifidni __OUTPUT_FORMAT__, elf
%include '/inc/nasmx.inc'
%include '/inc/win32/windows.inc'
%include '/inc/win32/kernel32.inc'
%include '/inc/win32/user32.inc'
%include '/inc/win32/wsock32.inc'
%else
%include 'inc\nasmx.inc'
%include 'inc\win32\windows.inc'
%include 'inc\win32\kernel32.inc'
%include 'inc\win32\user32.inc'
%include 'inc\win32\wsock32.inc'
%endif
entry demo1
; Convert numbers (constants!) to network byte order
%define hton(x) ((x & 0xFF000000) >> 24) | ((x & 0x00FF0000) >> 8) | ((x & 0x0000FF00) << 8) | ((x & 0x000000FF) << 24)
%define htons(x) ((x >> 8) & 0xFF) | ((x & 0xFF) << 8)
; Nathan's server
; urltext db "75.126.1.55", 0
_popip equ 4B7E0137h
POPIP equ hton(_popip)
POPPORT equ htons(80)
BUFFSIZE equ 4096
section .bss
wsadata resb 398
hsock resd 1
resp resb BUFFSIZE
numb resd 1
remain resd 1
realsize resd 1
section .data
pop_sa istruc sockaddr_in
at sockaddr_in.sin_family, dw 2
at sockaddr_in.sin_port, dw POPPORT
at sockaddr_in.sin_addr, dd POPIP
at sockaddr_in.sin_zero, dd 0, 0
iend
msg db "GET / HTTP/1.1", 13, 10
db "Host: clax.inspiretomorrow.net" ,13 ,10
db "Connection: close", 13, 10
db "User-Agent: ASM", 13, 10, 13, 10
msg_len equ $ - msg
proc demo1
xor eax, eax
mov , eax
invoke WSAStartup, 0x101, wsadata
invoke socket, dword 2, dword 1, dword 0
mov , eax
invoke connect, eax, pop_sa, 16
invoke send, , msg, msg_len, 0
mov ecx, BUFFSIZE
mov , ecx
mov ebx, resp
back:
invoke recv, , ebx, , 0
cmp eax, 0
jz cont
mov ebx, resp
add ebx, eax
add , eax
sub , eax
jmp back
cont:
invoke closesocket,
invoke WSACleanup
invoke GetStdHandle, dword -11
invoke WriteFile, eax, dword resp, , dword numb, 0
invoke ExitProcess, dword NULL
ret
endproc
Actually, with the latest version of NASMX-1.0rc1, it throws a couple of errors. Works with an earlier version...
Best,
Frank
Frank,
Please try again with the official NASMX-1.0 release.
Let me know if you are successful or what errors you receive and I'll look into it further.
Thank you.
Please try again with the official NASMX-1.0 release.
Let me know if you are successful or what errors you receive and I'll look into it further.
Thank you.
Hi Rob,
line 60 - non-constant argument to TIMES (iend)
line 72 - fatal: (INVOKE: 9) missing locals directive (invoke WSAstartup...)
Same as rc1, FWIW. I don't know whether the errors are in the source, or in one of the include files - I suspect the former, the source "looks okay" to me... but I'm not very familiar with NASMX...
As I think you know, I prefer "very low level" asm myself, but I think NASMX is a "good idea... if you wanna do it that way". If I get hit with an unexpected stroke of ambition, I'll contribute something to the Linux branch.
One of these days, I've gotta get organized! :)
Best,
Frank
P.S. I suppose I should attach that "fakeapi.asm" in case anyone wants it...
P.P.S. This may deserve a new topic, if we're going to persue it...
line 60 - non-constant argument to TIMES (iend)
line 72 - fatal: (INVOKE: 9) missing locals directive (invoke WSAstartup...)
Same as rc1, FWIW. I don't know whether the errors are in the source, or in one of the include files - I suspect the former, the source "looks okay" to me... but I'm not very familiar with NASMX...
As I think you know, I prefer "very low level" asm myself, but I think NASMX is a "good idea... if you wanna do it that way". If I get hit with an unexpected stroke of ambition, I'll contribute something to the Linux branch.
One of these days, I've gotta get organized! :)
Best,
Frank
P.S. I suppose I should attach that "fakeapi.asm" in case anyone wants it...
P.P.S. This may deserve a new topic, if we're going to persue it...
This one's easy: a proc always requires a locals macro to immediately follow.
The invoke macro fatals if locals is not specified since it's locals job to ensure the procedure stack frame prologue is set up properly. It has to be done this way as NASMX has to work within the Nasm macro capabilities while accounting for all calling conventions on all supported operating systems.
proc demo1
locals none
.
. your code
.
endproc
The invoke macro fatals if locals is not specified since it's locals job to ensure the procedure stack frame prologue is set up properly. It has to be done this way as NASMX has to work within the Nasm macro capabilities while accounting for all calling conventions on all supported operating systems.
Okay, that fixes that one, thanks!
I've still got a problem with "iend". I thought to try it with "-f win32" to see if that made any difference. Of course, that (re)enabled backslashes, so it wouldn't open the include file(s). Commented out that cruft (can you confirm that Windows still copes with slashes?), and another error cropped up. Probably a typo on my part, that one.
Any insight into the "iend" problem? As expected, adding the "-e" switch doesn't help much, but indicates a possible problem at line 358-360 - size_t not (yet) defined(?). I think this is probably an artifact of the "-e" switch only doing one pass(?)...
Thanks for your help with this!
Best,
Frank
Here's the "current" version, just for reference:
I've still got a problem with "iend". I thought to try it with "-f win32" to see if that made any difference. Of course, that (re)enabled backslashes, so it wouldn't open the include file(s). Commented out that cruft (can you confirm that Windows still copes with slashes?), and another error cropped up. Probably a typo on my part, that one.
Any insight into the "iend" problem? As expected, adding the "-e" switch doesn't help much, but indicates a possible problem at line 358-360 - size_t not (yet) defined(?). I think this is probably an artifact of the "-e" switch only doing one pass(?)...
Thanks for your help with this!
Best,
Frank
Here's the "current" version, just for reference:
; wget-like thingy
; author; Nathan Baker
; written for Windows
; modified for Linux, too: fbk
;
; nasm -f win32 nbget -i path to NASMX\
; link "as usual"
;
; for Linux
; nasm -f elf nbget.asm -i path to NASMX/
; nasm -f elf fakeapi.asm
; ld -o get nbget.o get4lin.o -e main
; swap backslashes to slashes
; I *think* Windows will accept shashes, too(?)
; %ifidni __OUTPUT_FORMAT__, elf
%include '/inc/nasmx.inc'
%include '/inc/win32/windows.inc'
%include '/inc/win32/kernel32.inc'
%include '/inc/win32/user32.inc'
%include '/inc/win32/wsock32.inc'
;%else
;%include 'inc\nasmx.inc'
;%include 'inc\win32\windows.inc'
;%include 'inc\win32\kernel32.inc'
;%include 'inc\win32\user32.inc'
;%include 'inc\win32\wsock32.inc'
;%endif
entry demo1
; Convert numbers (constants!) to network byte order
%define hton(x) ((x & 0xFF000000) >> 24) | ((x & 0x00FF0000) >> 8) | ((x & 0x0000FF00) << 8) | ((x & 0x000000FF) << 24)
%define htons(x) ((x >> 8) & 0xFF) | ((x & 0xFF) << 8)
; Nathan's server
; urltext db "75.126.1.55", 0
_popip equ 4B7E0137h
POPIP equ hton(_popip)
POPPORT equ htons(80)
BUFFSIZE equ 4096
section .bss
wsadata resb 398
hsock resd 1
resp resb BUFFSIZE
numb resd 1
remain resd 1
realsize resd 1
section .data
pop_sa istruc sockaddr_in
at sockaddr_in.sin_family, dw 2
at sockaddr_in.sin_port, dw POPPORT
at sockaddr_in.sin_addr, dd POPIP
at sockaddr_in.sin_zero, dd 0, 0
iend
msg db "GET / HTTP/1.1", 13, 10
db "Host: clax.inspiretomorrow.net" ,13 ,10
db "Connection: close", 13, 10
db "User-Agent: ASM", 13, 10, 13, 10
msg_len equ $ - msg
proc demo1
locals none
xor eax, eax
mov , eax
invoke WSAStartup, 0x101, wsadata
invoke socket, dword 2, dword 1, dword 0
mov , eax
invoke connect, eax, pop_sa, 16
invoke send, , msg, msg_len, 0
mov ecx, BUFFSIZE
mov , ecx
mov ebx, resp
back:
invoke recv, , ebx, , 0
cmp eax, 0
jz cont
mov ebx, resp
add ebx, eax
add , eax
sub , eax
jmp back
cont:
invoke closesocket,
invoke WSACleanup
invoke GetStdHandle, dword -11
invoke WriteFile, eax, dword resp, , dword numb, 0
invoke ExitProcess, dword NULL
ret
endproc
Here's modified source that assembles without error.
Please see my comments marked as RN:
Note that I did not have time to debug this,
I only nasmxified it :)
And the makefile I used for a Windows build:
(Note I named the source file above "wgetx.asm")
Please see my comments marked as RN:
Note that I did not have time to debug this,
I only nasmxified it :)
; wget-like thingy
; author; Nathan Baker
; written for Windows
; modified for Linux, too: fbk
;
; nasm -f win32 nbget -i path to NASMX\
; link "as usual"
;
; for Linux
; nasm -f elf nbget.asm -i path to NASMX/
; nasm -f elf fakeapi.asm
; ld -o get nbget.o get4lin.o -e main
; swap backslashes to slashes
; I *think* Windows will accept shashes, too(?)
; RN: Nasm accepts either for %include in your source
; at least with recent versions of Nasm. However,
; anything that reads/writes to disk must use the
; backslash in the path. It's best to simply
; always follow the host convention.
; RN: assuming you've set environment:
; Windows: set NASMENV=-IC:\path\to\nasmx\inc\
; Linux: export NASMENV=-I/path/to/nasm/inc/
%ifidni __OUTPUT_FORMAT__, elf
%include 'nasmx.inc'
%include 'win32/windows.inc'
%include 'win32/kernel32.inc'
%include 'win32/user32.inc'
%include 'win32/winsock.inc'
%include 'win32/wsock32.inc'
%else
%include 'nasmx.inc'
%include 'win32\windows.inc'
%include 'win32\kernel32.inc'
%include 'win32\user32.inc'
;
; RN: There is an easily corrected bug in winsock.inc
; find the line containing
; typedef SOCKET, size_t
; and replace with
; %xdefine SOCKET size_t
;
%include 'win32\winsock.inc'
%include 'win32\wsock32.inc'
%endif
entry demo1
;
; RN: Windows exposes htons as a function,
; thus to use your own hton macros you must
; comment out the htonl and htons imports in wsock32.inc
;
; Convert numbers (constants!) to network byte order
%define hton(x) ((x & 0xFF000000) >> 24) | ((x & 0x00FF0000) >> 8) | ((x & 0x0000FF00) << 8) | ((x & 0x000000FF) << 24)
%define htons(x) ((x >> 8) & 0xFF) | ((x & 0xFF) << 8)
; Nathan's server
; urltext db "75.126.1.55", 0
_popip equ 4B7E0137h
POPIP equ hton(_popip)
POPPORT equ htons(80)
BUFFSIZE equ 4096
section .bss
wsadata resb 398
hsock resd 1
resp resb BUFFSIZE
numb resd 1
remain resd 1
realsize resd 1
section .data
;pop_sa istruc sockaddr_in
; at sockaddr_in.sin_family, dw 2
; at sockaddr_in.sin_port, dw POPPORT
; at sockaddr_in.sin_addr, dd POPIP
; at sockaddr_in.sin_zero, dd 0, 0
;iend
; RN: Yes, it's ugly but it permits access
; to nested strucs and unions
NASMX_ISTRUC pop_sa, SOCKADDR_IN
NASMX_AT sin_family, AF_INET
NASMX_AT sin_port, POPPORT
NASMX_ISTRUC sin_addr, IN_ADDR
NASMX_AT S_un.S_addr, POPIP
NASMX_IENDSTRUC
NASMX_IENDSTRUC
msg db "GET / HTTP/1.1", 13, 10
db "Host: clax.inspiretomorrow.net" ,13 ,10
db "Connection: close", 13, 10
db "User-Agent: ASM", 13, 10, 13, 10
msg_len equ $ - msg
proc demo1
locals none
xor eax, eax
mov dword , eax
invoke WSAStartup, 0x101, wsadata
invoke socket, 2, 1, 0
mov size_t , eax
invoke connect, eax, pop_sa, 16
invoke send, size_t , msg, msg_len, 0
mov ecx, BUFFSIZE
mov dword , ecx
mov ebx, resp
back:
invoke recv, size_t , ebx, dword , 0
cmp eax, 0
jz cont
mov ebx, resp
add ebx, eax
add , eax
sub , eax
jmp back
cont:
invoke closesocket, size_t
invoke WSACleanup
invoke GetStdHandle, dword -11
invoke WriteFile, eax, dword resp, dword , dword numb, 0
invoke ExitProcess, dword NULL
endproc
And the makefile I used for a Windows build:
(Note I named the source file above "wgetx.asm")
##### Makefile #####
NAME=wgetx
AS=nasm
AFLAGS=-f win32
#AFLAGS=-f win32 -dUNICODE=1
LD=GoLink
LDFLAGS =/entry _main
LIBS =kernel32.dll user32.dll wsock32.dll
# [ Suffixes ]
# Change the suffixes to match your system environment
O = .obj
X = .exe
ASM = .asm
INC = .inc
LST = .lst
# rules
all: $(NAME)$(X)
$(NAME): $(NAME)$(X)
$(NAME)$(X): $(NAME)$(O)
$(LD) $(LDFLAGS) $(NAME)$(O) $(LIBS)
$(NAME)$(O): $(NAME)$(ASM)
$(AS) $(AFLAGS) $(NAME)$(ASM) -o $(NAME)$(O) -l $(NAME)$(LST)
clean:
-del /f *.obj
-del /f *.lst
cleaner:
-del /f *.bak
-del /f *.lst
-del /f *.obj
-del /f *.exe
##### End Makefile #####