phoenix wrote:
> Thank you guys for your responses. They' ve been very useful.
>
> I' ve made some tests today, the result is that if I leave "prog" as
> the label name and then I use the GCC "-nostdlib " parameter, a
> warning message stating that there's no _stat function appears but the
> program (or function) is correctly linked. Using "-nostdlib "
> parameter, the executable file is just 744 byte, without "-nostdlib "
> parameter the executable file is about 7 kB!
>
> My last question
Bet it isn't! :)
> is: what is the best way to write simple (addition,
> subtraction,...) STAND-ALONE assembly programs, without C libraries or
> external stuff (just pure assembly)? What about writing the code of
> the program with a _start label in it, then assembling and linking it,
> using the "-nostdlib " parameter (or using directly ld)? Or is there a
> better (or easier) way?
I think using ld directly is the easiest way. We can also use Nasm's "-f
bin" mode, and "stuff" an elf executable header on the front...
> P.S.: why the executable stops with a segmentation fault? Am I forced
> to use the syscall exit?
Yes! If you're "call"ed, say "main" being called from the "startup"
code, you can end with "ret". But the "_start" label is not called, it's
"jmp"ed to. There is no return address on the stack, the first thing on
the stack is the argument count, "argc". So a "ret" will attempt to
return to "argc" as an address - probably 1 (our program name is
"argv[0]", so "argc" is at least 1). This is outside "our" address
space, and segfaults.
Addition and subtraction are simple enough, displaying the result is
somewhat less obvious. If we send a number to stdout, it's treated as an
ascii code, and the ascii codes for the "number characters" are not the
same as the number! Fortunately, the decimal digit characters are
contiguous, so we can add '0' (the character '0', *not* the number 0 -
aka 48 decimal or 30h) to "convert" a number to its ascii code. That's
good for *one* digit, if we've got more, we need to extract 'em one at a
time. "div" will do this... there are faster ways. "div" puts the
quotient in eax, and the remainder in edx... if we "div" by ten
repeatedly, we get the digits we want, but "backwards" from the way we
want to print 'em. Simplest way to "demo" this is to use a "static"
buffer. This may be a little harder to follow, since it makes a
"tem****ary" buffer on the stack. If ya *can't* follow it, we can start
with something simpler... but you could "just use it"... ya don't know
how "printf" works either, most likely...
Best,
Frank
; nasm -f elf hwint.asm
; ld -o hwint hwint.o
global _start
section .data
hiya db "Hello, World of (real) Assembly Language!", 10
; "$", in this context, means "here", the current offset
; in the file, so this calculation counts characters.
hiya_len equ $ - hiya
ans db "InitDemo's value is "
ans_len equ $ - ans
InitDemo dd 5
section .text
_start:
mov ecx, hiya
mov edx, hiya_len
call write_stdout
mov ecx, ans
mov edx, ans_len
call write_stdout
mov eax, [InitDemo]
call showeaxd
call newline
xor eax, eax ; claim "no error".
exit:
mov ebx, eax ; error/return code in ebx (bl, actually)
mov eax, 1 ; __NR_exit
int 80h
;-----------------------
;---------------------------------
showeaxd:
pusha ; save caller's regs
sub esp, byte 10h ; make buffer on stack
lea ecx, [esp + 10h] ; start at "end" of buffer
mov ebx, 10 ; for decimal, divide by 10
xor esi, esi ; length counter
..top:
dec ecx ; work towards "front" of buffer
xor edx, edx ; "div" works with edx:eax!
div ebx ; quotient in eax, remainder in edx
add dl, '0' ; convert number to ascii char
mov [ecx], dl ; store it
inc esi ; count it
or eax, eax ; quotient zero?
jnz .top ; do more
mov edx, esi ; length in edx
call write_stdout ; print it
add esp, byte 10h ; free the buffer
popa ; restore caller's regs
ret
;---------------------------------
;-------------------
newline:
pusha
push byte 10 ; linefeed
mov ecx, esp ; stack is the buffer
mov edx, 1 ; just one
call write_stdout
add esp, byte 4 ; free buffer
popa
ret
;------------------
;------------------
write_stdout:
; expects buffer in ecx, length in edx
; trashes ebx!
mov ebx, 1 ; STDOUT
mov eax, 4 ; __NR_write
int 80h
ret
;-------------------


|