why is:

(load "t1.scm")
(define x 20)

valid, where as:

(define-macro (foo)
 (load "t1.scm")
 (define x 20))

result in a ill-placed define error?

This is not a problem specific to macros, the same error would happen if you did

(define (foo)
 (load "t1.scm")
 (define x 20))

That would fail, as would

(lambda ()
 (load "t1.scm")
 (define x 20))

, and

(lambda ()
 (+ 1 1)
 (define x 20))

. load is just a "normal" function, whereas define is a special form, and it has to be in the beginning of a scope, before any function calls are made.

I think of it as if Gambit internally converts defines within scopes to letrecs, like

(lambda () (define x 1) (define y 2) (+ x y))  =>  (lambda () (letrec ((x 1) (x 2)) (+ x y)))

Given that definition, your code above doesn't really make any sense. You could write

(lambda ()
 (load "t1.scm")
 (let ()
   (define x 20)))

or

(lambda ()
 (define x #f)
 (load "t1.scm")
 (set! x 20)))

depending on what you want.

/Per