これは現行のコンパイラの仕様上不可能です。あきらめましょう。
#undefの使い方に問題があります。
・#undefは「定義済みマクロ」の置き換え名称を解放するプリプロセス時解決命令です。
#funcは定義済みマクロを生成するプリプロセス命令ではないので有効ではありません。
#undefは定義可能な名称の解放に対して、エラーを発行しません。
未定義の名称、本来解放できないモノに対して使用してもエラーになりません。
文法エラー扱いされる件に関しては、#undefの珍妙な動作とコードの最適化が関わってきます。
以下は、OpenHSPの動作を独自に解釈したものです。
イ.#deffunc、#moduleなどでプリプロセスがユーザー定義の名称に
新たな役割を与える場合に、名前持ちのラベルを用意する。
ロ.展開マクロ系のプリプロセス命令はコンパイラに定義を伝播しない。
#func、#deffunc等はプリプロセス命令に特定のフォーマット変換を掛けコンパイラに再送する。
ハ.#undefは名前持ちのラベルを検索対象から外す役割を担う。
コンパイラへの再送は行わない。
ニ.プリプロセス・コンパイラは生成されたラベルに対して、
被参照回数をカウントする機能を有する。
ホ.コンパイラはプリプロセスからラベル情報を受け取り、被参照回数を引き継げる。
ヘ.コンパイラは被参照回数が0回のラベルの定義プリプロセス命令に対して、
展開しない選択肢を持つ(不要コードの削除)
掲題のコードをhspcmpの実装レベルで追いかけます。
1.llmod3/llmod3.hspの内部でGetProcAddressを呼び出す命令を持ち、
実行領域(module外)にその命令呼び出しがあるため、
GetProcAddress(llmod3内)は被参照回数1以上になる。
2.掲題コードに戻り、#undefによりGetProcAddress(llmod3内)は検索対象から外れます。
なおこのとき、「コンパイラへの引き継ぎ」もされません。
3.kernel32.asの内部で#func定義があり、その後呼び出しがないため、
GetProcAddress(kernel32)は被参照回数0としてコンパイラに引き継がれます。
4.コンパイラはllmod3内のGetProcAddressの#func定義を見つけた際、
名称検索によりGetProcAddress(kernel32)を発見し、被参照回数0により、
cmpopt-optcode未規定(最適化する)に従い、この定義をスキップします。
5.llmod3内のdll_getfunc内で呼ぶGetProcAddressが未定義命令としてエラーになります。←文法エラー
cmpopt-optcodeの最適化を切る/kernel32.asのインクルード以降にGetProcAddressを呼ぶと、
4.#func命令により、GetProcAddress(llmod3)が解決コード上に乗る。
5.llmod3内のGetProcAddressが正常にコンパイルされる。
6.#undefがあった行は"undef"はコンパイラに再送されないため、GetProcAddressの名称が有効のまま進む。
7.kernel32.as内のGetProcAddressを定義する#funcによって名称二重定義となりコンパイルエラーとなります。←二重定義エラー
すでに試されてると思いますが、インクルード順を変えてもダメです。
これが本来意図した言語仕様なのか私は明確な答えを持っていない為、
バグとも仕様とも答えられません。