From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-wm1-f48.google.com (mail-wm1-f48.google.com [209.85.128.48]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BDABE2D5925 for ; Sun, 8 Feb 2026 17:14:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.48 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770570900; cv=none; b=KNBS0rkXn/5AqSNxctX4JqBDfgtP62ewPqp5DUvBg0nwFcu+MAP8KlGlKPnRldOoab1GGw6x1nTm9FnfCdqaVLReem7FR2OGf/qJtsNu/ZwtSclQKPr+eQx4UIggwNZT9zR1ZPHsueVlIUCBdhZCiyU3AGqgrgh6WuT0DIxLCew= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770570900; c=relaxed/simple; bh=qZPWN31cPOx3+sf6En55WvyRZEwhHeDYa6D68RZlsSI=; h=Date:From:To:Cc:Subject:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=Gr1QY0VPw7Anf0EVULTZLRHsCGWpAuyHXhChSJm2d2G8LtWkfQqHYouRc1TiW5BSolhyvDyU0qkJwAkEmbETqFOpXWUgP2ThH0wHxUJyysJfEYPaywm8buMddz046zToM8RLa7JGXWq9BcYnWmcOcQ4TZzsQvkmHpBnK1i55Zek= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=ljVR55Pk; arc=none smtp.client-ip=209.85.128.48 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="ljVR55Pk" Received: by mail-wm1-f48.google.com with SMTP id 5b1f17b1804b1-483337aa225so2735745e9.2 for ; Sun, 08 Feb 2026 09:14:59 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1770570898; x=1771175698; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:subject:cc:to:from:date:from:to:cc:subject:date :message-id:reply-to; bh=E2C7SQDHo5qmwEqq/TSOUnzLZhYTP5MdriXahI0q24g=; b=ljVR55PkgNvBrzsJB9+NdAnDVJYTLBaAeWvLVxPaLTj0oRTZFpPvxJjPUMWsVWMcKY LXP8o7xtqlriE53oNu8kPAgltlW8loAw+kHAPHvhEBEzaEL0E3d/vChA1WkckSY+zUna iVR+/DHky23RmnrgqXFIX+u3ofBhQIXeP8IsV+Bh77Vc/L5zNpRNzCWYm7Fo59KKgoD8 41PZHXFjTswbOwv1w0PiEWKaJ4krK/JufxEUBVRmVmzWy7cwDkBor3g6o5/1XzA/gC1g +RiCIMcGljWkpnE0TE7WYf9Oj+CsHxr61tA9KYuIhUwUfsS3p3icVIwgLmPJgFMXfRZ6 KW2w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1770570898; x=1771175698; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:subject:cc:to:from:date:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=E2C7SQDHo5qmwEqq/TSOUnzLZhYTP5MdriXahI0q24g=; b=fgy/e2+NttBUYAHO+ScMDatsnbrsZdKdg+lCAvxQsiCo7FAIZ2+PtXECV0zHvEk8RD 7xJ0dMAEEgV4xhd98f/0xEIs8z7ly5O58cXBEtblOgUrpAojYDX4qRbKBRL56gtg31we gK11nKOmFCe+VlsY8Zc0gG7r0YJ53eqtMh28HpaNxw7Cm1xiHII4CUGL05T+LLzy6Kb3 EIq3S5Zpu80sEAxCNBvOYfJH877PZN/OM+fi+YtU0JxXFnlbtSdXWsh4770eMcMI9bZE Fr31zNXV9w4pO7PCDSd45WllkSdIBtea+759d47yZwJH3vZcWRYtChJMuC6QPGlTcOmC A7+Q== X-Forwarded-Encrypted: i=1; AJvYcCVZR1dT7NuKvYVO3YqchQxL7xm6CR/gtwCEOJmL8X9uDSV66rrC1hwSURKUlJrZg6nYgYfEFpV4RCleWrc=@vger.kernel.org X-Gm-Message-State: AOJu0YxPzcoXPBlQgqapJyCvSc8dE3osRv3dexy1y5C6mljusY+3sTxQ /UFef48nEjqVTQ3v3HEy0tDq+QGxJl4DTAykxJc8Kqm0EbK2aQtpTzAp X-Gm-Gg: AZuq6aJr2Ae4Fgsp1u7ghL7fCtN/YKAcM/5DI1o5jY6G1mz6cZJ3JL2Xs/SSCLv0z0S /hti3uUFSo+i3RwY2fFdnlj047rvcTZbDx+mXCBdOra33q3rpaHzujr68vM5eADJ2+PVF8vL8nU uP0GTJQ84Mh4OrfLMrsgsjz5WkTKdBVeER8zvPBYSdzTNly96aMB8u3WI2J8XNZl8VaE1CH0CJv uAOAeYhlJctNT0JYHWYMUS7ZkgPUObjAzP8LWoAn5zVBZq4dHNpXS59G2U9DXjk91LEH1nhIyT9 2RIUQoZggNgKWjOVaaIRlbzc/ERUcW5kZLMqJIBxSiM+5isaG5CxTs9Bpds+PX808C2djVzBxEV qu2MswfEnzCesNQZo1Z0WeSJoeSsY500FHKOguxaDsYQK/1PHs1fKv5sTNnL5UcJpYv+lkpiqy7 2OhRQ3i+zjfgucTKrGxnkfk26x+wOrtnfzSCC9f2/koO4yNq9Ei2/bCm9h644RCV0= X-Received: by 2002:a05:600c:3f08:b0:477:9b35:3e49 with SMTP id 5b1f17b1804b1-483201da274mr123437295e9.3.1770570897964; Sun, 08 Feb 2026 09:14:57 -0800 (PST) Received: from pumpkin (82-69-66-36.dsl.in-addr.zen.co.uk. [82.69.66.36]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-48317d2bab2sm465379775e9.3.2026.02.08.09.14.57 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 08 Feb 2026 09:14:57 -0800 (PST) Date: Sun, 8 Feb 2026 17:14:56 +0000 From: David Laight To: Willy Tarreau Cc: Thomas =?UTF-8?B?V2Vpw59zY2h1aA==?= , linux-kernel@vger.kernel.org, Cheng Li Subject: Re: [PATCH v2 next 07/11] tools/nolibc/printf: Add support for conversion flags "#- +" and format "%X" Message-ID: <20260208171456.16547cac@pumpkin> In-Reply-To: References: <20260206191121.3602-1-david.laight.linux@gmail.com> <20260206191121.3602-8-david.laight.linux@gmail.com> X-Mailer: Claws Mail 4.1.1 (GTK 3.24.38; arm-unknown-linux-gnueabihf) Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 7bit On Sun, 8 Feb 2026 16:47:23 +0100 Willy Tarreau wrote: > On Fri, Feb 06, 2026 at 07:11:17PM +0000, david.laight.linux@gmail.com wrote: > > -/* simple printf(). It supports the following formats: > > - * - %[-][width][{l,t,z,ll,L,j,q}]{d,u,c,x,p,s,m,%} > > - * - %% > > - * - invalid formats are copied to the output buffer > > +/* printf(). Supports most of the normal integer and string formats. > > + * - %[#-+ ][width][{l,t,z,ll,L,j,q}]{d,i,u,c,x,X,p,s,m,%} > > + * - %% generates a single % > > + * - %m outputs strerror(errno). > > + * - # only affects %x and prepends 0x to non-zero values. > > + * - %o (octal) isn't supported. > > + * - %X outputs a..f the same as %x. > > + * - No support for zero padding, precision or variable widths. > > + * - No support for wide characters. > > + * - invalid formats are copied to the output buffer. > > */ > > Thanks for updating this one, it does help quite a bit. > > > /* This code uses 'flag' variables that are indexed by the low 6 bits > > @@ -279,7 +285,7 @@ int __nolibc_printf(__nolibc_printf_cb cb, void *state, const char *fmt, va_list > > unsigned int written, width; > > unsigned int flags, ch_flag; > > size_t len; > > - char tmpbuf[21]; > > + char tmpbuf[32 + 24]; > > The previous buffer was sized to store a 64-bit int. I couldn't figure > what these 32 and 24 correspond to with the new supported specifiers. > Maybe please add a short comment on the line to hint about what they > correspond to ? The could just be 2 here, but the next patch needs extra space for all the '0' bytes. I do like to make char[] arrays multiple of 4 bytes as well. That is one reason for rounding the 21 up to 24. It does also mean the line doesn't need changing to support octal. > > > const char *outstr; > > > > written = 0; > > @@ -334,19 +340,32 @@ int __nolibc_printf(__nolibc_printf_cb cb, void *state, const char *fmt, va_list > > > > /* Conversion specifiers. */ > > > > - /* Numeric conversion specifiers. */ > > - ch_flag = _NOLIBC_PF_CHAR_IS_ONE_OF(ch, 'c', 'd', 'i', 'u', 'x', 'p'); > > - if (ch_flag != 0) { > > + /* Numeric and pointer conversion specifiers. > > + * > > + * Use an explicit bound check (rather than _NOLIBC_PF_CHAR_IS_ONE_OF()) > > + * so that 'X' can be allowed through. > > + * 'X' gets treated and 'x' because _NOLIBC_PF_FLAG() returns the same > > + * value for both. > > + */ > > + if ((ch < 'a' || ch > 'z') && ch != 'X') > > + goto non_numeric_conversion; > > + > > + /* We need to check for "%p" or "%#x" later, merging here gives better code. > > + * But '#' collides with 'c' so shift right. > > + */ > > + ch_flag = _NOLIBC_PF_FLAG(ch) | (flags & _NOLIBC_PF_FLAG('#')) >> 1; > > + if (_NOLIBC_PF_FLAGS_CONTAIN(ch_flag, 'c', 'd', 'i', 'u', 'x', 'p', 's')) { > > unsigned long long v; > > long long signed_v; > > - char *out = tmpbuf; > > + char *out = tmpbuf + 32; > > OK so you seem to be reserving a part of the buffer for certain uses ? Sign and zero pad (next patch). Ok, make a comment... > > > + int sign = 0; > > > > /* 'long' is needed for pointer/string conversions and ltz lengths. > > * A single test can be used provided 'p' (the same bit as '0') > > * is masked from flags. > > */ > > if (_NOLIBC_PF_FLAGS_CONTAIN(ch_flag | (flags & ~_NOLIBC_PF_FLAG('p')), > > - 'p', 'l', 't', 'z')) { > > + 'p', 's', 'l', 't', 'z')) { > > v = va_arg(args, unsigned long); > > signed_v = (long)v; > > } else if (_NOLIBC_PF_FLAGS_CONTAIN(flags, 'j', 'q')) { > > @@ -365,40 +384,62 @@ int __nolibc_printf(__nolibc_printf_cb cb, void *state, const char *fmt, va_list > > goto do_output; > > } > > > > + if (_NOLIBC_PF_FLAGS_CONTAIN(ch_flag, 's')) { > > + /* "%s" - character string. */ > > + if (!v) { > > + outstr = "(null)"; > > + len = 6; > > + goto do_output; > > + } > > + outstr = (void *)v; > > +do_strnlen_output: > > + len = strnlen(outstr, INT_MAX); > > I get why you turned strlen() to strnlen(INT_MAX) (result being an int) > but this will not change anything IMHO in that the rest of a 2GB+ string > will be written in multiple passes and will overflow the output anyway. > Thus I think that sticking to strlen() remains simpler and less confusing. Wrong reason. The next patch changes it to: len = strnlen(outstr, precision); and I didn't want to change the name of the label as well as this line. > > (...) > > - else if (ch == 'm') { > > + > > +non_numeric_conversion: > > + if (ch == 'm') { > > #ifdef NOLIBC_IGNORE_ERRNO > > outstr = "unknown error"; > > + len = __builtin_strlen(outstr); > > #else > > outstr = strerror(errno); > > + goto do_strnlen_output; > > #endif /* NOLIBC_IGNORE_ERRNO */ > > It's simlper (and smaller) to use the common label for both here: > > #ifdef NOLIBC_IGNORE_ERRNO > outstr = "unknown error"; > #else > outstr = strerror(errno); > #endif /* NOLIBC_IGNORE_ERRNO */ > + goto do_strnlen_output; If you look closely strerror() gets inlined here (at least with the makefile that builds the test program). I think you'll get smaller code by marking some of the functions noinline. There is an 'interesting' option for 64bit. Put "errno=" into 'sign', set 'v = errno', clear '.' (or set precision to 1) and jump to the 'output in decimal' code. strerror() could then be implemented using snprintf(buf, n, "%m"); Related is inlining the 'divide by reciprocal' u64toa() code into sprintf() - that might save it spilling to stack and be smaller. Then implement atoi() (etc) using snprintf(). Might generate smaller code overall - but it isn't a serious suggestion. David > > Overall OK to me. Ta > > Willy