Message ID | 20240126142411.22972-1-rodrigo@sdfg.com.ar |
---|---|
Headers |
Return-Path: <linux-kernel+bounces-40181-ouuuleilei=gmail.com@vger.kernel.org> Delivered-To: ouuuleilei@gmail.com Received: by 2002:a05:7300:e09d:b0:103:945f:af90 with SMTP id gm29csp694632dyb; Fri, 26 Jan 2024 06:28:43 -0800 (PST) X-Google-Smtp-Source: AGHT+IGxzbbUTyIC/S4xE1Dza39lPBHYCll/MaHzjHZbEKmmLFyKev/a3aWSSbhTVpZ5qkAfqf6n X-Received: by 2002:a05:620a:6188:b0:783:711e:1855 with SMTP id or8-20020a05620a618800b00783711e1855mr2008858qkn.101.1706279322755; Fri, 26 Jan 2024 06:28:42 -0800 (PST) ARC-Seal: i=2; a=rsa-sha256; t=1706279322; cv=pass; d=google.com; s=arc-20160816; b=iL0mOolqZhYiaLXKuKBntgjyIO7t7MJ2Jmdwe+4kBFS8E8yn43amzaLAjeoFcY5Xpe GkSdGjNdFQQ159v4eZBopNruab047Yrf/EDhuHxlg5qrVmKey7IsXG0IgQpJM1JbINJm crv+Z99hZetnf898DSQN7EqyrbZ8Hhysipw0pu/M86/sTHRFr9pfXIISRcuWyiAhS7YZ BkP/gNGl8j871xeBrC6+Nnk1ifAv1JcG9e/YTEJ7bp7da2b0wObjtokn+qlCq/AJj8w1 k8LVn8sTptZswK1h056/DQ4y77Af6RN1cWo9fXgrP8NzSAFEWtDXYReEdIDBemxDuBg6 VVzw== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:list-unsubscribe :list-subscribe:list-id:precedence:message-id:date:subject:cc:to :from; bh=7HvROSqc5fcBXfVVWU0fzvUR39KEZvIEPW6fHIIy3OY=; fh=1pO/fnqlbA1DlSshLp2Kp23nBXobkeZ558bQEuNU3Z8=; b=X7OdO9xwtvUfw8rChTFgwVBr2bUpASAv/YYrrwxKjpb7EvtkHtZ3U6y6oMbp9BIEEH /3un7snpGhMAQafCx9+nCbqIxEWk/gnGdHQpDWNTCeAy0BvADfwm5SACcLSj4TzKc8zy QC3AHHZfL1bewp/yeDkzVV1h20FW7dsan0eGf7pNLJz6JPrFbMTA9Il/YuHdAAU0PFtz uAGOBoR/viOocjvQWNtoP4xuToCGtCk0cTT5D3kBsqi0M6zyXtCXSqvmd7vD0GavloHw ucTYQF6eSg2oMu7HyiYbGa1kuF6qUroAv+xVzOtQYIbRAC5iHN8P5d5jrJLS17F8vFmn A1/Q== ARC-Authentication-Results: i=2; mx.google.com; arc=pass (i=1 spf=pass spfdomain=sdfg.com.ar); spf=pass (google.com: domain of linux-kernel+bounces-40181-ouuuleilei=gmail.com@vger.kernel.org designates 2604:1380:45d1:ec00::1 as permitted sender) smtp.mailfrom="linux-kernel+bounces-40181-ouuuleilei=gmail.com@vger.kernel.org" Received: from ny.mirrors.kernel.org (ny.mirrors.kernel.org. [2604:1380:45d1:ec00::1]) by mx.google.com with ESMTPS id m9-20020a05620a220900b0078322b9b513si1356245qkh.746.2024.01.26.06.28.42 for <ouuuleilei@gmail.com> (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 26 Jan 2024 06:28:42 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel+bounces-40181-ouuuleilei=gmail.com@vger.kernel.org designates 2604:1380:45d1:ec00::1 as permitted sender) client-ip=2604:1380:45d1:ec00::1; Authentication-Results: mx.google.com; arc=pass (i=1 spf=pass spfdomain=sdfg.com.ar); spf=pass (google.com: domain of linux-kernel+bounces-40181-ouuuleilei=gmail.com@vger.kernel.org designates 2604:1380:45d1:ec00::1 as permitted sender) smtp.mailfrom="linux-kernel+bounces-40181-ouuuleilei=gmail.com@vger.kernel.org" Received: from smtp.subspace.kernel.org (wormhole.subspace.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ny.mirrors.kernel.org (Postfix) with ESMTPS id 898DA1C23D4E for <ouuuleilei@gmail.com>; Fri, 26 Jan 2024 14:28:42 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 5836B1DFDE; Fri, 26 Jan 2024 14:27:18 +0000 (UTC) Received: from alerce.blitiri.com.ar (alerce.blitiri.com.ar [49.12.208.134]) (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 5B06F1D542 for <linux-kernel@vger.kernel.org>; Fri, 26 Jan 2024 14:27:13 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=49.12.208.134 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706279236; cv=none; b=TQtqnhkznFCWEvWLzudZuIK/I9bi8xTsWU5f3dPpgPacTGSmEI+qY0fyENatx4UD93zek5nWKtHrz+USHcfIlGiE+RU5bPdZr7eOlV6pKJCWBUtFea3Ujl7Dx5dO/5HzggGDxzE82oWK1arbPGZWKcDwvXKgXvdfAGGDynL61eY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706279236; c=relaxed/simple; bh=cZBJLKefiwIoCqsp24IQdNQsW6/wBIH4IUtTtYyyoSM=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version; b=TMV4OZvbpVIV0fA2g1qipNtzBKDaySdXKdt2qjtijPLAES1BaSiJUqrdHoWyGkPL6VawpXDGms9Qg0yy+wPHPfr2841XGgbPQB0UTC+k3zAKc2f1a8D/NqMUfEGXOyUeGNshCNnpEzpC8eaum9ReetHKx9jRs7zVNX2L/ZYcDEY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=sdfg.com.ar; spf=pass smtp.mailfrom=sdfg.com.ar; arc=none smtp.client-ip=49.12.208.134 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=sdfg.com.ar Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=sdfg.com.ar Received: from localhost.localdomain by sdfg.com.ar (chasquid) with ESMTPSA tls TLS_AES_128_GCM_SHA256 (over submission, TLS-1.3, envelope from "rodrigo@sdfg.com.ar") ; Fri, 26 Jan 2024 14:25:10 +0000 From: Rodrigo Campos <rodrigo@sdfg.com.ar> To: Willy Tarreau <w@1wt.eu>, =?utf-8?q?Thomas_Wei=C3=9Fschuh?= <linux@weissschuh.net> Cc: linux-kernel@vger.kernel.org, Rodrigo Campos <rodrigo@sdfg.com.ar> Subject: [PATCH 0/1] tools/nolibc/string: export strlen() Date: Fri, 26 Jan 2024 15:24:10 +0100 Message-ID: <20240126142411.22972-1-rodrigo@sdfg.com.ar> X-Mailer: git-send-email 2.43.0 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: <linux-kernel.vger.kernel.org> List-Subscribe: <mailto:linux-kernel+subscribe@vger.kernel.org> List-Unsubscribe: <mailto:linux-kernel+unsubscribe@vger.kernel.org> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1789163547151258888 X-GMAIL-MSGID: 1789163547151258888 |
Series |
tools/nolibc/string: export strlen()
|
|
Message
Rodrigo Campos
Jan. 26, 2024, 2:24 p.m. UTC
Hi, while using nolibc on debian testing, I found that compilation fails when using strlcat(). The compilation fails with: cc -fno-asynchronous-unwind-tables -fno-ident -s -Os -nostdlib -lgcc -static -o test test.c /usr/bin/ld: /tmp/cccIasKL.o: in function `main': test.c:(.text.startup+0x1e): undefined reference to `strlen' collect2: error: ld returned 1 exit status This is using debian testing, with gcc 13.2.0. A small repro case that fails with this error on debian is: int main(void) { char dst[6] = "12"; char *src = "abc"; strlcat(dst, src, 6); printf("dst is: %s\n", dst); return 0; } Please note that this code is not using strlen() and strlcat() doesn't seems to use it either. First I noted that removing the attribute unused in strlen(), the compilation worked fine. And then I noticied that other functions had the attribute weak, a custom section and export the function. In particular, what happens here seems to be the same as in commit "tools/nolibc/string: export memset() and memmove()" (8d304a374023), as removing the -Os or adding the -ffreestanding seem to fix the issue. So, I did the same as that commit, for strlen(). However, I'm not 100% confident on how to check that this is done by the compiler to later replace it and provide a builtin. I'm not sure how that was verified for commit 8d304a374023, but if you let me know, I can verify it too. What do you think? As a side note, it seems strlcat()/strlcpy() fail to set the terminating null byte on some cases, and the return code is not always the same as when using libbsd. It seems to be only on "error" cases, and not sure if it's worth fixing all/some of those cases. Let me know if you think it is worth adding some _simple_ patches (I don't think it is worth fixing all the cases, the code is to fix all of the cases is probably not nice and not worth it). Best, Rodrigo --- Rodrigo Campos (1): tools/nolibc/string: export strlen() tools/include/nolibc/string.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
Comments
Hi! On 2024-01-26 15:24:10+0100, Rodrigo Campos wrote: > Hi, while using nolibc on debian testing, I found that compilation fails when using strlcat(). > > The compilation fails with: > > cc -fno-asynchronous-unwind-tables -fno-ident -s -Os -nostdlib -lgcc -static -o test test.c > /usr/bin/ld: /tmp/cccIasKL.o: in function `main': > test.c:(.text.startup+0x1e): undefined reference to `strlen' > collect2: error: ld returned 1 exit status > > This is using debian testing, with gcc 13.2.0. I can reproduce the issue with gcc 13.2.1 on Arch. > A small repro case that fails with this error on debian is: > > int main(void) { > char dst[6] = "12"; > char *src = "abc"; > strlcat(dst, src, 6); > > printf("dst is: %s\n", dst); > > return 0; > } > > Please note that this code is not using strlen() and strlcat() doesn't seems to use it either. I think the comment in strlen() explains it: Note that gcc12 recognizes an strlen() pattern and replaces it with a jump to strlen(). strlcat() indeed contains this pattern. I was able to fix the issue by replacing the open-coded strlen() in strlcat() with a call to the function and that also fixed the issue. It seems nicer to me as a fix, on the other hand the change to a weak definition will also catch other instances of the issue. Maybe we do both. > First I noted that removing the attribute unused in strlen(), the compilation worked fine. And then > I noticied that other functions had the attribute weak, a custom section and export the function. > > In particular, what happens here seems to be the same as in commit "tools/nolibc/string: export memset() and > memmove()" (8d304a374023), as removing the -Os or adding the -ffreestanding seem to fix the issue. > So, I did the same as that commit, for strlen(). > > However, I'm not 100% confident on how to check that this is done by the compiler to later replace > it and provide a builtin. I'm not sure how that was verified for commit 8d304a374023, but if you let > me know, I can verify it too. > > What do you think? Personally I don't know how it was verified, we'll have to wait for Willy on that. > As a side note, it seems strlcat()/strlcpy() fail to set the terminating null byte on some cases, > and the return code is not always the same as when using libbsd. It seems to be only on "error" > cases, and not sure if it's worth fixing all/some of those cases. > > Let me know if you think it is worth adding some _simple_ patches (I don't think it is worth fixing > all the cases, the code is to fix all of the cases is probably not nice and not worth it). Souns reasonable to me to fix the return values. And get some tests for it. > Best, > Rodrigo > > --- > > > Rodrigo Campos (1): > tools/nolibc/string: export strlen()
Hi! On Sat, Jan 27, 2024 at 03:53:32PM +0100, Thomas Weißschuh wrote: > Hi! > > On 2024-01-26 15:24:10+0100, Rodrigo Campos wrote: > > Hi, while using nolibc on debian testing, I found that compilation fails when using strlcat(). > > > > The compilation fails with: > > > > cc -fno-asynchronous-unwind-tables -fno-ident -s -Os -nostdlib -lgcc -static -o test test.c > > /usr/bin/ld: /tmp/cccIasKL.o: in function `main': > > test.c:(.text.startup+0x1e): undefined reference to `strlen' > > collect2: error: ld returned 1 exit status > > > > This is using debian testing, with gcc 13.2.0. > > I can reproduce the issue with gcc 13.2.1 on Arch. > > > A small repro case that fails with this error on debian is: > > > > int main(void) { > > char dst[6] = "12"; > > char *src = "abc"; > > strlcat(dst, src, 6); > > > > printf("dst is: %s\n", dst); > > > > return 0; > > } > > > > Please note that this code is not using strlen() and strlcat() doesn't seems to use it either. > > I think the comment in strlen() explains it: > > Note that gcc12 recognizes an strlen() pattern and replaces it with a > jump to strlen(). > > strlcat() indeed contains this pattern. > > I was able to fix the issue by replacing the open-coded strlen() in > strlcat() with a call to the function and that also fixed the issue. > > It seems nicer to me as a fix, on the other hand the change to a weak > definition will also catch other instances of the issue. > Maybe we do both. Yes, once we have the proof that the compiler may produce such a call, it can also happen in whatever user code so we need to export the function, there's no other solution. > > First I noted that removing the attribute unused in strlen(), the compilation worked fine. And then > > I noticied that other functions had the attribute weak, a custom section and export the function. > > > > In particular, what happens here seems to be the same as in commit "tools/nolibc/string: export memset() and > > memmove()" (8d304a374023), as removing the -Os or adding the -ffreestanding seem to fix the issue. > > So, I did the same as that commit, for strlen(). > > > > However, I'm not 100% confident on how to check that this is done by the compiler to later replace > > it and provide a builtin. I'm not sure how that was verified for commit 8d304a374023, but if you let > > me know, I can verify it too. > > > > What do you think? > > Personally I don't know how it was verified, we'll have to wait for > Willy on that. Oh it's very simple, just build a small code that doesn't contain any such explicit nor implicit call and check that it doesn't contain the function. E.g.: $ printf "int main(void) { }\n" | gcc -nostdlib -static -Isysroot/x86/include -include nolibc.h -Os -Wl,--gc-sections -xc - $ nm --size a.out 0000000000000003 T main 0000000000000004 V errno 0000000000000008 V _auxv 0000000000000008 V environ 000000000000000f W _start 0000000000000042 W _start_c and: $ printf "int main(void) { return (long)&strlen;}\n" | gcc -nostdlib -static -Isysroot/x86/include -include nolibc.h -Os -Wl,--gc-sections -xc - $ nm --size a.out 0000000000000004 V errno 0000000000000006 T main 0000000000000008 V _auxv 0000000000000008 V environ 000000000000000e t strlen 000000000000000f W _start 0000000000000042 W _start_c > > As a side note, it seems strlcat()/strlcpy() fail to set the terminating null byte on some cases, Indeed I've just checked and you're right, that defeats their purpose! > > and the return code is not always the same as when using libbsd. It seems to be only on "error" > > cases, and not sure if it's worth fixing all/some of those cases. OK. > > Let me know if you think it is worth adding some _simple_ patches (I don't think it is worth fixing > > all the cases, the code is to fix all of the cases is probably not nice and not worth it). > > Souns reasonable to me to fix the return values. > And get some tests for it. Seconded! Thanks! Willy
On 1/27/24 17:24, Willy Tarreau wrote: > On Sat, Jan 27, 2024 at 03:53:32PM +0100, Thomas Weißschuh wrote: >> On 2024-01-26 15:24:10+0100, Rodrigo Campos wrote: >>> Please note that this code is not using strlen() and strlcat() doesn't seems to use it either. >> >> I think the comment in strlen() explains it: >> >> Note that gcc12 recognizes an strlen() pattern and replaces it with a >> jump to strlen(). >> >> strlcat() indeed contains this pattern. >> >> I was able to fix the issue by replacing the open-coded strlen() in >> strlcat() with a call to the function and that also fixed the issue. >> >> It seems nicer to me as a fix, on the other hand the change to a weak >> definition will also catch other instances of the issue. >> Maybe we do both. > > Yes, once we have the proof that the compiler may produce such a call, it > can also happen in whatever user code so we need to export the function, > there's no other solution. Makes sense, thanks! > >>> First I noted that removing the attribute unused in strlen(), the compilation worked fine. And then >>> I noticied that other functions had the attribute weak, a custom section and export the function. >>> >>> In particular, what happens here seems to be the same as in commit "tools/nolibc/string: export memset() and >>> memmove()" (8d304a374023), as removing the -Os or adding the -ffreestanding seem to fix the issue. >>> So, I did the same as that commit, for strlen(). >>> >>> However, I'm not 100% confident on how to check that this is done by the compiler to later replace >>> it and provide a builtin. I'm not sure how that was verified for commit 8d304a374023, but if you let >>> me know, I can verify it too. >>> >>> What do you think? >> >> Personally I don't know how it was verified, we'll have to wait for >> Willy on that. > > Oh it's very simple, just build a small code that doesn't contain any > such explicit nor implicit call and check that it doesn't contain the > function. > > E.g > > $ printf "int main(void) { }\n" | gcc -nostdlib -static -Isysroot/x86/include -include nolibc.h -Os -Wl,--gc-sections -xc - > $ nm --size a.out Oh, cool. I can confirm that gcc does indeed add the strlen call (note I had to remove the "--size" param to nm, as the symbol is undefined and not shown otherwise) I wonder if there is an easy way to check for which functions gcc/clang do this... >>> As a side note, it seems strlcat()/strlcpy() fail to set the terminating null byte on some cases, > > Indeed I've just checked and you're right, that defeats their purpose! Cool. >>> Let me know if you think it is worth adding some _simple_ patches (I don't think it is worth fixing >>> all the cases, the code is to fix all of the cases is probably not nice and not worth it). >> >> Souns reasonable to me to fix the return values. >> And get some tests for it. > > Seconded! Thanks, I'll see how to improve that too :) Best, Rodrigo
. > Yes, once we have the proof that the compiler may produce such a call, it > can also happen in whatever user code so we need to export the function, > there's no other solution. Does that mean that it you try to implement strlen() in C gcc will generate a recursive call? I guess an 'asm volatile("");' in the loop fix it. Although, IIRC, you need a comment in the asm - and there isn't a portable comment. David - Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK Registration No: 1397386 (Wales)
On Sat, Jan 27, 2024 at 09:23:01PM +0000, David Laight wrote: > .. > > Yes, once we have the proof that the compiler may produce such a call, it > > can also happen in whatever user code so we need to export the function, > > there's no other solution. > > Does that mean that it you try to implement strlen() in C > gcc will generate a recursive call? Yes, that's exactly what happened the first time with strlen() itself! > I guess an 'asm volatile("");' in the loop fix it. That's how we fixed it for strlen(). The problem I'm having with addressing it this way is that as long as the compiler will decide to emit calls to strlen() which was not explicitly referenced in the code, it will still be missing and will continue to fail. Thus the safest solution is to make sure strlen() remains accessible in case the compiler decides to make use of it. Willy