From 5587fd2885c9bf29f47f5c20d6946385bb444387 Mon Sep 17 00:00:00 2001 From: Haolan Date: Mon, 25 Aug 2025 19:05:30 +0800 Subject: [PATCH] feat: add libc --- internal/crosscompile/crosscompile.go | 76 +++++++++++ internal/crosscompile/fetch.go | 42 ++++++ internal/crosscompile/libc.go | 185 ++++++++++++++++++++++++++ internal/targets/config.go | 1 + internal/targets/loader.go | 3 + targets/esp32.ld | 14 +- targets/esp32.rom.newlib-data.ld | 23 ++++ targets/esp32.rom.newlib-funcs.ld | 130 ++++++++++++++++++ targets/esp32.rom.newlib-locale.ld | 19 +++ targets/esp32.rom.newlib-nano.ld | 115 ++++++++++++++++ targets/esp32.rom.newlib-time.ld | 38 ++++++ 11 files changed, 638 insertions(+), 8 deletions(-) create mode 100644 internal/crosscompile/libc.go create mode 100644 targets/esp32.rom.newlib-data.ld create mode 100644 targets/esp32.rom.newlib-funcs.ld create mode 100644 targets/esp32.rom.newlib-locale.ld create mode 100644 targets/esp32.rom.newlib-nano.ld create mode 100644 targets/esp32.rom.newlib-time.ld diff --git a/internal/crosscompile/crosscompile.go b/internal/crosscompile/crosscompile.go index e5f302e3..a4581832 100644 --- a/internal/crosscompile/crosscompile.go +++ b/internal/crosscompile/crosscompile.go @@ -8,8 +8,11 @@ import ( "os/exec" "path/filepath" "runtime" + "slices" "strings" + "github.com/goplus/llgo/internal/clang" + "github.com/goplus/llgo/internal/env" "github.com/goplus/llgo/internal/targets" "github.com/goplus/llgo/internal/xtool/llvm" @@ -215,6 +218,70 @@ func getESPClangPlatform(goos, goarch string) string { return "" } +func getOrCompileLibc(cc, linkerName, libcName string, ccflags, exportLdFlags []string) (ldflags []string, err error) { + baseDir := filepath.Join(cacheRoot(), "crosscompile") + libcDir := filepath.Join(baseDir, libcName) + libcArchive := filepath.Join(libcDir, "libc.a") + // fast-path: compiled already + if _, err = os.Stat(libcArchive); !os.IsNotExist(err) { + ldflags = append(ldflags, "-nostdlib", "-L", libcDir, "-lc") + return ldflags, nil + } + compileConfig, err := getCompileLibcConfigByName(baseDir, libcName) + if err != nil { + return + } + tempDir, err := os.MkdirTemp("", "compile*") + if err != nil { + return + } + defer os.RemoveAll(tempDir) + + fmt.Fprintf(os.Stderr, "%s not found in LLGO_ROOT or cache, will download and compile.\n", libcDir) + if err = checkDownloadAndExtractLibc(compileConfig.Url, libcDir, compileConfig.ArchiveSrcDir); err != nil { + return + } + compileLDFlags := append(slices.Clone(exportLdFlags), compileConfig.LDFlags...) + + cfg := clang.NewConfig(cc, ccflags, compileConfig.CFlags, compileLDFlags, linkerName) + + var objFiles []string + + compiler := clang.NewCompiler(cfg) + linker := clang.NewLinker(cfg) + + compiler.Verbose = true + linker.Verbose = true + fmt.Fprintf(os.Stderr, "Start to compile libc %s to %s...\n", libcName, libcArchive) + + for _, file := range compileConfig.Files { + var tempObjFile *os.File + tempObjFile, err = os.CreateTemp(tempDir, "libc*.o") + if err != nil { + return + } + fmt.Fprintf(os.Stderr, "Compile libc file %s to %s...\n", file, tempObjFile.Name()) + + err = compiler.Compile("-o", tempObjFile.Name(), "-x", "c", "-c", file) + if err != nil { + return + } + + objFiles = append(objFiles, tempObjFile.Name()) + } + + args := []string{"-o", libcArchive} + args = append(args, objFiles...) + + err = linker.Link(args...) + if err != nil { + return + } + ldflags = append(ldflags, "-nostdlib", "-L", libcDir, "-lc") + + return +} + func use(goos, goarch string, wasiThreads bool) (export Export, err error) { targetTriple := llvm.GetTargetTriple(goos, goarch) llgoRoot := env.LLGoROOT() @@ -574,6 +641,15 @@ func useTarget(targetName string) (export Export, err error) { } ldflags = append(ldflags, "-L", env.LLGoROOT()) // search targets/*.ld + if config.Libc != "" { + var libcLDFlags []string + libcLDFlags, err = getOrCompileLibc(export.CC, export.Linker, config.Libc, ccflags, ldflags) + if err != nil { + return + } + ldflags = append(ldflags, libcLDFlags...) + } + // Combine with config flags and expand template variables export.CFLAGS = cflags export.CCFLAGS = ccflags diff --git a/internal/crosscompile/fetch.go b/internal/crosscompile/fetch.go index 3584b38f..ba000df9 100644 --- a/internal/crosscompile/fetch.go +++ b/internal/crosscompile/fetch.go @@ -8,6 +8,7 @@ import ( "net/http" "os" "os/exec" + "path" "path/filepath" "strings" "syscall" @@ -78,6 +79,47 @@ func checkDownloadAndExtractESPClang(platformSuffix, dir string) error { return nil } +func checkDownloadAndExtractLibc(url, dstDir, internalArchiveSrcDir string) error { + // Check if already exists + if _, err := os.Stat(dstDir); err == nil { + return nil + } + + // Create lock file path for the final destination + lockPath := dstDir + ".lock" + lockFile, err := acquireLock(lockPath) + if err != nil { + return fmt.Errorf("failed to acquire lock: %w", err) + } + defer releaseLock(lockFile) + + // Double-check after acquiring lock + if _, err := os.Stat(dstDir); err == nil { + return nil + } + + description := fmt.Sprintf("Libc %s", path.Base(url)) + + // Use temporary extraction directory + tempExtractDir := dstDir + ".extract" + if err := downloadAndExtractArchive(url, tempExtractDir, description); err != nil { + return err + } + defer os.RemoveAll(tempExtractDir) + + srcDir := tempExtractDir + + if internalArchiveSrcDir != "" { + srcDir = filepath.Join(tempExtractDir, internalArchiveSrcDir) + } + + if err := os.Rename(srcDir, dstDir); err != nil { + return fmt.Errorf("failed to rename libc directory: %w", err) + } + + return nil +} + // acquireLock creates and locks a file to prevent concurrent operations func acquireLock(lockPath string) (*os.File, error) { // Ensure the parent directory exists diff --git a/internal/crosscompile/libc.go b/internal/crosscompile/libc.go new file mode 100644 index 00000000..774ea390 --- /dev/null +++ b/internal/crosscompile/libc.go @@ -0,0 +1,185 @@ +package crosscompile + +import ( + "fmt" + "os" + "path/filepath" +) + +// CompileLibcConfig represents libc compilation configuration +type compileLibcConfig struct { + Url string + Name string // Libc name (e.g., "picolibc", "musl", "glibc") + Files []string // List of source files to compile + CFlags []string // C compiler flags specific to this libc + LDFlags []string // Linker flags + ArchiveSrcDir string +} + +// GetCompileLibcConfigByName retrieves libc compilation configuration by name +// Returns compilation file lists and corresponding cflags +func getCompileLibcConfigByName(baseDir, libcName string) (*compileLibcConfig, error) { + if libcName == "" { + return nil, fmt.Errorf("libc name cannot be empty") + } + libcDir := filepath.Join(baseDir, libcName) + + switch libcName { + case "picolibc": + return getPicolibcConfig(libcDir), nil + default: + return nil, fmt.Errorf("unsupported libc: %s", libcName) + } +} + +// getPicolibcConfig returns configuration for picolibc +func getPicolibcConfig(baseDir string) *compileLibcConfig { + libcIncludeDir := filepath.Join(baseDir, "libc", "include") + libmIncludeDir := filepath.Join(baseDir, "libm", "common") + localeIncludeDir := filepath.Join(baseDir, "libc", "locale") + + os.MkdirAll(baseDir, 0700) + + headerFile, _ := os.Create(filepath.Join(baseDir, "picolibc.h")) + headerFile.Close() + + return &compileLibcConfig{ + Url: "https://github.com/picolibc/picolibc/releases/download/1.8.10/picolibc-1.8.10.tar.xz", + Name: "picolibc", + Files: []string{ + filepath.Join(baseDir, "libc", "string", "bcmp.c"), + filepath.Join(baseDir, "libc", "string", "bcopy.c"), + filepath.Join(baseDir, "libc", "string", "bzero.c"), + filepath.Join(baseDir, "libc", "string", "explicit_bzero.c"), + filepath.Join(baseDir, "libc", "string", "ffsl.c"), + filepath.Join(baseDir, "libc", "string", "ffsll.c"), + filepath.Join(baseDir, "libc", "string", "fls.c"), + filepath.Join(baseDir, "libc", "string", "flsl.c"), + filepath.Join(baseDir, "libc", "string", "flsll.c"), + filepath.Join(baseDir, "libc", "string", "gnu_basename.c"), + filepath.Join(baseDir, "libc", "string", "index.c"), + filepath.Join(baseDir, "libc", "string", "memccpy.c"), + filepath.Join(baseDir, "libc", "string", "memchr.c"), + filepath.Join(baseDir, "libc", "string", "memcmp.c"), + filepath.Join(baseDir, "libc", "string", "memcpy.c"), + filepath.Join(baseDir, "libc", "string", "memmem.c"), + filepath.Join(baseDir, "libc", "string", "memmove.c"), + filepath.Join(baseDir, "libc", "string", "mempcpy.c"), + filepath.Join(baseDir, "libc", "string", "memrchr.c"), + filepath.Join(baseDir, "libc", "string", "memset.c"), + filepath.Join(baseDir, "libc", "string", "rawmemchr.c"), + filepath.Join(baseDir, "libc", "string", "rindex.c"), + filepath.Join(baseDir, "libc", "string", "stpcpy.c"), + filepath.Join(baseDir, "libc", "string", "stpncpy.c"), + filepath.Join(baseDir, "libc", "string", "strcasecmp.c"), + filepath.Join(baseDir, "libc", "string", "strcasecmp_l.c"), + filepath.Join(baseDir, "libc", "string", "strcasestr.c"), + filepath.Join(baseDir, "libc", "string", "strcat.c"), + filepath.Join(baseDir, "libc", "string", "strchr.c"), + filepath.Join(baseDir, "libc", "string", "strchrnul.c"), + filepath.Join(baseDir, "libc", "string", "strcmp.c"), + filepath.Join(baseDir, "libc", "string", "strcoll.c"), + filepath.Join(baseDir, "libc", "string", "strcoll_l.c"), + filepath.Join(baseDir, "libc", "string", "strcpy.c"), + filepath.Join(baseDir, "libc", "string", "strcspn.c"), + filepath.Join(baseDir, "libc", "string", "strerror_r.c"), + filepath.Join(baseDir, "libc", "string", "strlcat.c"), + filepath.Join(baseDir, "libc", "string", "strlcpy.c"), + filepath.Join(baseDir, "libc", "string", "strlen.c"), + filepath.Join(baseDir, "libc", "string", "strlwr.c"), + filepath.Join(baseDir, "libc", "string", "strncasecmp.c"), + filepath.Join(baseDir, "libc", "string", "strncasecmp_l.c"), + filepath.Join(baseDir, "libc", "string", "strncat.c"), + filepath.Join(baseDir, "libc", "string", "strncmp.c"), + filepath.Join(baseDir, "libc", "string", "strncpy.c"), + filepath.Join(baseDir, "libc", "string", "strndup.c"), + filepath.Join(baseDir, "libc", "string", "strnlen.c"), + filepath.Join(baseDir, "libc", "string", "strnstr.c"), + filepath.Join(baseDir, "libc", "string", "strpbrk.c"), + filepath.Join(baseDir, "libc", "string", "strrchr.c"), + filepath.Join(baseDir, "libc", "string", "strsep.c"), + filepath.Join(baseDir, "libc", "string", "strsignal.c"), + filepath.Join(baseDir, "libc", "string", "strspn.c"), + filepath.Join(baseDir, "libc", "string", "strstr.c"), + filepath.Join(baseDir, "libc", "string", "strtok.c"), + filepath.Join(baseDir, "libc", "string", "strtok_r.c"), + filepath.Join(baseDir, "libc", "string", "strupr.c"), + filepath.Join(baseDir, "libc", "string", "strverscmp.c"), + filepath.Join(baseDir, "libc", "string", "strxfrm.c"), + filepath.Join(baseDir, "libc", "string", "strxfrm_l.c"), + filepath.Join(baseDir, "libc", "string", "swab.c"), + filepath.Join(baseDir, "libc", "string", "timingsafe_bcmp.c"), + filepath.Join(baseDir, "libc", "string", "timingsafe_memcmp.c"), + filepath.Join(baseDir, "libc", "string", "strerror.c"), + filepath.Join(baseDir, "libc", "string", "wcpcpy.c"), + filepath.Join(baseDir, "libc", "string", "wcpncpy.c"), + filepath.Join(baseDir, "libc", "string", "wcscasecmp.c"), + filepath.Join(baseDir, "libc", "string", "wcscasecmp_l.c"), + filepath.Join(baseDir, "libc", "string", "wcscat.c"), + filepath.Join(baseDir, "libc", "string", "wcschr.c"), + filepath.Join(baseDir, "libc", "string", "wcscmp.c"), + filepath.Join(baseDir, "libc", "string", "wcscoll.c"), + filepath.Join(baseDir, "libc", "string", "wcscoll_l.c"), + filepath.Join(baseDir, "libc", "string", "wcscpy.c"), + filepath.Join(baseDir, "libc", "string", "wcscspn.c"), + filepath.Join(baseDir, "libc", "string", "wcsdup.c"), + filepath.Join(baseDir, "libc", "string", "wcslcat.c"), + filepath.Join(baseDir, "libc", "string", "wcslcpy.c"), + filepath.Join(baseDir, "libc", "string", "wcslen.c"), + filepath.Join(baseDir, "libc", "string", "wcsncasecmp.c"), + filepath.Join(baseDir, "libc", "string", "wcsncasecmp_l.c"), + filepath.Join(baseDir, "libc", "string", "wcsncat.c"), + filepath.Join(baseDir, "libc", "string", "wcsncmp.c"), + filepath.Join(baseDir, "libc", "string", "wcsncpy.c"), + filepath.Join(baseDir, "libc", "string", "wcsnlen.c"), + filepath.Join(baseDir, "libc", "string", "wcspbrk.c"), + filepath.Join(baseDir, "libc", "string", "wcsrchr.c"), + filepath.Join(baseDir, "libc", "string", "wcsspn.c"), + filepath.Join(baseDir, "libc", "string", "wcsstr.c"), + filepath.Join(baseDir, "libc", "string", "wcstok.c"), + filepath.Join(baseDir, "libc", "string", "wcswidth.c"), + filepath.Join(baseDir, "libc", "string", "wcsxfrm.c"), + filepath.Join(baseDir, "libc", "string", "wcsxfrm_l.c"), + filepath.Join(baseDir, "libc", "string", "wcwidth.c"), + filepath.Join(baseDir, "libc", "string", "wmemchr.c"), + filepath.Join(baseDir, "libc", "string", "wmemcmp.c"), + filepath.Join(baseDir, "libc", "string", "wmemcpy.c"), + filepath.Join(baseDir, "libc", "string", "wmemmove.c"), + filepath.Join(baseDir, "libc", "string", "wmempcpy.c"), + filepath.Join(baseDir, "libc", "string", "wmemset.c"), + filepath.Join(baseDir, "libc", "string", "xpg_strerror_r.c"), + + filepath.Join(baseDir, "libc", "stdlib", "nano-calloc.c"), + filepath.Join(baseDir, "libc", "stdlib", "nano-malloc.c"), + filepath.Join(baseDir, "libc", "stdlib", "nano-pvalloc.c"), + filepath.Join(baseDir, "libc", "stdlib", "nano-realloc.c"), + filepath.Join(baseDir, "libc", "stdlib", "nano-valloc.c"), + filepath.Join(baseDir, "libc", "stdlib", "rand.c"), + filepath.Join(baseDir, "libc", "stdlib", "srand.c"), + filepath.Join(baseDir, "libc", "stdlib", "nano-free.c"), + + filepath.Join(baseDir, "libc", "tinystdio", "printf.c"), + filepath.Join(baseDir, "libc", "tinystdio", "putchar.c"), + filepath.Join(baseDir, "libc", "tinystdio", "puts.c"), + }, + CFlags: []string{ + "-D_COMPILING_NEWLIB", + "-D_HAVE_ALIAS_ATTRIBUTE", + "-DTINY_STDIO", + "-DPOSIX_IO", + "-DFORMAT_DEFAULT_INTEGER", + "-D_IEEE_LIBM", + "-D__OBSOLETE_MATH_FLOAT=1", + "-D__OBSOLETE_MATH_DOUBLE=0", + "-D_WANT_IO_C99_FORMATS", + "-nostdlib", + "-isystem" + libcIncludeDir, + "-I" + libmIncludeDir, + "-I" + localeIncludeDir, + "-I" + baseDir, + "-I" + filepath.Join(baseDir, "libc", "tinystdio"), + }, + LDFlags: []string{"-nostdlib"}, + ArchiveSrcDir: filepath.Join("picolibc-1.8.10", "newlib"), + } +} diff --git a/internal/targets/config.go b/internal/targets/config.go index 99938e74..4071e9fe 100644 --- a/internal/targets/config.go +++ b/internal/targets/config.go @@ -16,6 +16,7 @@ type Config struct { GOARCH string `json:"goarch"` // Compiler and linker configuration + Libc string `json:"libc"` Linker string `json:"linker"` LinkerScript string `json:"linkerscript"` CFlags []string `json:"cflags"` diff --git a/internal/targets/loader.go b/internal/targets/loader.go index ebcd0c07..15687ccd 100644 --- a/internal/targets/loader.go +++ b/internal/targets/loader.go @@ -134,6 +134,9 @@ func (l *Loader) mergeConfig(dst, src *Config) { if src.GOARCH != "" { dst.GOARCH = src.GOARCH } + if src.Libc != "" { + dst.Libc = src.Libc + } if src.Linker != "" { dst.Linker = src.Linker } diff --git a/targets/esp32.ld b/targets/esp32.ld index 6818ce31..0d5de614 100644 --- a/targets/esp32.ld +++ b/targets/esp32.ld @@ -97,14 +97,6 @@ _heap_end = ORIGIN(DRAM) + LENGTH(DRAM); _stack_size = 4K; -/* From ESP-IDF: - * components/esp_rom/esp32/ld/esp32.rom.newlib-funcs.ld - * This is the subset that is sometimes used by LLVM during codegen, and thus - * must always be present. - */ -memcpy = 0x4000c2c8; -memmove = 0x4000c3c0; -memset = 0x4000c44c; /* From ESP-IDF: * components/esp_rom/esp32/ld/esp32.rom.libgcc.ld @@ -200,3 +192,9 @@ __umodsi3 = 0x4000c7d0; __umulsidi3 = 0x4000c7d8; __unorddf2 = 0x400637f4; __unordsf2 = 0x40063478; + +INCLUDE "targets/esp32.rom.newlib-data.ld"; +INCLUDE "targets/esp32.rom.newlib-funcs.ld"; +INCLUDE "targets/esp32.rom.newlib-locale.ld"; +INCLUDE "targets/esp32.rom.newlib-nano.ld"; +INCLUDE "targets/esp32.rom.newlib-time.ld"; diff --git a/targets/esp32.rom.newlib-data.ld b/targets/esp32.rom.newlib-data.ld new file mode 100644 index 00000000..ed5795c8 --- /dev/null +++ b/targets/esp32.rom.newlib-data.ld @@ -0,0 +1,23 @@ +/* These are the .bss/.data symbols used by newlib functions present in ESP32 ROM. + See also esp32.rom.newlib-funcs.ld for the list of general newlib functions, + and esp32.rom.newlib-nano.ld for "nano" versions of printf/scanf family of functions. + + Unlike other ROM functions and data which are exported using PROVIDE, which declares + weak symbols, newlib related functions are exported using assignment, + which declares strong symbols. This is done so that ROM functions are always + used instead of the ones provided by libc.a. + */ + +_ctype_ = 0x3ff96354; +__ctype_ptr__ = 0x3ff96350; +environ = 0x3ffae0b4; +_global_impure_ptr = 0x3ffae0b0; +__mb_cur_max = 0x3ff96530; +__sf_fake_stderr = 0x3ff96458; +__sf_fake_stdin = 0x3ff96498; +__sf_fake_stdout = 0x3ff96478; +__wctomb = 0x3ff96540; +__sfp_lock = 0x3ffae0ac; +__sinit_lock = 0x3ffae0a8; +__env_lock_object = 0x3ffae0b8; +__tz_lock_object = 0x3ffae080; diff --git a/targets/esp32.rom.newlib-funcs.ld b/targets/esp32.rom.newlib-funcs.ld new file mode 100644 index 00000000..79d5c5be --- /dev/null +++ b/targets/esp32.rom.newlib-funcs.ld @@ -0,0 +1,130 @@ +/* These are the newlib functions present in ESP32 ROM. + They should not be used when compiling with PSRAM cache workaround enabled. + See also esp32.rom.newlib-data.ld for the list of .data/.bss symbols + used by these functions, and esp32.rom.newlib-nano.ld for "nano" versions + of printf/scanf family of functions. + + Unlike other ROM functions which are exported using PROVIDE, which declares + weak symbols, newlib related functions are exported using assignment, + which declares strong symbols. This is done so that ROM functions are always + used instead of the ones provided by libc.a. + + Time functions were moved to the esp32.rom.newlib-time.ld file. + */ + +abs = 0x40056340; +__ascii_wctomb = 0x40058ef0; +atoi = 0x400566c4; +_atoi_r = 0x400566d4; +atol = 0x400566ec; +_atol_r = 0x400566fc; +bzero = 0x4000c1f4; +_cleanup = 0x40001df8; +_cleanup_r = 0x40001d48; +creat = 0x40000e8c; +div = 0x40056348; +__dummy_lock = 0x4000c728; +__dummy_lock_try = 0x4000c730; +__env_lock = 0x40001fd4; +__env_unlock = 0x40001fe0; +fclose = 0x400020ac; +_fclose_r = 0x40001fec; +fflush = 0x40059394; +_fflush_r = 0x40059320; +_findenv_r = 0x40001f44; +__fp_lock_all = 0x40001f1c; +__fp_unlock_all = 0x40001f30; +__fputwc = 0x40058da0; +fputwc = 0x40058ea8; +_fputwc_r = 0x40058e4c; +_fwalk = 0x4000c738; +_fwalk_reent = 0x4000c770; +_getenv_r = 0x40001fbc; +isalnum = 0x40000f04; +isalpha = 0x40000f18; +isascii = 0x4000c20c; +isblank = 0x40000f2c; +iscntrl = 0x40000f50; +isdigit = 0x40000f64; +isgraph = 0x40000f94; +islower = 0x40000f78; +isprint = 0x40000fa8; +ispunct = 0x40000fc0; +isspace = 0x40000fd4; +isupper = 0x40000fe8; +__itoa = 0x40056678; +itoa = 0x400566b4; +labs = 0x40056370; +ldiv = 0x40056378; +longjmp = 0x400562cc; +memccpy = 0x4000c220; +memchr = 0x4000c244; +memcmp = 0x4000c260; +memcpy = 0x4000c2c8; +memmove = 0x4000c3c0; +memrchr = 0x4000c400; +memset = 0x4000c44c; +qsort = 0x40056424; +rand = 0x40001058; +rand_r = 0x400010d4; +__sccl = 0x4000c498; +__sclose = 0x400011b8; +__seofread = 0x40001148; +setjmp = 0x40056268; +__sflush_r = 0x400591e0; +__sfmoreglue = 0x40001dc8; +__sfp = 0x40001e90; +__sfp_lock_acquire = 0x40001e08; +__sfp_lock_release = 0x40001e14; +__sinit = 0x40001e38; +__sinit_lock_acquire = 0x40001e20; +__sinit_lock_release = 0x40001e2c; +srand = 0x40001004; +__sread = 0x40001118; +__sseek = 0x40001184; +strcasecmp = 0x400011cc; +strcasestr = 0x40001210; +strcat = 0x4000c518; +strchr = 0x4000c53c; +strcmp = 0x40001274; +strcoll = 0x40001398; +strcpy = 0x400013ac; +strcspn = 0x4000c558; +strdup = 0x4000143c; +_strdup_r = 0x40001450; +strlcat = 0x40001470; +strlcpy = 0x4000c584; +strlen = 0x400014c0; +strlwr = 0x40001524; +strncasecmp = 0x40001550; +strncat = 0x4000c5c4; +strncmp = 0x4000c5f4; +strncpy = 0x400015d4; +strndup = 0x400016b0; +_strndup_r = 0x400016c4; +strnlen = 0x4000c628; +strrchr = 0x40001708; +strsep = 0x40001734; +strspn = 0x4000c648; +strstr = 0x4000c674; +__strtok_r = 0x4000c6a8; +strtok_r = 0x4000c70c; +strtol = 0x4005681c; +_strtol_r = 0x40056714; +strtoul = 0x4005692c; +_strtoul_r = 0x40056834; +strupr = 0x4000174c; +__submore = 0x40058f3c; +__swbuf = 0x40058cb4; +__swbuf_r = 0x40058bec; +__swrite = 0x40001150; +toascii = 0x4000c720; +tolower = 0x40001868; +toupper = 0x40001884; +ungetc = 0x400590f4; +_ungetc_r = 0x40058fa0; +__utoa = 0x400561f0; +utoa = 0x40056258; +wcrtomb = 0x40058920; +_wcrtomb_r = 0x400588d8; +_wctomb_r = 0x40058f14; diff --git a/targets/esp32.rom.newlib-locale.ld b/targets/esp32.rom.newlib-locale.ld new file mode 100644 index 00000000..81e22aaf --- /dev/null +++ b/targets/esp32.rom.newlib-locale.ld @@ -0,0 +1,19 @@ +/* These are the locale-related newlib functions present in ESP32 ROM. + ESP32 ROM contains newlib version 2.2.0, and these functions should not be + used when compiling with newlib version 3, since locale implementation is + different there. + + Unlike other ROM functions which are exported using PROVIDE, which declares + weak symbols, newlib related functions are exported using assignment, + which declares strong symbols. This is done so that ROM functions are always + used instead of the ones provided by libc.a. + */ + +__locale_charset = 0x40059540; +__locale_cjk_lang = 0x40059558; +localeconv = 0x4005957c; +_localeconv_r = 0x40059560; +__locale_mb_cur_max = 0x40059548; +__locale_msgcharset = 0x40059550; +setlocale = 0x40059568; +_setlocale_r = 0x4005950c; diff --git a/targets/esp32.rom.newlib-nano.ld b/targets/esp32.rom.newlib-nano.ld new file mode 100644 index 00000000..51d93a1e --- /dev/null +++ b/targets/esp32.rom.newlib-nano.ld @@ -0,0 +1,115 @@ +/* These are the printf/scanf related newlib functions present in ESP32 ROM. + These functions are compiled with newlib "nano" format option. + As such, they don's support 64-bit integer formats. + Floating point formats are supported by setting _printf_float and + _scanf_float entries in syscall table. This is done automatically + by startup code. + These functions should not be used when compiling with PSRAM cache workaround enabled. + See also esp32.rom.newlib-data.ld for the list of .data/.bss symbols + used by newlib functions, and esp32.rom.newlib-funcs.ld for the list + of general newlib functions. + + Unlike other ROM functions which are exported using PROVIDE, which declares + weak symbols, newlib related functions are exported using assignment, + which declares strong symbols. This is done so that ROM functions are always + used instead of the ones provided by libc.a. + */ + +asiprintf = 0x40056d9c; +_asiprintf_r = 0x40056d4c; +asniprintf = 0x40056cd8; +_asniprintf_r = 0x40056c64; +asnprintf = 0x40056cd8; +_asnprintf_r = 0x40056c64; +asprintf = 0x40056d9c; +_asprintf_r = 0x40056d4c; +fiprintf = 0x40056efc; +_fiprintf_r = 0x40056ed8; +fiscanf = 0x40058884; +_fiscanf_r = 0x400588b4; +fprintf = 0x40056efc; +_fprintf_r = 0x40056ed8; +fscanf = 0x40058884; +_fscanf_r = 0x400588b4; +iprintf = 0x40056978; +_iprintf_r = 0x40056944; +iscanf = 0x40058760; +_iscanf_r = 0x4005879c; +printf = 0x40056978; +_printf_common = 0x40057338; +_printf_i = 0x40057404; +_printf_r = 0x40056944; +scanf = 0x40058760; +_scanf_chars = 0x40058384; +_scanf_i = 0x4005845c; +_scanf_r = 0x4005879c; +__sfputs_r = 0x40057790; +siprintf = 0x40056c08; +_siprintf_r = 0x40056bbc; +siscanf = 0x400587d0; +_siscanf_r = 0x40058830; +sniprintf = 0x40056b4c; +_sniprintf_r = 0x40056ae4; +snprintf = 0x40056b4c; +_snprintf_r = 0x40056ae4; +sprintf = 0x40056c08; +_sprintf_r = 0x40056bbc; +__sprint_r = 0x400577e4; +sscanf = 0x400587d0; +_sscanf_r = 0x40058830; +__ssprint_r = 0x40056ff8; +__ssputs_r = 0x40056f2c; +__ssrefill_r = 0x40057fec; +__ssvfiscanf_r = 0x4005802c; +__ssvfscanf_r = 0x4005802c; +_sungetc_r = 0x40057f6c; +_svfiprintf_r = 0x40057100; +__svfiscanf_r = 0x40057b08; +_svfprintf_r = 0x40057100; +__svfscanf = 0x40057f04; +__svfscanf_r = 0x40057b08; +vasiprintf = 0x40056eb8; +_vasiprintf_r = 0x40056e80; +vasniprintf = 0x40056e58; +_vasniprintf_r = 0x40056df8; +vasnprintf = 0x40056e58; +_vasnprintf_r = 0x40056df8; +vasprintf = 0x40056eb8; +_vasprintf_r = 0x40056e80; +vfiprintf = 0x40057ae8; +_vfiprintf_r = 0x40057850; +vfiscanf = 0x40057eb8; +_vfiscanf_r = 0x40057f24; +vfprintf = 0x40057ae8; +_vfprintf_r = 0x40057850; +vfscanf = 0x40057eb8; +_vfscanf_r = 0x40057f24; +viprintf = 0x400569b4; +_viprintf_r = 0x400569e4; +viscanf = 0x40058698; +_viscanf_r = 0x400586c8; +vprintf = 0x400569b4; +_vprintf_r = 0x400569e4; +vscanf = 0x40058698; +_vscanf_r = 0x400586c8; +vsiprintf = 0x40056ac4; +_vsiprintf_r = 0x40056a90; +vsiscanf = 0x40058740; +_vsiscanf_r = 0x400586f8; +vsniprintf = 0x40056a68; +_vsniprintf_r = 0x40056a14; +vsnprintf = 0x40056a68; +_vsnprintf_r = 0x40056a14; +vsprintf = 0x40056ac4; +_vsprintf_r = 0x40056a90; +vsscanf = 0x40058740; +_vsscanf_r = 0x400586f8; + +/* _print_float and _scanf_float functions in ROM are stubs which call + real implementations in IDF through the syscall table. + As such, don't include these ROM symbols. + +_printf_float = 0x4000befc; +_scanf_float = 0x4000bf18; + +*/ diff --git a/targets/esp32.rom.newlib-time.ld b/targets/esp32.rom.newlib-time.ld new file mode 100644 index 00000000..50ec6488 --- /dev/null +++ b/targets/esp32.rom.newlib-time.ld @@ -0,0 +1,38 @@ +/* These are the newlib functions and the .bss/.data symbols necessary for these functions present in ESP32 ROM. + They should not be used when you need to solve the Y2K38 problem. + Because these functions were compiled with 32-bit width for the time_t structure. + */ + +asctime = 0x40059588; +asctime_r = 0x40000ec8; +ctime = 0x400595b0; +ctime_r = 0x400595c4; +__gettzinfo = 0x40001fcc; +__get_current_time_locale = 0x40001834; +gmtime = 0x40059848; +gmtime_r = 0x40059868; +localtime = 0x400595dc; +localtime_r = 0x400595fc; +mktime = 0x4005a5e8; +strftime = 0x40059ab4; +time = 0x40001844; +__time_load_locale = 0x4000183c; +tzset = 0x40001a1c; +_tzset_r = 0x40001a28; +__tzcalc_limits = 0x400018a0; +__tz_lock = 0x40001a04; +__tz_unlock = 0x40001a10; +/* The .bss/.data symbols necessary for these functions */ +_timezone = 0x3ffae0a0; +_tzname = 0x3ffae030; +_daylight = 0x3ffae0a4; +__month_lengths = 0x3ff9609c; + +/* These functions don't use time_t, but use other structures which include time_t. + * For example, 'struct stat' contains time_t. + */ +_isatty_r = 0x40000ea0; +__sfvwrite_r = 0x4005893c; +__smakebuf_r = 0x40059108; +__srefill_r = 0x400593d4; +__swsetup_r = 0x40058cc8;