I'm compile 1.c
with debug info:
gcc -O0 -g ./1.c
// 1.c
#include <stdio.h>
#include <string.h>
int main() {
char c[222];
scanf("%s", c);
int a = strlen("dadw");
return 0;
}
But I can't find strlen
through readelf -a a.out
or nm ./a.out
. In my understanding, strlen
is provided by libc.so
and resolved by dynamic linking. So it should appear in the symbol table. Is it caused by some special tricks of gcc?
❯ nm ./a.out
000000000000038c r __abi_tag
0000000000004010 B __bss_start
0000000000004010 b completed.0
w __cxa_finalize@GLIBC_2.2.5
0000000000004000 D __data_start
0000000000004000 W data_start
00000000000010b0 t deregister_tm_clones
0000000000001120 t __do_global_dtors_aux
0000000000003db8 d __do_global_dtors_aux_fini_array_entry
0000000000004008 D __dso_handle
0000000000003dc0 d _DYNAMIC
0000000000004010 D _edata
0000000000004018 B _end
00000000000011cc T _fini
0000000000001160 t frame_dummy
0000000000003db0 d __frame_dummy_init_array_entry
00000000000020e8 r __FRAME_END__
0000000000003fb0 d _GLOBAL_OFFSET_TABLE_
w __gmon_start__
0000000000002008 r __GNU_EH_FRAME_HDR
0000000000001000 T _init
0000000000002000 R _IO_stdin_used
U __isoc99_scanf@GLIBC_2.7
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
U __libc_start_main@GLIBC_2.34
0000000000001169 T main
00000000000010e0 t register_tm_clones
U __stack_chk_fail@GLIBC_2.4
0000000000001080 T _start
0000000000004010 D __TMC_END__
CodePudding user response:
Why strlen
isn't present in the symbol table
Because GCC replaces the call to strlen
with a constant 4
. x86-64 GCC 12.2 with the options -O0 -g
produces the following assembly code. Notice the line mov DWORD PTR [rbp-4], 4
, which is the constant 4
for the length of the string.
.LC0:
.string "%s"
main:
push rbp
mov rbp, rsp
sub rsp, 240
lea rax, [rbp-240]
mov rsi, rax
mov edi, OFFSET FLAT:.LC0
mov eax, 0
call __isoc99_scanf
mov DWORD PTR [rbp-4], 4
mov eax, 0
leave
ret
How to make it actually call strlen
Without replacing the constant string "dadw"
with a value read at runtime, one way to make GCC generate the call to strlen
is to disable built-in functions by using the -fno-builtins
option (link to documentation). According to the documentation:
GCC normally generates special code to handle certain built-in functions more efficiently; [...] the function calls no longer appear as such, [...]
With the options -O0 -g -fno-builtin
, x86-64 GCC 12.2 produces the following assembly code, and strlen
is present in the symbol table.
Notice the line call strlen
.
.LC0:
.string "%s"
.LC1:
.string "dadw"
main:
push rbp
mov rbp, rsp
sub rsp, 240
lea rax, [rbp-240]
mov rsi, rax
mov edi, OFFSET FLAT:.LC0
mov eax, 0
call __isoc99_scanf
mov edi, OFFSET FLAT:.LC1
call strlen
mov DWORD PTR [rbp-4], eax
mov eax, 0
leave
ret