From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailtransmit05.runbox.com (mailtransmit05.runbox.com [185.226.149.38]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8A3A035CB8F for ; Mon, 23 Feb 2026 11:09:42 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.226.149.38 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771844984; cv=none; b=nSsA71Z+q3ixsgik0ezQtfb7ZqEwg3d3e/AuWf4sgwJfNKH9AMpc7k1kX0YQCbFDM3rR2Akf3GXbtYO1O//JBrrDLHgsOQ3r9+JWcc3UXPtHoRviSa/pqil2RYGVVAYKouzKoYtcfBFEeBCsz3NpykX7HBLmlbtUab9M2RjhAco= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771844984; c=relaxed/simple; bh=hW5yZnI8l3t9iNmxsvr8a8yrvZbkSUFoZUt847CW9F0=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=XmCZq7Fby16WqwEwRzAGMXQOzP+fFIm2V7XDw+iBVCdBMIOwIc90uu4w4T3FTNSKfUm5Wh5/51FCUX4zXL4skTDMQP/K9Bukp747SFwvXg9zOUC2As1PoRLy5mJdcgQ7StNLi9f8F0TZicZIRW0jLvFpXsMUDUM0jO5oJYmz8BI= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=fail (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=runbox.com; dkim=pass (2048-bit key) header.d=runbox.com header.i=@runbox.com header.b=pnB2jG/Q; arc=none smtp.client-ip=185.226.149.38 Authentication-Results: smtp.subspace.kernel.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=runbox.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=runbox.com header.i=@runbox.com header.b="pnB2jG/Q" Received: from mailtransmit03.runbox ([10.9.9.163] helo=aibo.runbox.com) by mailtransmit05.runbox.com with esmtps (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.93) (envelope-from ) id 1vuT1A-00GoCq-2x; Mon, 23 Feb 2026 11:18:20 +0100 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=runbox.com; s=selector2; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To :Message-Id:Date:Subject:Cc:To:From; bh=lIqWK+ETxsAU8lN5Xp0EO5Isjnb5exAhcz1Iatt/SF4=; b=pnB2jG/QAlQM+f5XNx+TQiy1PR AoBoKTl7k5wE/GHiWvE0VJ+arvQzLAwM7mUaAvsZKqzJ3ogrwiamS6cihyqWoXjWbZz9RHraLyDSq xFlnv5pUI7wetvLyXlUiFLYbn62f+Rw1l4nmWOWVw8pJXIKg/zYiLBAIAb3N+cJ2KyiC55KdwsfyT fCuF85Jl1JA9M9kATQkXlcYbeTEBaYMZBo4IHGmKbKfz+hWbD8Kr/Ov5u8yg9zW5vHsf1+dHQzysd cpld55O05G74Dt2Slsb8VK45LClXTWD6Y1obnjOChvJhnnnOcFbyzy4Wq5dngmHItkTc75vSQFMk3 N+CoOkPA==; Received: from [10.9.9.73] (helo=submission02.runbox) by mailtransmit03.runbox with esmtp (Exim 4.86_2) (envelope-from ) id 1vuT19-0001Rm-OX; Mon, 23 Feb 2026 11:18:19 +0100 Received: by submission02.runbox with esmtpsa [Authenticated ID (1493616)] (TLS1.2:ECDHE_SECP256R1__RSA_PSS_RSAE_SHA256__AES_256_GCM:256) (Exim 4.93) id 1vuT13-006AjD-R7; Mon, 23 Feb 2026 11:18:13 +0100 From: david.laight.linux@gmail.com To: Willy Tarreau , =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= , linux-kernel@vger.kernel.org, Cheng Li Cc: David Laight Subject: [PATCH v3 next 09/17] tools/nolibc/printf: Simplify __nolibc_printf() Date: Mon, 23 Feb 2026 10:17:27 +0000 Message-Id: <20260223101735.2922-10-david.laight.linux@gmail.com> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20260223101735.2922-1-david.laight.linux@gmail.com> References: <20260223101735.2922-1-david.laight.linux@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit From: David Laight Move the check for the length modifiers into the format processing between the field width and conversion specifier. This lets the loop be simplified and a 'fast scan' for a format start used. If an error is detected (eg an invalid conversion specifier) then copy the invalid format to the output buffer. Reduces code size by about 10% on x86-64. Acked-By; Willy Tarreau Signed-off-by: David Laight --- Some versions of gcc bloat this version by generating a jump table. All goes away in the later patches. No change for v3, patch 5 in v2. tools/include/nolibc/stdio.h | 104 ++++++++++++++++++----------------- 1 file changed, 53 insertions(+), 51 deletions(-) diff --git a/tools/include/nolibc/stdio.h b/tools/include/nolibc/stdio.h index ea6c514c4b7a..52c4c4476102 100644 --- a/tools/include/nolibc/stdio.h +++ b/tools/include/nolibc/stdio.h @@ -310,28 +310,52 @@ typedef int (*__nolibc_printf_cb)(void *state, const char *buf, size_t size); static __attribute__((unused, format(printf, 3, 0))) int __nolibc_printf(__nolibc_printf_cb cb, void *state, const char *fmt, va_list args) { - char escape, lpref, ch; + char lpref, ch; unsigned long long v; int written, width, len; - size_t ofs; char outbuf[21]; const char *outstr; - written = ofs = escape = lpref = 0; + written = 0; while (1) { - ch = fmt[ofs++]; + outstr = fmt; + ch = *fmt++; + if (!ch) + break; + width = 0; + if (ch != '%') { + while (*fmt && *fmt != '%') + fmt++; + /* Output characters from the format string. */ + len = fmt - outstr; + } else { + /* we're in a format sequence */ - if (escape) { - /* we're in an escape sequence, ofs == 1 */ - escape = 0; + ch = *fmt++; /* width */ while (ch >= '0' && ch <= '9') { width *= 10; width += ch - '0'; - ch = fmt[ofs++]; + ch = *fmt++; + } + + /* Length modifiers */ + if (ch == 'l') { + lpref = 1; + ch = *fmt++; + if (ch == 'l') { + lpref = 2; + ch = *fmt++; + } + } else if (ch == 'j') { + /* intmax_t is long long */ + lpref = 2; + ch = *fmt++; + } else { + lpref = 0; } if (ch == 'c' || ch == 'd' || ch == 'u' || ch == 'x' || ch == 'p') { @@ -383,56 +407,34 @@ int __nolibc_printf(__nolibc_printf_cb cb, void *state, const char *fmt, va_list } else if (ch == 'm') { outstr = strerror(errno); - } - else if (ch == '%') { - /* queue it verbatim */ - continue; - } - else { - /* modifiers or final 0 */ - if (ch == 'l') { - /* long format prefix, maintain the escape */ - lpref++; - } else if (ch == 'j') { - lpref = 2; + } else { + if (ch != '%') { + /* Invalid format: back up to output the format characters */ + fmt = outstr + 1; + /* and output a '%' now. */ } - escape = 1; - goto do_escape; + /* %% is documented as a 'conversion specifier'. + * Any flags, precision or length modifier are ignored. + */ + width = 0; + outstr = "%"; } len = strlen(outstr); - goto flush_str; } - /* not an escape sequence */ - if (ch == 0 || ch == '%') { - /* flush pending data on escape or end */ - escape = 1; - lpref = 0; - outstr = fmt; - len = ofs - 1; - flush_str: - width -= len; - while (width > 0) { - /* Output pad in 16 byte blocks with the small block first. */ - int pad_len = ((width - 1) & 15) + 1; - width -= pad_len; - written += pad_len; - if (cb(state, " ", pad_len) != 0) - return -1; - } - if (cb(state, outstr, len) != 0) - return -1; + written += len; - written += len; - do_escape: - if (ch == 0) - break; - fmt += ofs; - ofs = 0; - continue; + width -= len; + while (width > 0) { + /* Output pad in 16 byte blocks with the small block first. */ + int pad_len = ((width - 1) & 15) + 1; + width -= pad_len; + written += pad_len; + if (cb(state, " ", pad_len) != 0) + return -1; } - - /* literal char, just queue it */ + if (cb(state, outstr, len) != 0) + return -1; } /* Request a final '\0' be added to the snprintf() output. -- 2.39.5