Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stage2: printf is sometimes converted to putchar or puts in ReleaseMode #12533

Open
akovaski opened this issue Aug 20, 2022 · 2 comments
Open
Labels
use case Describes a real use case that is difficult or impossible, but does not propose a solution.
Milestone

Comments

@akovaski
Copy link

Zig Version

0.10.0-dev.3659+e5e6eb983

Steps to Reproduce

test-printf.zig:

extern fn printf([*:0]const u8, ...) void;

export fn p_test_line() void {
    // printf characters followed by newline seems to invoke puts
    printf("Hello world\n");
}
export fn p_test_char() void {
    // printf of a single character seems to invoke putchar
    printf("x");
}
zig build-obj test-printf.zig -O ReleaseSmall -target riscv64-freestanding
llvm-objdump -t test-printf.o | grep 'printf\|put'

Expected Behavior

Expected printf to be in the symbol table. Expected puts and putchar to not be in the symbol table.

test-printf.o:  file format elf64-littleriscv
0000000000000000 l    df *ABS*  0000000000000000 test-printf
0000000000000000         *UND*  0000000000000000 printf

This is the behavior I get by doing one of:

  • passing -fstage1
  • using zig-linux-x86_64-0.10.0-dev.3475+b3d463c9e
  • passing -O Debug instead of -O ReleaseSmall

Actual Behavior

puts or putchar are in the symbol table, and printf is not.

test-printf.o:  file format elf64-littleriscv
0000000000000000 l    df *ABS*  0000000000000000 test-printf
0000000000000000         *UND*  0000000000000000 puts
0000000000000000         *UND*  0000000000000000 putchar

I experience this with all of ReleaseSmall, ReleaseFast, and ReleaseSafe.

This seems to be a fairly standard optimization for C, but it doesn't really make sense to me if libc is not used.

For the most zig programs, I imagine this optimization is fine. This behavior causes issues at link-time if puts or putchar are not defined.

The specific case I have is for compiling an OS (riscv64-freestanding) that defines printf but not puts or putchar. This is not a big deal to work around, but it was quite confusing to me when I was getting link errors such as LLD Link... ld.lld: error: undefined symbol: puts and ld.lld: error: undefined symbol: putchar and I had no references to puts or putchar in my code.

This issue is probably not restricted to printf because LibCallSimplifier appears to have optimizations for other functions as well.

It is pretty cool that zig/llvm can do these optimizations if you've gone through the effort of implementing the libc functions with compatible functionality. Though it invites a really confusing situation for anybody who implements libc functions with different functionality.

@akovaski akovaski added the bug Observed behavior contradicts documented or intended behavior label Aug 20, 2022
@nektro
Copy link
Contributor

nektro commented Aug 20, 2022

the api surface of libc is standardized. unsure how Zig is meant to detect an incomplete implementation. #2879 may make some headway on this, perhaps not though since printf/puts require io which is not defined on freestanding unless by the user

@andrewrk andrewrk added use case Describes a real use case that is difficult or impossible, but does not propose a solution. and removed bug Observed behavior contradicts documented or intended behavior labels Aug 22, 2022
@andrewrk andrewrk added this to the 0.12.0 milestone Aug 22, 2022
@andrewrk
Copy link
Member

This is working as designed. However maybe we can reach some kind of improvement for this use case. Perhaps if "none" is used as the C ABI of the target, Zig could disable this particular optimization.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
use case Describes a real use case that is difficult or impossible, but does not propose a solution.
Projects
None yet
Development

No branches or pull requests

3 participants