This question already has answers here:
Why does GCC use multiplication by a strange number in implementing integer division?
(5 answers)
Divide Signed Integer By 2 compiles to complex assembly output, not just a shift
(1 answer)
Closed 1 year ago.
I have these functions in C++
int f1(int a)
{
int x = a / 2;
}
int f2(int a)
{
int y = a % 2;
}
int f3(int a)
{
int z = a % 7;
}
int f4(int a,int b)
{
int xy = a % b;
}
And i saw their assembly code but couldn't understand what they are doing.I couldn't even find a good referance or some explained example for the same. Here is the assembly
f1(int):
push rbp
mov rbp, rsp
mov DWORD PTR [rbp-20], edi
mov eax, DWORD PTR [rbp-20]
mov edx, eax
shr edx, 31
add eax, edx
sar eax
mov DWORD PTR [rbp-4], eax
nop
pop rbp
ret
f2(int):
push rbp
mov rbp, rsp
mov DWORD PTR [rbp-20], edi
mov eax, DWORD PTR [rbp-20]
cdq
shr edx, 31
add eax, edx
and eax, 1
sub eax, edx
mov DWORD PTR [rbp-4], eax
nop
pop rbp
ret
f3(int):
push rbp
mov rbp, rsp
mov DWORD PTR [rbp-20], edi
mov eax, DWORD PTR [rbp-20]
movsx rdx, eax
imul rdx, rdx, -1840700269
shr rdx, 32
add edx, eax
sar edx, 2
mov esi, eax
sar esi, 31
mov ecx, edx
sub ecx, esi
mov edx, ecx
sal edx, 3
sub edx, ecx
sub eax, edx
mov DWORD PTR [rbp-4], eax
nop
pop rbp
ret
f4(int, int):
push rbp
mov rbp, rsp
mov DWORD PTR [rbp-20], edi
mov DWORD PTR [rbp-24], esi
mov eax, DWORD PTR [rbp-20]
cdq
idiv DWORD PTR [rbp-24]
mov DWORD PTR [rbp-4], edx
nop
pop rbp
ret
Can you please tell by some example or what steps it is following to calculate the answers in all these three cases and why would they work just fine instead of normal divide
Related
In the learncpp article about the hidden this pointer, the author mentioned that the compiler converts the object prefix to an argument passed by address to the function.
In the example:
simple.setID(2);
Will be converted to:
setID(&simple, 2); // note that simple has been changed from an object prefix to a function argument!
Why does the compiler do this? I've tried searching other documentation about it but couldn't find any. I've asked other people but they say it is a mistake or the compiler doesn't do that.
I have a second question on this topic. Let's go back to the example:
simple.setID(2); //Will be converted to setID(&simple, 2);
If the compiler converts it, won't it just look exactly like a function that has a name of setID and has two parameters?
void setID(MyClass* obj, int id) {
return;
}
int main() {
MyClass simple;
simple.setID(2); //Will be converted to setID(&simple, 2);
setID(&simple, 2);
}
Line 6 and 7 would look exactly the same.
object prefix to an argument passed by address to the function
This refers to how implementations use to translate it to machine code (but they could do it any other way)
Why does the compiler do this?
In some way, you need to be able to refer to the object in the called member function, and one way is to just handle it like an argument.
If the compiler converts it, won't it just look exactly like a function that has a name of setID and has two parameters?
If you have this code:
struct Test {
int v = 0;
Test(int v ) : v(v) {
}
void test(int a) {
int v = this->v;
int r = a;
}
};
void test(Test* t, int a) {
int v = t->v;
int r = a + v;
}
int main() {
Test a(2);
a.test(1);
test(&a, 1);
return 0;
}
gcc-12 will create this assembly code (for x86 and if optimizations are turned off):
Test::Test(int) [base object constructor]:
push rbp
mov rbp, rsp
mov QWORD PTR [rbp-8], rdi
mov DWORD PTR [rbp-12], esi
mov rax, QWORD PTR [rbp-8]
mov edx, DWORD PTR [rbp-12]
mov DWORD PTR [rax], edx
nop
pop rbp
ret
Test::test(int a):
push rbp
mov rbp, rsp
mov QWORD PTR [rbp-24], rdi
mov DWORD PTR [rbp-28], esi
// int v = this->v;
mov rax, QWORD PTR [rbp-24]
mov eax, DWORD PTR [rax]
mov DWORD PTR [rbp-4], eax
// int r = a;
mov eax, DWORD PTR [rbp-28]
mov DWORD PTR [rbp-8], eax
// end of function
nop
pop rbp
ret
test(Test* t, int a):
push rbp
mov rbp, rsp
mov QWORD PTR [rbp-24], rdi
mov DWORD PTR [rbp-28], esi
// int v = t->v;
mov rax, QWORD PTR [rbp-24]
mov eax, DWORD PTR [rax]
mov DWORD PTR [rbp-4], eax
// int r = a + v;
mov edx, DWORD PTR [rbp-28]
mov eax, DWORD PTR [rbp-4]
add eax, edx
mov DWORD PTR [rbp-8], eax
// end of function
nop
pop rbp
ret
main:
push rbp
mov rbp, rsp
sub rsp, 16
lea rax, [rbp-4]
mov esi, 2
mov rdi, rax
call Test::Test(int) [complete object constructor]
// a.test(1);
lea rax, [rbp-4]
mov esi, 1
mov rdi, rax
call Test::test(int)
// test(&a, 1);
lea rax, [rbp-4]
mov esi, 1
mov rdi, rax
call test(Test*, int)
// end of main
mov eax, 0
leave
ret
So the machine code generated with no optimizations, looks identical for test(&a, 1) and a.test(1). And that's what the statement refers to.
But again that is an implementation detail how the compiler translates c++ to machine code, and not related to c++ itself.
I'd like to call from my c++ code some 3-rd party text outputting procedure which i have an memory offset. Here is the assembly code of the function:
op_float_msg_ proc near ; initIntExtra_+628o
a3 = dword ptr -3Ch
_object = dword ptr -34h
a2 = byte ptr -30h
font = dword ptr -28h
outline_clr= dword ptr -24h
clr = dword ptr -20h
text = dword ptr -1Ch
push ebx
push ecx
push edx
push esi
push edi
push ebp
sub esp, 34h
mov ecx, eax
mov ebx, 65h
xor eax, eax
xor edx, edx
xor edi, edi
xor esi, esi
mov al, ds:_YellowColor
xor ebp, ebp
mov [esp+4Ch+clr], eax
xor eax, eax
mov [esp+4Ch+text], edx
mov al, ds:_colorTable ; Ś˝ÓşŰę
mov [esp+4Ch+font], ebx
mov [esp+4Ch+outline_clr], eax
loc_4592B6: ; op_float_msg_+BEj
mov eax, ecx ; a1
call interpretPopShort_ ; Get value type
mov word ptr [esp+esi+4Ch+a2], ax
mov eax, ecx ; a1
call interpretPopLong_ ; Get value
mov dx, word ptr [esp+esi+4Ch+a2]
mov [esp+ebp+4Ch+a3], eax
cmp dx, 9801h
jnz short loc_4592E9
mov ebx, eax ; a3
xor edx, edx
mov eax, ecx ; result
mov dx, word ptr [esp+esi+4Ch+a2] ; a2
call interpretDecStringRef_
loc_4592E9: ; op_float_msg_+57j
cmp edi, 1
jz short loc_459312
xor eax, eax
mov ax, word ptr [esp+esi+4Ch+a2]
and ah, 0F7h
cmp eax, 0C001h
jz short loc_459334
push edi
mov eax, [ecx]
push eax
push offset asc_50683C ; "script error: %s: invalid arg %d to flo"...
call interpretError_
add esp, 0Ch
jmp short loc_459334
; ---------------------------------------------------------------------------
loc_459312: ; op_float_msg_+6Cj
xor edx, edx
mov dx, word ptr [esp+esi+4Ch+a2] ; a2
mov eax, edx
and ah, 0F7h
cmp eax, 9001h
jnz short loc_459334
mov eax, ecx ; a1
mov ebx, [esp+ebp+4Ch+a3] ; a3
call interpretGetString_
mov [esp+4Ch+text], eax
loc_459334: ; op_float_msg_+7Dj ...
add ebp, 4
inc edi
add esi, 2
cmp edi, 3
jl loc_4592B6
mov edx, [esp+4Ch+_object]
test edx, edx
jnz short loc_459362
mov ebx, 1 ; type
mov edx, offset aFloat_msg ; "float_msg"
mov eax, ecx ; arg
call dbg_error_
jmp loc_459496
; ---------------------------------------------------------------------------
loc_459362: ; op_float_msg_+CAj
mov ebx, [esp+4Ch+text]
mov esi, edx
test ebx, ebx
jz short loc_459371
cmp byte ptr [ebx], 0
jnz short loc_459387
loc_459371: ; op_float_msg_+EAj
mov eax, esi ; result
call text_object_remove_
call tile_refresh_display_
add esp, 34h
pop ebp
pop edi
pop esi
pop edx
pop ecx
pop ebx
retn
Based on the code above how can I call pass the parameters to the function, especially the string to display? I know, that it's maybe a little guessing but can someone please help me try to deduce it?
This question already has answers here:
How is a reference variable represented in memory?
(1 answer)
memory of a reference variable in c++?
(3 answers)
How does a C++ reference look, memory-wise?
(9 answers)
C++ do references occupy memory
(2 answers)
Closed 1 year ago.
I compile following code
int foo(int num) {
int &numReference = num;
int numVarible = num;
return numVarible;
}
output assemble translation.
foo(int):
push rbp
mov rbp, rsp
mov DWORD PTR [rbp-20], edi
lea rax, [rbp-20]
mov QWORD PTR [rbp-8], rax
mov eax, DWORD PTR [rbp-20]
mov DWORD PTR [rbp-12], eax
mov eax, DWORD PTR [rbp-12]
pop rbp
ret
int &numReference = num; output assemble:
lea rax, [rbp-20]
mov QWORD PTR [rbp-8], rax
int numVarible = num; output assemble:
mov eax, DWORD PTR [rbp-20]
mov DWORD PTR [rbp-12], eax
the question 1 is what's the difference about memeory comsumption.
When I change code from "return numVarible;" to "return numReference ;".
assemble changes from
mov eax, DWORD PTR [rbp-12]
to
mov rax, QWORD PTR [rbp-8]
mov eax, DWORD PTR [rax]
the question 2 is: when using reference, why assemble shows more line?
So I'm debugging my DPLL implementation and it's not quite working right so I step through the code line by line in the debugger, it gets to a return statement but the thing is it doesn't return, it just keeps on executing the same function. WTF I thought, am I really seeing this? So I looked at the dissasembly and sure enough one of the return statements jumps to the wrong place. Never have I seen VS generate incorrect code so I'm wondering if I screwed up somewhere but I can't find anything. The jump is incorrect even when compiling with all optimizations off.
This illustrates whats going on.
bool dpll(std::vector<clause> f)
{
unitPropagate(f);
if(checkFalseClause(f))
{
return false; //je dpll+5Fh (0C01D1Fh) <-- Totally wrong jump adress
}
else if(checkAllClausesTrue(f))
{
return true; //jmp dpll+206h (0C01EC6h) <-- this is fine
}
else
{
atom l = chooseLiteral(f); //this is where the jump ends up (0C01D1Fh)
std::vector<clause> a = makeDuplicate(f);
replaceInstancesOf(a, l, true);
std::vector<clause> b = makeDuplicate(f);
replaceInstancesOf(b, l, false);
return dpll(a) | dpll(b);
}
//this is where the jump is supposed to go (0C01EC6h)
}
So my question is, is Visual Studio actually broken or have I misunderstood something? Has anyone run into something like this before?
The version is Visual Studio Enterprise 2015 if that makes a difference, the code is generated for x86_32.
Here's the full dissasembly if anyone's interested:
00C01CC0 push ebp
00C01CC1 mov ebp,esp
00C01CC3 push 0FFFFFFFFh
00C01CC5 push 0C08FF0h
00C01CCA mov eax,dword ptr fs:[00000000h]
00C01CD0 push eax
00C01CD1 sub esp,40h
00C01CD4 mov eax,dword ptr [__security_cookie (0C0D008h)]
00C01CD9 xor eax,ebp
00C01CDB mov dword ptr [ebp-10h],eax
00C01CDE push ebx
00C01CDF push esi
00C01CE0 push eax
00C01CE1 lea eax,[ebp-0Ch]
00C01CE4 mov dword ptr fs:[00000000h],eax
bool dpll(std::vector<clause> f)
00C01CEA lea ecx,[f]
00C01CED mov dword ptr [ebp-4],0
00C01CF4 call unitPropagate (0C01950h)
{
unitPropagate(f);
00C01CF9 lea ecx,[f]
00C01CFC call checkFalseClause (0C01660h)
00C01D01 test al,al
00C01D03 je dpll+4Ch (0C01D0Ch)
00C01D05 xor bh,bh
00C01D07 jmp dpll+206h (0C01EC6h)
if(checkFalseClause(f))
{
return false;
00C01D0C lea ecx,[f]
00C01D0F call checkAllClausesTrue (0C014F0h)
00C01D14 test al,al
00C01D16 je dpll+5Fh (0C01D1Fh)
}
else if(checkAllClausesTrue(f))
00C01D18 mov bh,1
00C01D1A jmp dpll+206h (0C01EC6h)
{
return true;
}
else
00C01D1F lea edx,[f]
00C01D22 lea ecx,[l]
00C01D25 call chooseLiteral (0C013D0h)
00C01D2A mov byte ptr [ebp-4],1
{
atom l = chooseLiteral(f);
00C01D2E lea edx,[f]
00C01D31 xorps xmm0,xmm0
00C01D34 mov dword ptr [ebp-20h],0
00C01D3B lea ecx,[a]
00C01D3E movq mmword ptr [a],xmm0
00C01D43 call makeDuplicate (0C01A30h)
00C01D48 mov byte ptr [ebp-4],2
00C01D4C sub esp,20h
00C01D4F mov esi,esp
00C01D51 mov bl,1
00C01D53 mov dword ptr [ebp-4Ch],esi
00C01D56 lea ecx,[esi+4]
00C01D59 mov al,byte ptr [l]
00C01D5C mov byte ptr [esi],al
00C01D5E mov dword ptr [ecx+14h],0Fh
00C01D65 mov dword ptr [ecx+10h],0
00C01D6C cmp dword ptr [ecx+14h],10h
00C01D70 jb dpll+0B6h (0C01D76h)
00C01D72 mov eax,dword ptr [ecx]
00C01D74 jmp dpll+0B8h (0C01D78h)
00C01D76 mov eax,ecx
00C01D78 push 0FFFFFFFFh
00C01D7A mov byte ptr [eax],0
00C01D7D lea eax,[ebp-44h]
00C01D80 push 0
00C01D82 push eax
00C01D83 call std::basic_string<char,std::char_traits<char>,std::allocator<char> >::assign (0C02A80h)
00C01D88 mov al,byte ptr [ebp-2Ch]
00C01D8B lea ecx,[a]
00C01D8E mov byte ptr [esi+1Ch],al
00C01D91 mov dl,bl
00C01D93 mov al,byte ptr [ebp-2Bh]
00C01D96 mov byte ptr [esi+1Dh],al
00C01D99 call replaceInstancesOf (0C017D0h)
00C01D9E xorps xmm0,xmm0
00C01DA1 mov dword ptr [ebp-14h],0
std::vector<clause> a = makeDuplicate(f);
replaceInstancesOf(a, l, true);
00C01DA8 lea edx,[f]
std::vector<clause> a = makeDuplicate(f);
replaceInstancesOf(a, l, true);
00C01DAB movq mmword ptr [b],xmm0
00C01DB0 lea ecx,[b]
00C01DB3 call makeDuplicate (0C01A30h)
00C01DB8 mov esi,esp
00C01DBA mov byte ptr [ebp-4],3
00C01DBE mov dword ptr [ebp-4Ch],esi
00C01DC1 lea ecx,[esi+4]
00C01DC4 mov al,byte ptr [l]
00C01DC7 xor bl,bl
00C01DC9 push 0FFFFFFFFh
00C01DCB mov byte ptr [esi],al
00C01DCD lea eax,[ebp-44h]
00C01DD0 push 0
00C01DD2 mov dword ptr [ecx+14h],0Fh
00C01DD9 mov dword ptr [ecx+10h],0
00C01DE0 push eax
00C01DE1 mov byte ptr [ecx],bl
00C01DE3 call std::basic_string<char,std::char_traits<char>,std::allocator<char> >::assign (0C02A80h)
00C01DE8 mov al,byte ptr [ebp-2Ch]
00C01DEB lea ecx,[b]
00C01DEE mov byte ptr [esi+1Ch],al
00C01DF1 mov dl,bl
00C01DF3 mov al,byte ptr [ebp-2Bh]
00C01DF6 mov byte ptr [esi+1Dh],al
00C01DF9 call replaceInstancesOf (0C017D0h)
std::vector<clause> b = makeDuplicate(f);
replaceInstancesOf(b, l, false);
00C01DFE add esp,14h
00C01E01 lea eax,[a]
00C01E04 mov ecx,esp
00C01E06 push eax
00C01E07 call std::vector<std::vector<atom,std::allocator<atom> >,std::allocator<std::vector<atom,std::allocator<atom> > > >::vector<std::vector<atom,std::allocator<atom> >,std::allocator<std::vector<atom,std::allocator<atom> > > > (0C02420h)
00C01E0C call dpll (0C01CC0h)
00C01E11 mov bl,al
00C01E13 mov ecx,esp
00C01E15 lea eax,[b]
00C01E18 push eax
00C01E19 call std::vector<std::vector<atom,std::allocator<atom> >,std::allocator<std::vector<atom,std::allocator<atom> > > >::vector<std::vector<atom,std::allocator<atom> >,std::allocator<std::vector<atom,std::allocator<atom> > > > (0C02420h)
00C01E1E call dpll (0C01CC0h)
00C01E23 mov ecx,dword ptr [b]
00C01E26 mov bh,al
00C01E28 add esp,0Ch
00C01E2B or bh,bl
00C01E2D test ecx,ecx
00C01E2F je dpll+1B4h (0C01E74h)
00C01E31 push dword ptr [ebp-4Ch]
00C01E34 mov edx,dword ptr [ebp-18h]
00C01E37 push ecx
00C01E38 call std::_Destroy_range1<std::allocator<std::vector<atom,std::allocator<atom> > >,std::vector<atom,std::allocator<atom> > *> (0C035E0h)
00C01E3D mov ecx,dword ptr [ebp-14h]
00C01E40 mov eax,2AAAAAABh
00C01E45 mov esi,dword ptr [b]
00C01E48 add esp,8
00C01E4B sub ecx,esi
00C01E4D imul ecx
00C01E4F sar edx,1
00C01E51 mov eax,edx
00C01E53 shr eax,1Fh
00C01E56 add eax,edx
00C01E58 push eax
00C01E59 push esi
00C01E5A call std::_Wrap_alloc<std::allocator<std::vector<atom,std::allocator<atom> > > >::deallocate (0C02D20h)
00C01E5F mov dword ptr [b],0
00C01E66 mov dword ptr [ebp-18h],0
00C01E6D mov dword ptr [ebp-14h],0
00C01E74 mov ecx,dword ptr [a]
00C01E77 test ecx,ecx
00C01E79 je dpll+1FEh (0C01EBEh)
00C01E7B push dword ptr [ebp-4Ch]
00C01E7E mov edx,dword ptr [ebp-24h]
00C01E81 push ecx
00C01E82 call std::_Destroy_range1<std::allocator<std::vector<atom,std::allocator<atom> > >,std::vector<atom,std::allocator<atom> > *> (0C035E0h)
00C01E87 mov ecx,dword ptr [ebp-20h]
00C01E8A mov eax,2AAAAAABh
00C01E8F mov esi,dword ptr [a]
00C01E92 add esp,8
00C01E95 sub ecx,esi
00C01E97 imul ecx
00C01E99 sar edx,1
00C01E9B mov eax,edx
00C01E9D shr eax,1Fh
00C01EA0 add eax,edx
00C01EA2 push eax
00C01EA3 push esi
00C01EA4 call std::_Wrap_alloc<std::allocator<std::vector<atom,std::allocator<atom> > > >::deallocate (0C02D20h)
00C01EA9 mov dword ptr [a],0
00C01EB0 mov dword ptr [ebp-24h],0
00C01EB7 mov dword ptr [ebp-20h],0
00C01EBE lea ecx,[ebp-44h]
00C01EC1 call std::basic_string<char,std::char_traits<char>,std::allocator<char> >::~basic_string<char,std::char_traits<char>,std::allocator<char> > (0C027A0h)
00C01EC6 mov ecx,dword ptr [f]
00C01EC9 test ecx,ecx
00C01ECB je dpll+23Bh (0C01EFBh)
00C01ECD push dword ptr [ebp-4Ch]
00C01ED0 mov edx,dword ptr [ebp+0Ch]
00C01ED3 push ecx
00C01ED4 call std::_Destroy_range1<std::allocator<std::vector<atom,std::allocator<atom> > >,std::vector<atom,std::allocator<atom> > *> (0C035E0h)
00C01ED9 mov ecx,dword ptr [ebp+10h]
00C01EDC mov eax,2AAAAAABh
00C01EE1 mov esi,dword ptr [f]
00C01EE4 add esp,8
00C01EE7 sub ecx,esi
00C01EE9 imul ecx
00C01EEB sar edx,1
00C01EED mov ecx,edx
00C01EEF shr ecx,1Fh
00C01EF2 add ecx,edx
00C01EF4 push ecx
00C01EF5 push esi
00C01EF6 call std::_Wrap_alloc<std::allocator<std::vector<atom,std::allocator<atom> > > >::deallocate (0C02D20h)
00C01EFB mov al,bh
00C01EFD mov ecx,dword ptr [ebp-0Ch]
00C01F00 mov dword ptr fs:[0],ecx
00C01F07 pop ecx
00C01F08 pop esi
00C01F09 pop ebx
00C01F0A mov ecx,dword ptr [ebp-10h]
00C01F0D xor ecx,ebp
00C01F0F call __security_check_cookie (0C080CCh)
00C01F14 mov esp,ebp
00C01F16 pop ebp
00C01F17 ret
The source interleaving is wrong. This is the correct place you want to look at:
00C01CFC call checkFalseClause (0C01660h)
00C01D01 test al,al
00C01D03 je dpll+4Ch (0C01D0Ch)
00C01D05 xor bh,bh
00C01D07 jmp dpll+206h (0C01EC6h)
As you can see, it goes to the expected address if the return value was nonzero.
The part you looked at is actually for the else if(checkAllClausesTrue(f)) and the jump is the one going to the else clause because the compiler negated the condition.
I'm using a proprietary DLL (CP5200.dll) to communicate with 10 scrolling message LED signs. I'm using openFrameworks generate and save images of the text I want to display, and then using the DLL to package the images into data the sign can process.
I call the following functions a few times a minute, and they return a file of 2-4kb , depending on image size, but at a certain point - around 3hrs 45 minutes after startup, they start returning files of 128 bytes, which result in a blank LED display when uploaded. I'm hypothesizing that there's a buffer inside the dll that doesn't get emptied, or something of the sort, but I can't make sense of the decompiled code.
Here are the functions:
int CP5200_Program_AddPicture(HOBJECT hObj, int nWinNo, const char* pPictFile, int nMode, int nEffect, int nSpeed, int nStay, int nCompress)
int CP5200_Program_SaveToFile(HOBJECT hObj, const char* pFilename)
Decompiled functions:
Exported fn(): CP5200_Program_AddImage - Ord:00C3h
:1000FD20 51 push ecx
:1000FD21 55 push ebp
:1000FD22 8B6C240C mov ebp, dword ptr [esp+0C]
:1000FD26 85ED test ebp, ebp
:1000FD28 7508 jne 1000FD32
:1000FD2A 83C8FF or eax, FFFFFFFF
:1000FD2D 5D pop ebp
:1000FD2E 59 pop ecx
:1000FD2F C23000 ret 0030
Function fully disassembled. I couldn't manage to decompile.
:1000FC50 ; Exported entry 15. CP5200_Program_AddPicture
:1000FC50
:1000FC50 ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦
:1000FC50
:1000FC50
:1000FC50 public CP5200_Program_AddPicture
:1000FC50 CP5200_Program_AddPicture proc near
:1000FC50
:1000FC50 arg_0 = dword ptr 8
:1000FC50 arg_4 = dword ptr 0Ch
:1000FC50 arg_8 = dword ptr 10h
:1000FC50 arg_C = dword ptr 14h
:1000FC50 arg_10 = dword ptr 18h
:1000FC50 arg_14 = dword ptr 1Ch
:1000FC50 arg_18 = dword ptr 20h
:1000FC50 arg_1C = dword ptr 24h
:1000FC50
:1000FC50 push ebx
:1000FC51 mov ebx, [esp+arg_0]
:1000FC55 test ebx, ebx
:1000FC57 jnz short loc_1000FC60
:1000FC59 or eax, 0FFFFFFFFh
:1000FC5C pop ebx
:1000FC5D retn 20h
:1000FC60 ; ---------------------------------------------------------------------------
:1000FC60
:1000FC60 loc_1000FC60: ; CODE XREF: CP5200_Program_AddPicture+7j
:1000FC60 push esi
:1000FC61 push edi
:1000FC62 mov edi, ebx
:1000FC64 mov esi, offset aCprogram ; "CProgram"
:1000FC69 mov ecx, 9
:1000FC6E xor eax, eax
:1000FC70 repe cmpsb
:1000FC72 jz short loc_1000FC79
:1000FC74 sbb eax, eax
:1000FC76 sbb eax, 0FFFFFFFFh
:1000FC79
:1000FC79 loc_1000FC79: ; CODE XREF: CP5200_Program_AddPicture+22j
:1000FC79 test eax, eax
:1000FC7B jz short loc_1000FC86
:1000FC7D pop edi
:1000FC7E pop esi
:1000FC7F or eax, 0FFFFFFFFh
:1000FC82 pop ebx
:1000FC83 retn 20h
:1000FC86 ; ---------------------------------------------------------------------------
:1000FC86
:1000FC86 loc_1000FC86: ; CODE XREF: CP5200_Program_AddPicture+2Bj
:1000FC86 mov esi, [esp+8+arg_4]
:1000FC8A test esi, esi
:1000FC8C jl short loc_1000FD07
:1000FC8E mov ecx, ebx
:1000FC90 call sub_10018020
:1000FC95 cmp esi, eax
:1000FC97 jge short loc_1000FD07
:1000FC99 push esi
:1000FC9A mov ecx, ebx
:1000FC9C call sub_10018030
:1000FCA1 push 3Eh
:1000FCA3 mov edi, eax
:1000FCA5 call ??2#YAPAXI#Z ; operator new(uint)
:1000FCAA add esp, 4
:1000FCAD test eax, eax
:1000FCAF jz short loc_1000FCBE
:1000FCB1 mov ecx, eax
:1000FCB3 call sub_100012E0
:1000FCB8 mov esi, eax
:1000FCBA test esi, esi
:1000FCBC jnz short loc_1000FCC9
:1000FCBE
:1000FCBE loc_1000FCBE: ; CODE XREF: CP5200_Program_AddPicture+5Fj
:1000FCBE pop edi
:1000FCBF pop esi
:1000FCC0 mov eax, 0FFFFFFFCh
:1000FCC5 pop ebx
:1000FCC6 retn 20h
:1000FCC9 ; ---------------------------------------------------------------------------
:1000FCC9
:1000FCC9 loc_1000FCC9: ; CODE XREF: CP5200_Program_AddPicture+6Cj
:1000FCC9 mov eax, [esp+8+arg_8]
:1000FCCD push eax
:1000FCCE lea ecx, [esi+25h]
:1000FCD1 call sub_100076A0
:1000FCD6 mov ecx, [esp+8+arg_C]
:1000FCDA mov edx, [esp+8+arg_10]
:1000FCDE mov eax, [esp+8+arg_14]
:1000FCE2 mov [esi+2Ah], ecx
:1000FCE5 mov ecx, [esp+8+arg_18]
:1000FCE9 mov [esi+2Eh], edx
:1000FCEC mov edx, [esp+8+arg_1C]
:1000FCF0 mov [esi+36h], ecx
:1000FCF3 push esi
:1000FCF4 mov ecx, edi
:1000FCF6 mov [esi+32h], eax
:1000FCF9 mov [esi+3Ah], edx
:1000FCFC call sub_100015A0
:1000FD01 pop edi
:1000FD02 pop esi
:1000FD03 pop ebx
:1000FD04 retn 20h
:1000FD0F CP5200_Program_AddPicture endp
Exported fn(): CP5200_Program_SaveToFile - Ord:0013h
:1000CE80 8B542404 mov edx, dword ptr [esp+04]
:1000CE84 85D2 test edx, edx
:1000CE86 741F je 1000CEA7
:1000CE88 56 push esi
:1000CE89 57 push edi
:1000CE8A 8BFA mov edi, edx
:1000CE8C BE8C060610 mov esi, 1006068C
:1000CE91 B909000000 mov ecx, 00000009
:1000CE96 33C0 xor eax, eax
:1000CE98 F3 repz
:1000CE99 A6 cmpsb
:1000CE9A 5F pop edi
:1000CE9B 5E pop esi
:1000CE9C 7405 je 1000CEA3
:1000CE9E 1BC0 sbb eax, eax
:1000CEA0 83D8FF sbb eax, FFFFFFFF
I'm writing in VS 2012, with openframeworks version of_v0.8.3_vs_release.
Does the decompiled code give any clues as to what's happening in the DLL that causes this behavior?