feat: add libc

This commit is contained in:
Haolan
2025-08-25 19:05:30 +08:00
parent ddc61adc63
commit 5587fd2885
11 changed files with 638 additions and 8 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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"),
}
}

View File

@@ -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"`

View File

@@ -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
}

View File

@@ -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";

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;
*/

View File

@@ -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;