Hi nasmkid,
Well, now we know "what OS?".
"%include" essentially does a "cut-and-paste". It's one way to combine files, but probably not the one you want.
Each program wants one (and only one!) entrypoint. A .com file starts at the beginning of the file - no options. Typically, you'd need to declare "global _start" or "global main", but in "-f obj" output format (only!), Nasm knows the special symbol "..start", and knows it's supposed to be global. (other assemblers use "end foo" to declare that "foo" is the entrypoint!) This doesn't need to be the first thing in your source file - you can put subroutines first - but it'll be the first code that gets executed.
You've got a "..start" label in 1.asm:
==============================================
Contents of "1.asm"
==============================================
;--------------- my procedures ----------------
;----------------------------------------------
; procedure "r_start" start
;----------------------------------------------
r_start:
..start:
mov ax,data
mov ds,ax
mov ax,stack
mov ss,ax
mov sp,stacktop
ret
;----------------------------------------------
; procedure "r_start" end
;----------------------------------------------
When dos loads a .com file, it sets segment registers to the chosen segment - they're all the same. Not true for an .exe file - ds and es point to the "Program Segment Prefix" (a 256 byte area preceeding our actual code), so we need to correct that - I'd do es, also, although you may not need it:
..start:
mov ax,data
mov ds,ax
mov es, ax
I know the example in the Friendly Manual shows setting up ss and sp, too, but dos takes care of that for you. You're better off without it, IMO (I'll remove it from the manual "one of these days"... I delay because I'm not sure why it's there - maybe there's some reason I'm not aware of...) For now, ditch that part.
Slight diversion: "call" puts the return address (the address of the next instruction after "call") on the stack. "ret" gets the return address off the stack so it knows where to "ret" to. If the return address isn't the next thing on the stack when we get to "ret", we go to the wrong place (crash, usually, although we can deliberately put a "wrong" address on the stack and "ret" to it). So... if you had managed to "call r_start" (that code doesn't ever get executed), and then meddled with sp, it wouldn't work anyway. Generally, one does not "ret" from the "..start" label - there's no return address on the stack!
Further diversion: "main" (often spelled "_main") is a special word to C. Ordinarilly, C links in some "startup code" which calls main, after putting a pointer to environment variables, a pointer to command line parameters, and the parameter count on the stack. So you can "ret" from "main". In assembly, "main" is not a "special word", so you can use it as an ordinary label. Some people like to call their entrypoint "main". Personally, I don't like to use "main" unless I've got a "C-style main" - at least a return address, and preferably "argc", "**argp", and "**envp" above it...
To get back to what you're trying to do, if you don't want to "ret" from the "..start" label, what do you want to do? That stuff in 2.asm, I guess. You don't want to call r_start - that's already been done. Say hello and exit, I guess - perhaps not at the same time. So let's make 'em into separate procedures. Declare 'em "global" (some assemblers use "public"). Since "r_print" is in 1.asm, we need to declare it "extern". "global" is for stuff in this file that needs to be visible outside this file, "extern" is for stuff outside this file that needs to be used in this file. Nasm just tells the linker about it, and the linker hooks 'em up.
;Contents of "2.asm"
;==============================================
; %include "1.asm"
global sayhi
global exit
extern r_print
; define data segment
segment data
hello db 'Hello World', 0
; define code segment
segment code
; call r_start
;-----------------------------------
sayhi:
mov si,hello
call r_print
ret
;-----------------------------------
;------------------------
exit:
mov ah,0x4c
int 0x21
; does not return
;----------------------------------
; define stack segment
segment stack stack
resb 64
Now 1.asm can look like this:
;==============================================
;Contents of "1.asm"
;==============================================
;--------------- my procedures ----------------
global r_print
extern sayhi
extern exit
segment code ; better make sure they're the same name.
;----------------------------------------------
; procedure "r_start" start
;----------------------------------------------
r_start:
..start:
mov ax,data
mov ds,ax
mov es, ax ; might as well do es, too
; mov ax,stack
; mov ss,ax
; mov sp,stacktop
; ret
call sayhi
call exit
; does not return
;----------------------------------------------
; procedure "r_start" end
;----------------------------------------------
;----------------------------------------------
; procedure "r_print" start
;----------------------------------------------
r_print:
mov ah, 02h
a:
mov dl, [si] ; move the character to 'dl' register
inc si ; increment si register
cmp dl, 0 ; compare 0 (null) is received
je b
int 21h ; print the char
jmp a ; continue to lable 'a'
b:
ret ; procedure end
;----------------------------------------------
; procedure "r_print" end
;----------------------------------------------
That's untested(!), but should work if I haven't made any errors. Actually, the "my procedures" label indicates that you probably want the "..start" label in 2.asm, as Christian suggested. You could "call r_start" as a subroutine to initialize ds (and es, if you want), but definitely don't fiddle with ss/sp or it won't return! (put the "ret" back, in that case)
Then assemble both files, and tell alink about 'em.
nasm -f obj 1.asm
nasm -f obj 2.asm
alink -oEXE -o outname.exe 1.obj 2.obj
outname
(if memory serves, alink has got kind of a weird interface: "-o" (or "/o"?) without a space after it indicates the output format - "-oEXE" may be the default - and with a space, indicates the output file name. "-entry" (or "/entry") if you want an entrypoint other than "..start". If all else fails, RTFM.)
In any case, "global" and "extern" are the keys to including procedures from other files.
Best,
Frank