--- libstdc++-v3/include/std/charconv.jj	2022-10-31 22:20:39.475072806 +0100
+++ libstdc++-v3/include/std/charconv	2022-11-01 16:48:50.693196228 +0100
@@ -736,6 +736,27 @@ namespace __detail
       __value = __val;
     return __res;
   }
+#elif defined(__STDCPP_FLOAT128_T__) && defined(_GLIBCXX_HAVE_FLOAT128_MATH)
+#ifdef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT
+  __extension__ from_chars_result
+  from_chars(const char* __first, const char* __last, __ieee128& __value,
+	     chars_format __fmt = chars_format::general) noexcept;
+
+  inline from_chars_result
+  from_chars(const char* __first, const char* __last, _Float128& __value,
+	     chars_format __fmt = chars_format::general) noexcept
+  {
+    __extension__ __ieee128 __val;
+    from_chars_result __res = from_chars(__first, __last, __val, __fmt);
+    if (__res.ec == errc{})
+      __value = __val;
+    return __res;
+  }
+#else
+  from_chars_result
+  from_chars(const char* __first, const char* __last, _Float128& __value,
+	     chars_format __fmt = chars_format::general) noexcept;
+#endif
 #endif
 
 #if defined(__STDCPP_BFLOAT16_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32) \
@@ -851,6 +872,46 @@ namespace __detail
     return to_chars(__first, __last, static_cast<long double>(__value), __fmt,
 		    __precision);
   }
+#elif defined(__STDCPP_FLOAT128_T__) && defined(_GLIBCXX_HAVE_FLOAT128_MATH)
+#ifdef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT
+  __extension__ to_chars_result
+  to_chars(char* __first, char* __last, __float128 __value) noexcept;
+  __extension__ to_chars_result
+  to_chars(char* __first, char* __last, __float128 __value,
+	   chars_format __fmt) noexcept;
+  __extension__ to_chars_result
+  to_chars(char* __first, char* __last, __float128 __value,
+	   chars_format __fmt, int __precision) noexcept;
+
+  inline to_chars_result
+  to_chars(char* __first, char* __last, _Float128 __value) noexcept
+  {
+    __extension__
+    return to_chars(__first, __last, static_cast<__float128>(__value));
+  }
+  inline to_chars_result
+  to_chars(char* __first, char* __last, _Float128 __value,
+	   chars_format __fmt) noexcept
+  {
+    __extension__
+    return to_chars(__first, __last, static_cast<__float128>(__value), __fmt);
+  }
+  inline to_chars_result
+  to_chars(char* __first, char* __last, _Float128 __value,
+	   chars_format __fmt, int __precision) noexcept
+  {
+    __extension__
+    return to_chars(__first, __last, static_cast<__float128>(__value), __fmt,
+		    __precision);
+  }
+#else
+  to_chars_result to_chars(char* __first, char* __last, _Float128 __value)
+    noexcept;
+  to_chars_result to_chars(char* __first, char* __last, _Float128 __value,
+			   chars_format __fmt) noexcept;
+  to_chars_result to_chars(char* __first, char* __last, _Float128 __value,
+			   chars_format __fmt, int __precision) noexcept;
+#endif
 #endif
 
 #if defined(__STDCPP_BFLOAT16_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32)
--- libstdc++-v3/config/abi/pre/gnu.ver.jj	2022-10-31 22:20:39.475072806 +0100
+++ libstdc++-v3/config/abi/pre/gnu.ver	2022-11-01 17:00:57.682346445 +0100
@@ -2450,6 +2450,10 @@ GLIBCXX_3.4.31 {
     _ZSt21__to_chars_bfloat16_tPcS_fSt12chars_format;
     _ZSt22__from_chars_float16_tPKcS0_RfSt12chars_format;
     _ZSt23__from_chars_bfloat16_tPKcS0_RfSt12chars_format;
+    _ZSt8to_charsPcS_DF128_;
+    _ZSt8to_charsPcS_DF128_St12chars_format;
+    _ZSt8to_charsPcS_DF128_St12chars_formati;
+    _ZSt10from_charsPKcS0_RDF128_St12chars_format;
 } GLIBCXX_3.4.30;
 
 # Symbols in the support library (libsupc++) have their own tag.
--- libstdc++-v3/src/c++17/floating_from_chars.cc.jj	2022-10-31 22:20:39.476072793 +0100
+++ libstdc++-v3/src/c++17/floating_from_chars.cc	2022-11-01 16:59:23.999615740 +0100
@@ -59,6 +59,14 @@
 #endif
 // strtold for __ieee128
 extern "C" __ieee128 __strtoieee128(const char*, char**);
+#elif __FLT128_MANT_DIG__ == 113 && __LDBL_MANT_DIG__ != 113 \
+      && defined(__GLIBC_PREREQ)
+#define USE_STRTOF128_FOR_FROM_CHARS 1
+extern "C" _Float128 __strtof128(const char*, char**)
+#ifndef _GLIBCXX_HAVE_FLOAT128_MATH
+  __attribute__((__weak__))
+#endif
+  __asm ("strtof128");
 #endif
 
 #if _GLIBCXX_FLOAT_IS_IEEE_BINARY32 && _GLIBCXX_DOUBLE_IS_IEEE_BINARY64 \
@@ -618,6 +626,16 @@ namespace
 # ifdef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT
 	else if constexpr (is_same_v<T, __ieee128>)
 	  tmpval = __strtoieee128(str, &endptr);
+# elif defined(USE_STRTOF128_FOR_FROM_CHARS)
+	else if constexpr (is_same_v<T, _Float128>)
+	  {
+#ifndef _GLIBCXX_HAVE_FLOAT128_MATH
+	    if (&__strtof128 == nullptr)
+	      tmpval = _Float128(std::strtold(str, &endptr);
+	    else
+#endif
+	      tmpval = __strtof128(str, &endptr);
+	  }
 # endif
 #else
 	tmpval = std::strtod(str, &endptr);
@@ -1232,6 +1250,14 @@ from_chars(const char* first, const char
 	   chars_format fmt) noexcept
 {
   // fast_float doesn't support IEEE binary128 format, but we can use strtold.
+  return from_chars_strtod(first, last, value, fmt);
+}
+#elif defined(USE_STRTOF128_FOR_FROM_CHARS)
+from_chars_result
+from_chars(const char* first, const char* last, _Float128& value,
+	   chars_format fmt) noexcept
+{
+  // fast_float doesn't support IEEE binary128 format, but we can use strtold.
   return from_chars_strtod(first, last, value, fmt);
 }
 #endif
--- libstdc++-v3/src/c++17/floating_to_chars.cc.jj	2022-11-01 12:16:14.352652455 +0100
+++ libstdc++-v3/src/c++17/floating_to_chars.cc	2022-11-01 16:25:48.330968909 +0100
@@ -43,6 +43,13 @@
 #endif
 // sprintf for __ieee128
 extern "C" int __sprintfieee128(char*, const char*, ...);
+#elif __FLT128_MANT_DIG__ == 113 && __LDBL_MANT_DIG__ != 113 \
+      && defined(__GLIBC_PREREQ)
+extern "C" int __strfromf128(char*, size_t, const char*, _Float128)
+#ifndef _GLIBCXX_HAVE_FLOAT128_MATH
+  __attribute__((__weak__))
+#endif
+  __asm ("strfromf128");
 #endif
 
 // This implementation crucially assumes float/double have the
@@ -77,10 +84,11 @@ extern "C" int __sprintfieee128(char*, c
 #if defined _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT && __FLT128_MANT_DIG__ == 113
 // Define overloads of std::to_chars for __float128.
 # define FLOAT128_TO_CHARS 1
-#endif
-
-#ifdef FLOAT128_TO_CHARS
 using F128_type = __float128;
+#elif __FLT128_MANT_DIG__ == 113 && __LDBL_MANT_DIG__ != 113 \
+      && defined(__GLIBC_PREREQ)
+# define FLOAT128_TO_CHARS 1
+using F128_type = _Float128;
 #else
 using F128_type = void;
 #endif
@@ -252,7 +260,7 @@ namespace
 
 # ifdef FLOAT128_TO_CHARS
   template<>
-    struct floating_type_traits<__float128> : floating_type_traits_binary128
+    struct floating_type_traits<F128_type> : floating_type_traits_binary128
     { };
 # endif
 #endif
@@ -1035,7 +1043,8 @@ namespace
 #pragma GCC diagnostic ignored "-Wabi"
   template<typename T, typename... Extra>
   inline int
-  sprintf_ld(char* buffer, const char* format_string, T value, Extra... args)
+  sprintf_ld(char* buffer, size_t length __attribute__((unused)),
+	     const char* format_string, T value, Extra... args)
   {
     int len;
 
@@ -1045,10 +1054,31 @@ namespace
       fesetround(FE_TONEAREST); // We want round-to-nearest behavior.
 #endif
 
+#ifdef FLOAT128_TO_CHARS
 #ifdef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT
     if constexpr (is_same_v<T, __ieee128>)
       len = __sprintfieee128(buffer, format_string, args..., value);
     else
+#else
+    if constexpr (is_same_v<T, _Float128>)
+      {
+#ifndef _GLIBCXX_HAVE_FLOAT128_MATH
+	if (&__strfromf128 == nullptr)
+	  len = sprintf(buffer, format_string, args..., (long double)value);
+	else
+#endif
+	if constexpr (sizeof...(args) == 0)
+	  len = __strfromf128(buffer, length, "%.0f", value);
+	else
+	  {
+	    // strfromf128 unfortunately doesn't allow .*
+	    char fmt[3 * sizeof(int) + 6];
+	    sprintf(fmt, "%%.%d%c", args..., int(format_string[4]));
+	    len = __strfromf128(buffer, length, fmt, value);
+	  }
+      }
+    else
+#endif
 #endif
     len = sprintf(buffer, format_string, args..., value);
 
@@ -1206,8 +1236,10 @@ template<typename T>
 	    // can avoid this if we use sprintf to write all but the last
 	    // digit, and carefully compute and write the last digit
 	    // ourselves.
-	    char buffer[expected_output_length+1];
-	    const int output_length = sprintf_ld(buffer, "%.0Lf", value);
+	    char buffer[expected_output_length + 1];
+	    const int output_length = sprintf_ld(buffer,
+						 expected_output_length + 1,
+						 "%.0Lf", value);
 	    __glibcxx_assert(output_length == expected_output_length);
 	    memcpy(first, buffer, output_length);
 	    return {first + output_length, errc{}};
@@ -1397,9 +1429,10 @@ template<typename T>
 	  __builtin_unreachable();
 
 	// Do the sprintf into the local buffer.
-	char buffer[output_length_upper_bound+1];
+	char buffer[output_length_upper_bound + 1];
 	int output_length
-	  = sprintf_ld(buffer, output_specifier, value, effective_precision);
+	  = sprintf_ld(buffer, output_length_upper_bound + 1, output_specifier,
+		       value, effective_precision);
 	__glibcxx_assert(output_length <= output_length_upper_bound);
 
 	if (effective_precision > 0)
@@ -1799,6 +1832,7 @@ to_chars(char* first, char* last, long d
 }
 
 #ifdef FLOAT128_TO_CHARS
+#ifdef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT
 to_chars_result
 to_chars(char* first, char* last, __float128 value) noexcept
 {
@@ -1817,6 +1851,26 @@ to_chars(char* first, char* last, __floa
 {
   return __floating_to_chars_precision(first, last, value, fmt, precision);
 }
+#else
+to_chars_result
+to_chars(char* first, char* last, _Float128 value) noexcept
+{
+  return __floating_to_chars_shortest(first, last, value, chars_format{});
+}
+
+to_chars_result
+to_chars(char* first, char* last, _Float128 value, chars_format fmt) noexcept
+{
+  return __floating_to_chars_shortest(first, last, value, fmt);
+}
+
+to_chars_result
+to_chars(char* first, char* last, _Float128 value, chars_format fmt,
+	 int precision) noexcept
+{
+  return __floating_to_chars_precision(first, last, value, fmt, precision);
+}
+#endif
 #endif
 
 // Entrypoints for 16-bit floats.
--- libstdc++-v3/testsuite/20_util/to_chars/float128_c++23.cc.jj	2022-11-01 17:04:19.895606130 +0100
+++ libstdc++-v3/testsuite/20_util/to_chars/float128_c++23.cc	2022-11-01 20:47:15.254989646 +0100
@@ -0,0 +1,105 @@
+// Copyright (C) 2022 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2b" }
+// { dg-do run { target c++23 } }
+// { dg-require-effective-target ieee_floats }
+// { dg-require-effective-target size32plus }
+// { dg-add-options ieee }
+
+#include <charconv>
+#include <stdfloat>
+#include <limits>
+#include <numbers>
+#include <testsuite_hooks.h>
+
+#if defined(__STDCPP_FLOAT128_T__) \
+    && (defined(_GLIBCXX_LDOUBLE_IS_IEEE_BINARY128) \
+	|| defined(_GLIBCXX_HAVE_FLOAT128_MATH))
+void
+test(std::chars_format fmt = std::chars_format{})
+{
+  std::float128_t tests[] = {
+//    std::numeric_limits<std::float128_t>::denorm_min(),
+    std::numeric_limits<std::float128_t>::min(),
+    0.0f128,
+    -42.0f128,
+    1234.5678912345f128,
+    std::numbers::e_v<std::float128_t>,
+    std::numbers::log2e_v<std::float128_t>,
+    std::numbers::log10e_v<std::float128_t>,
+    std::numbers::pi_v<std::float128_t>,
+    std::numbers::inv_pi_v<std::float128_t>,
+    std::numbers::inv_sqrtpi_v<std::float128_t>,
+    std::numbers::ln2_v<std::float128_t>,
+    std::numbers::ln10_v<std::float128_t>,
+    std::numbers::sqrt2_v<std::float128_t>,
+    std::numbers::sqrt3_v<std::float128_t>,
+    std::numbers::inv_sqrt3_v<std::float128_t>,
+    std::numbers::egamma_v<std::float128_t>,
+    std::numbers::phi_v<std::float128_t>,
+    std::numeric_limits<std::float128_t>::max()
+  };
+  char str1[10000], str2[10000];
+  for (auto u : tests)
+    {
+      auto [ptr1, ec1] = std::to_chars(str1, str1 + sizeof(str1), u, fmt);
+      VERIFY( ec1 == std::errc() );
+//    std::cout << i << ' ' << std::string_view (str1, ptr1) << '\n';
+      if (fmt == std::chars_format::fixed)
+	{
+	  auto [ptr2, ec2] = std::to_chars(str2, str2 + (ptr1 - str1), u, fmt);
+	  VERIFY( ec2 == std::errc() && ptr2 - str2 == ptr1 - str1 );
+	  auto [ptr3, ec3] = std::to_chars(str2, str2 + (ptr1 - str1 - 1), u, fmt);
+	  VERIFY( ec3 != std::errc() );
+	}
+      std::float128_t v;
+      auto [ptr4, ec4] = std::from_chars(str1, ptr1, v,
+					 fmt == std::chars_format{}
+					 ? std::chars_format::general : fmt);
+      VERIFY( ec4 == std::errc() && ptr4 == ptr1 );
+      VERIFY( u == v );
+
+      auto [ptr5, ec5] = std::to_chars(str1, str1 + sizeof(str1), u, fmt, 90);
+      VERIFY( ec5 == std::errc() );
+//    std::cout << i << ' ' << std::string_view (str1, ptr5) << '\n';
+      v = 4.0f128;
+      auto [ptr6, ec6] = std::from_chars(str1, ptr5, v,
+					 fmt == std::chars_format{}
+					 ? std::chars_format::general : fmt);
+      VERIFY( ec6 == std::errc() && ptr6 == ptr5 );
+      if (fmt == std::chars_format::fixed && u > 0.0f128 && u < 0.000001f128)
+	VERIFY( v == 0.0 );
+      else
+	VERIFY( u == v );
+    }
+}
+#endif
+
+int
+main()
+{
+#if defined(__STDCPP_FLOAT128_T__) \
+    && (defined(_GLIBCXX_LDOUBLE_IS_IEEE_BINARY128) \
+	|| defined(_GLIBCXX_HAVE_FLOAT128_MATH))
+  test();
+  test(std::chars_format::fixed);
+  test(std::chars_format::scientific);
+  test(std::chars_format::general);
+  test(std::chars_format::hex);
+#endif
+}
