I am looking through assembly generated by my trivial C++ program. The full listing is:
test_func_0(int):
add edi, 15
pxor xmm0, xmm0
cvtsi2ss xmm0, edi
divss xmm0, DWORD PTR .LC0[rip]
cvttss2si eax, xmm0
ret
test_func_1(int&):
mov eax, DWORD PTR [rdi]
pxor xmm0, xmm0
add eax, 15
cvtsi2ss xmm0, eax
divss xmm0, DWORD PTR .LC0[rip]
cvttss2si eax, xmm0
ret
test_func_2(int*):
mov eax, DWORD PTR [rdi]
pxor xmm0, xmm0
add eax, 15
cvtsi2ss xmm0, eax
divss xmm0, DWORD PTR .LC0[rip]
cvttss2si eax, xmm0
ret
.LC1:
.string " "
main:
push r12
mov esi, 10
mov edi, OFFSET FLAT:_ZSt4cout
push rbp
sub rsp, 8
call std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
mov edx, 1
mov esi, OFFSET FLAT:.LC1
mov rdi, rax
call std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long)
mov esi, 10
mov edi, OFFSET FLAT:_ZSt4cout
call std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
mov edx, 1
mov esi, OFFSET FLAT:.LC1
mov rdi, rax
call std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long)
mov esi, 10
mov edi, OFFSET FLAT:_ZSt4cout
call std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
mov rbp, rax
mov rax, QWORD PTR [rax]
mov rax, QWORD PTR [rax-24]
mov r12, QWORD PTR [rbp+240+rax]
test r12, r12
je .L10
cmp BYTE PTR [r12+56], 0
je .L7
movsx esi, BYTE PTR [r12+67]
.L8:
mov rdi, rbp
call std::basic_ostream<char, std::char_traits<char> >::put(char)
mov rdi, rax
call std::basic_ostream<char, std::char_traits<char> >::flush()
add rsp, 8
xor eax, eax
pop rbp
pop r12
ret
.L7:
mov rdi, r12
call std::ctype<char>::_M_widen_init() const
mov rax, QWORD PTR [r12]
mov esi, 10
mov rdi, r12
call [QWORD PTR [rax+48]]
movsx esi, al
jmp .L8
.L10:
call std::__throw_bad_cast()
_GLOBAL__sub_I_test_func_0(int):
sub rsp, 8
mov edi, OFFSET FLAT:_ZStL8__ioinit
call std::ios_base::Init::Init() [complete object constructor]
mov edx, OFFSET FLAT:__dso_handle
mov esi, OFFSET FLAT:_ZStL8__ioinit
mov edi, OFFSET FLAT:_ZNSt8ios_base4InitD1Ev
add rsp, 8
jmp __cxa_atexit
.LC0:
.long 1077936128
And it is geneaterd from
#include <iostream>
int test_func_0 (int my_int)
{
return (my_int + 15) / 3.0f;
}
int test_func_1 (int& my_int)
{
return (my_int + 15) / 3.0f;
}
int test_func_2 (int* my_int)
{
return (*my_int + 15) / 3.0f;
}
int main()
{
int a = 17;
std::cout << test_func_0(a) << " ";
std::cout << test_func_1(a) << " ";
std::cout << test_func_2(&a) << std::endl;
return 0;
}
I believe I have been able to understand a lot of this, but three things I'm not seeing are:
- Where are my functions being called? I see the long calls to std::cout (as well as a weird cout looking thing
OFFSET FLAT:_ZSt4cout
), but no explicit calls totest_func_1(int&)
. - Where has my
17
gone?? I can understand it being taken as const and inlined somewhere.. but where? - I thought my
17
might have been the.long 1077936128
at the bottom, but in a weird format, but I'm not convinced by this. So what is this1077936128
number?
C++ Insights helps a little by showing me:
int main()
{
int a = 17;
std::operator<<(std::cout.operator<<(test_func_0(a)), " ");
std::operator<<(std::cout.operator<<(test_func_1(a)), " ");
std::cout.operator<<(test_func_2(&a)).operator<<(std::endl);
return 0;
}
Doing various inlines, as I thought. But I still don't see in the assembly where the functions are called.