Documentation
¶
Overview ¶
Package dl implements a pure-Go ELF dynamic loader / runtime linker for Linux amd64 and arm64. It provides dlopen/dlsym semantics: loading shared objects (.so files) at runtime, resolving symbols, performing relocations, and calling exported functions — all without cgo.
SECURITY WARNING: Loading a shared object executes arbitrary native machine code in the current process. No sandboxing is provided or claimed. Treat all .so files as untrusted unless you have independently verified them.
Quick start ¶
ld := dl.New(dl.WithRoot("/linux"))
h, err := ld.Open("libc.so.6", dl.RTLD_NOW|dl.RTLD_GLOBAL)
if err != nil { log.Fatal(err) }
defer h.Close()
addr, err := h.Sym("puts")
if err != nil { log.Fatal(err) }
dl.Call1(addr, dl.CString("hello world"))
Package dl provides a pure-Go ELF dynamic loader / runtime linker.
SECURITY WARNING: This package loads and executes native machine code from disk. Treat all .so files as untrusted unless independently verified. Loading a shared object is equivalent to executing arbitrary native code in the current process. No sandboxing is provided or claimed.
Index ¶
- Variables
- func CString(s string) ([]byte, uintptr)
- func CStringPtr(s string) uintptr
- func Call0(addr uintptr) uintptr
- func Call1(addr uintptr, a1 uintptr) uintptr
- func Call2(addr uintptr, a1, a2 uintptr) uintptr
- func Call3(addr uintptr, a1, a2, a3 uintptr) uintptr
- func Call6(addr uintptr, a1, a2, a3, a4, a5, a6 uintptr) uintptr
- type Flags
- type FormatError
- type Handle
- type LoadError
- type Loader
- type Object
- type Option
- type RelocError
- type Stats
- type SymbolError
Constants ¶
This section is empty.
Variables ¶
var ( ErrNotFound = fmt.Errorf("dl: library not found") ErrNotELF = fmt.Errorf("dl: not an ELF file") ErrWrongArch = fmt.Errorf("dl: wrong ELF machine type for this architecture") ErrSymbolNotFound = fmt.Errorf("dl: symbol not found") ErrClosed = fmt.Errorf("dl: handle is closed") ErrUnsupported = fmt.Errorf("dl: unsupported") )
Common sentinel errors.
Functions ¶
func CString ¶
CString allocates a NUL-terminated byte slice suitable for passing to C functions expecting a const char*. The returned uintptr points to the first byte. The caller must keep the returned []byte alive for the duration of the call (to prevent GC from collecting it).
Example:
s, p := dl.CString("hello")
_ = s // keep alive
dl.Call1(putsAddr, p)
func CStringPtr ¶
CStringPtr is a convenience that returns just the pointer. The caller must ensure the string stays referenced until after the native call returns. In practice, the Go compiler will keep the string argument alive.
Types ¶
type Flags ¶
type Flags uint32
Flags control how a shared object is loaded and bound.
const ( // RTLD_LAZY defers function binding until first call (PLT lazy binding). RTLD_LAZY Flags = 0x00001 // RTLD_NOW resolves all symbols before Open returns. RTLD_NOW Flags = 0x00002 // RTLD_GLOBAL makes the object's symbols available for subsequent loads. RTLD_GLOBAL Flags = 0x00100 // RTLD_LOCAL restricts symbol scope to the handle (default). RTLD_LOCAL Flags = 0x00000 // RTLD_DEEPBIND causes the loaded object to prefer its own symbols over // those in the global scope when resolving references. RTLD_DEEPBIND Flags = 0x00008 // RTLD_NODELETE prevents unloading even when refcount reaches zero. RTLD_NODELETE Flags = 0x01000 // RTLD_NOLOAD does not load the object; returns a handle only if already // loaded (useful for promoting to RTLD_GLOBAL or getting stats). RTLD_NOLOAD Flags = 0x00004 )
type FormatError ¶
FormatError is returned when an ELF file is malformed.
func (*FormatError) Error ¶
func (e *FormatError) Error() string
type Handle ¶
type Handle struct {
// contains filtered or unexported fields
}
Handle represents a loaded shared object (or group of objects for transitive dependencies). Use Sym to resolve exported symbols and Close to decrement the reference count.
func (*Handle) Close ¶
Close decrements the reference count of all objects in this handle's scope. When an object's count reaches zero, its destructors (DT_FINI_ARRAY, DT_FINI) are called and its mappings are released — in reverse dependency order.
type Loader ¶
type Loader struct {
// contains filtered or unexported fields
}
Loader holds global state for the dynamic linker: loaded objects, search paths, the global symbol scope, and caching. It is safe for concurrent use.
func (*Loader) AddSearchPath ¶
AddSearchPath appends a directory to the library search list.
func (*Loader) Objects ¶
Objects returns a deduplicated snapshot of all loaded objects for debugging. The map may contain both path and soname keys pointing to the same object; this method deduplicates by pointer identity.
func (*Loader) Open ¶
Open loads a shared object and its dependencies, applies relocations, and runs constructors. The returned Handle provides Sym/Close.
Flags control binding and scope behavior:
- RTLD_NOW: resolve all symbols immediately (default if RTLD_LAZY not set)
- RTLD_LAZY: defer PLT binding (currently resolved eagerly for correctness)
- RTLD_GLOBAL: add symbols to the global scope
- RTLD_LOCAL: keep symbols in handle-local scope (default)
- RTLD_DEEPBIND: prefer object's own symbols
- RTLD_NOLOAD: return handle only if already loaded
- RTLD_NODELETE: prevent unloading
type Object ¶
type Object struct {
// Identity
Path string // resolved filesystem path
Soname string // DT_SONAME if present
// Memory layout
Base uintptr // load bias (difference between mapped and vaddr)
MinVaddr uint64 // lowest vaddr of PT_LOAD segments
MaxVaddr uint64 // highest vaddr+memsz (page-aligned)
MapSize uintptr // total mapped region size
// Program headers (in-memory copy)
Phdrs []elf64Phdr
// Dependencies (sonames from DT_NEEDED)
Needed []string
// RPATH / RUNPATH for dependency search
Rpath string
Runpath string
// contains filtered or unexported fields
}
Object represents a single loaded ELF shared object. It contains the parsed headers, memory mappings, dynamic tables, symbol/string tables, relocation info, TLS metadata, and dependency list.
type Option ¶
type Option func(*Loader)
Option configures a Loader.
func WithLDLibraryPath ¶
func WithLDLibraryPath() Option
WithLDLibraryPath enables reading LD_LIBRARY_PATH from the environment and prepending those directories to the search list.
func WithLogger ¶
WithLogger sets a custom logger for debug output.
func WithRoot ¶
WithRoot sets an alternate filesystem root. Library search paths like /lib, /usr/lib become <root>/lib, <root>/usr/lib. Default is "/".
func WithSearchPaths ¶
WithSearchPaths adds extra directories to the default library search list.
type RelocError ¶
type RelocError struct {
Type uint32 // R_* relocation type number
Symbol string // symbol name, if any
Object string // object containing the relocation
Err error
}
RelocError is returned when a relocation cannot be applied.
func (*RelocError) Error ¶
func (e *RelocError) Error() string
func (*RelocError) Unwrap ¶
func (e *RelocError) Unwrap() error
type Stats ¶
type Stats struct {
LoadedObjects int // number of currently loaded ELF objects
TotalRelocs uint64 // total relocations applied across all objects
SymbolLookups uint64 // total symbol lookup attempts
CacheHits uint64 // symbol cache hits
}
Stats contains diagnostic counters for a Loader.
type SymbolError ¶
type SymbolError struct {
Name string
Version string // empty if unversioned
Object string // object that references the symbol
Err error
}
SymbolError is returned when a symbol cannot be resolved.
func (*SymbolError) Error ¶
func (e *SymbolError) Error() string
func (*SymbolError) Unwrap ¶
func (e *SymbolError) Unwrap() error