I'm writing a linker for Windows. I compiled a simple "hello world" program using cl.exe
, and now I'm trying to link it using my custom linker, but it's not working. It works fine using link.exe
.
// hello.c
#include <stdio.h>
int main(void) {
printf("Hello, Windows!\n");
return 0;
}
The generated object file contains an undefined symbol called ?_OptionsStorage@?1??__local_stdio_printf_options@@9@9
.
# dumpbin output
00F 00000000 SECT4 notype () External | ___local_stdio_printf_options
010 00000000 UNDEF notype () External | ___acrt_iob_func
011 00000000 UNDEF notype () External | ___stdio_common_vfprintf
012 00000000 SECT5 notype () External | __vfprintf_l
013 00000000 SECT6 notype () External | _printf
014 00000000 SECT3 notype () External | _main
015 00000008 UNDEF notype External | ?_OptionsStorage@?1??__local_stdio_printf_options@@9@9 (`__local_stdio_printf_options'::`2'::_OptionsStorage)
016 00000000 SECT7 notype Static | .data
Section length 11, #relocs 0, #linenums 0, checksum F2A3A4F3
018 00000000 SECT7 notype Static | $SG9585
019 00000000 SECT8 notype Static | .chks64
Section length 40, #relocs 0, #linenums 0, checksum 0
My linker is unable to resolve this symbol, because it compares symbols using simple string comparison. libcmt.lib
does contain a similar symbol called ?_OptionsStorage@?1??__local_stdio_printf_options@@9@4_KA
in one of its object files:
# dumpbin output
07A 00000000 SECT27 notype Static | .xdata$x
Section length 1C, #relocs 2, #linenums 0, checksum 6A27921E, selection 5 (pick associative Section 0x1C)
07C 00000000 SECT27 notype Static | __sehtable$?notify_debugger@@YAXABUtagEXCEPTION_VISUALCPP_DEBUG_INFO@@@Z
07D 00000000 SECT28 notype Static | .bss
Section length 8, #relocs 0, #linenums 0, checksum 0, selection 2 (pick any)
07F 00000000 SECT28 notype External | ?_OptionsStorage@?1??__local_stdio_printf_options@@9@4_KA (unsigned __int64 `__local_stdio_printf_options'::`2'::_OptionsStorage)
080 00000000 SECT29 notype Static | .rdata
Section length 6C, #relocs 0, #linenums 0, checksum DD6D9A7E, selection 2 (pick any)
082 00000000 SECT29 notype External | ??_C@_1GM@CNOOJIHC@?$AAR?$AAu?$AAn?$AAt?$AAi?$AAm?$AAe?$AA?5?$AAC?$AAh?$AAe?$AAc?$AAk?$AA?5?$AAE@ (`string')
083 00000000 SECT2A notype Static | .rdata
These symbols look very similar. When I use undname.exe
to unmangle them, it looks like the former ends up being a suffix of the latter:
Undecoration of :- "?_OptionsStorage@?1??__local_stdio_printf_options@@9@9"
is :- "`__local_stdio_printf_options'::`2'::_OptionsStorage"
Undecoration of :- "?_OptionsStorage@?1??__local_stdio_printf_options@@9@4_KA"
is :- "unsigned __int64 `__local_stdio_printf_options'::`2'::_OptionsStorage"
But this isn't enough to answer my questions, which are:
- How do I figure out whether
?_OptionsStorage@?1??__local_stdio_printf_options@@9@4_KA
is the symbol thatlink.exe
is using to successfully resolve the undefined symbol inhello.obj
? Runninglink.exe
with/VERBOSE
and/or/MAP
doesn't seem to give me this information. - If this is the definition that is selected for symbol resolution, why? The symbol names are not exactly the same.
- Is there a different check besides simple equality that I should be doing in my linker to make this work properly? How do I do this robustly?
I'm writing a linker for Windows. I compiled a simple "hello world" program using cl.exe
, and now I'm trying to link it using my custom linker, but it's not working. It works fine using link.exe
.
// hello.c
#include <stdio.h>
int main(void) {
printf("Hello, Windows!\n");
return 0;
}
The generated object file contains an undefined symbol called ?_OptionsStorage@?1??__local_stdio_printf_options@@9@9
.
# dumpbin output
00F 00000000 SECT4 notype () External | ___local_stdio_printf_options
010 00000000 UNDEF notype () External | ___acrt_iob_func
011 00000000 UNDEF notype () External | ___stdio_common_vfprintf
012 00000000 SECT5 notype () External | __vfprintf_l
013 00000000 SECT6 notype () External | _printf
014 00000000 SECT3 notype () External | _main
015 00000008 UNDEF notype External | ?_OptionsStorage@?1??__local_stdio_printf_options@@9@9 (`__local_stdio_printf_options'::`2'::_OptionsStorage)
016 00000000 SECT7 notype Static | .data
Section length 11, #relocs 0, #linenums 0, checksum F2A3A4F3
018 00000000 SECT7 notype Static | $SG9585
019 00000000 SECT8 notype Static | .chks64
Section length 40, #relocs 0, #linenums 0, checksum 0
My linker is unable to resolve this symbol, because it compares symbols using simple string comparison. libcmt.lib
does contain a similar symbol called ?_OptionsStorage@?1??__local_stdio_printf_options@@9@4_KA
in one of its object files:
# dumpbin output
07A 00000000 SECT27 notype Static | .xdata$x
Section length 1C, #relocs 2, #linenums 0, checksum 6A27921E, selection 5 (pick associative Section 0x1C)
07C 00000000 SECT27 notype Static | __sehtable$?notify_debugger@@YAXABUtagEXCEPTION_VISUALCPP_DEBUG_INFO@@@Z
07D 00000000 SECT28 notype Static | .bss
Section length 8, #relocs 0, #linenums 0, checksum 0, selection 2 (pick any)
07F 00000000 SECT28 notype External | ?_OptionsStorage@?1??__local_stdio_printf_options@@9@4_KA (unsigned __int64 `__local_stdio_printf_options'::`2'::_OptionsStorage)
080 00000000 SECT29 notype Static | .rdata
Section length 6C, #relocs 0, #linenums 0, checksum DD6D9A7E, selection 2 (pick any)
082 00000000 SECT29 notype External | ??_C@_1GM@CNOOJIHC@?$AAR?$AAu?$AAn?$AAt?$AAi?$AAm?$AAe?$AA?5?$AAC?$AAh?$AAe?$AAc?$AAk?$AA?5?$AAE@ (`string')
083 00000000 SECT2A notype Static | .rdata
These symbols look very similar. When I use undname.exe
to unmangle them, it looks like the former ends up being a suffix of the latter:
Undecoration of :- "?_OptionsStorage@?1??__local_stdio_printf_options@@9@9"
is :- "`__local_stdio_printf_options'::`2'::_OptionsStorage"
Undecoration of :- "?_OptionsStorage@?1??__local_stdio_printf_options@@9@4_KA"
is :- "unsigned __int64 `__local_stdio_printf_options'::`2'::_OptionsStorage"
But this isn't enough to answer my questions, which are:
- How do I figure out whether
?_OptionsStorage@?1??__local_stdio_printf_options@@9@4_KA
is the symbol thatlink.exe
is using to successfully resolve the undefined symbol inhello.obj
? Runninglink.exe
with/VERBOSE
and/or/MAP
doesn't seem to give me this information. - If this is the definition that is selected for symbol resolution, why? The symbol names are not exactly the same.
- Is there a different check besides simple equality that I should be doing in my linker to make this work properly? How do I do this robustly?
1 Answer
Reset to default 0link.exe always uses exact name matches only.
?_OptionsStorage@?1??__local_stdio_printf_options@@9@4_KA
is not used of course. used exactly ?_OptionsStorage@?1??__local_stdio_printf_options@@9@9
and this symbol exist in libucrt.lib as example. maybe in some another libs too
How do I figure out whether
?_OptionsStorage@?1??__local_stdio_printf_options@@9@4_KA
is the symbol that link.exe is using to successfully resolve the undefined symbol in hello.obj?
?_OptionsStorage@?1??__local_stdio_printf_options@@9@4_KA
not used
Is there a different check besides simple equality that I should be doing in my linker to make this work properly? How do I do this robustly?
no
?_OptionsStorage@?1??__local_stdio_printf_options@@9@9
symbol. in what problem ? question is trivial – RbMm Commented 3 hours ago