Re: Linking libraries?



Solar wrote:

....
extern _getenv

You've uncovered one of the dirty little secrets of the "portable" C language ! :) For ELF C, externals *don't* take the leading underscore.
The "_start" label has an underscore, but "main", "printf",... and "getenv" stay as is.

Once you've fixed that, you'll need to tell ld we're using libc. A simple "-lc" *ought* to do it, but by default, ld uses the wrong dynamic loader - /lib/ld-linux.so.1. We want /lib/ld-linux.so.2 (the former will cause a "no such file" error - just as if the program you just made didn't exist!) "-I" is a shorter alias for "--dynamic-loader", so...

ld -o path path.o -lc -I/lib/ld-linux.so.2

should put you on the right... path. :)

(you really want to name this thing just "path"?)

But there's no need to call a library to find an environment variable in a Linux program - they're right there on the stack. Easiest thing in the world...

Best,
Frank

; nasm -f elf showpath.asm
; ld -o showpath showpath.o
; [strip showpath]

section .text
global _start
_start:

; When the ELF loader loads us, command-line arguments,
; if any (there's always "argv[0]" - the program name),
; and the environment strings, are on the stack.
; Unlike a C "main" startup, we haven't been "call"ed,
; and there's been no "push ebp", so we start right off
; with "argc" at [esp]. Next ([esp + 4]) is a zero-terminated
; array of pointers to zero-terminated strings
; (command-line args), followed by a similar
; array of pointers to environment strings. No
; "count" is provided, so we have to watch for
; the terminating zero. To get directly to the
; environment variables, we start with the initial
; esp, add 4 to clear "argc", add 4 times "argc" to
; clear the command-line arguments, and another 4
; to clear the terminating zero. Thus:


mov eax, [esp] ; "argc"

; lea ebx, [esp + 8 + eax * 4]
; but we'd like to bump ebx at the *top* of our loop, so:

lea ebx, [esp + 4 + eax * 4]

..top:
add ebx, byte 4
mov esi, [ebx] ; get a pointer
test esi, esi ; watch for the end!
jz .not_found

cmp dword [esi], 'PATH' ; look for path
jnz .top
cmp byte [esi + 4], '=' ; better make sure there's
jnz .top ; not more...

call putz ; got it - print it
mov esi, newline
call putz

xor ebx, ebx ; return success
jmp short .exit

..not_found:
or ebx, byte -1 ; return failure
..exit
mov eax, 1
int 80h
;-----------------------

;-----------------------
; expects: esi -> zero-terminated string
; returns: nothing useful

putz:
pusha
mov eax, 4 ; sys_write (__NR_write)
mov ebx, 1 ; stdout
mov ecx, esi ; buffer
; length in edx
or edx, byte -1
..find_len:
cmp [ecx + edx + 1], byte 1
inc edx
jnc .find_len

int 80h
popa
ret
;-----------------------------

;-----------------------------
; this is "const" data, and should really go in
; a "readonly" section... ".text" will do, BUT!
; kernels 2.6.10 thru 2.6.16 or so require a
; writeable section last, or the loader (not
; your code) segfaults. So put it in ".data"
; for those kernels.

;section .data
newline db 10, 0

;--------------------------------


.