This question already has answers here:
Reaching end of function without return statement
(2 answers)
Closed 4 years ago.
This is a simple function to check whether the given number is prime or not and works for the most part except for 2 and 3 (as it doesn't enter the for loop) but they are already prime so no checking is required and the flag should remain untouched.But notice how I put the return statement inside the for loop(This was by mistake) so for integers 2 and 3 as they do not enter the loop the function should return 0(or so I assumed) but they always return 1.why? Is it because the program terminated incorrectly? then why always 1? it can be any non-zero integer right?and are there cases where the main() itself returns a 1?.Please clarify my doubts.Dev-C++ is the IDE used and it uses tdm-gcc 4.9.2 compiler.
int checkPrime(int n)
{
int i, isPrime = 0;
for(i = 2; i <= n/2; ++i) {
if(n % i == 0) {
isPrime = 1;
break;
}
return isPrime;
}
}
Your return statement is in wrong place. You should put it out of for loop. And also in programming 1 stands for true and 0 for false, so you are asking if n is prime and for 17 your function returns 0 (false), but it is prime:
int checkPrime(int n)
{
int i, isPrime = 1;
for(i = 2; i <= n/2; ++i) {
if(n % i == 0) {
isPrime = 0;
break;
}
}
return isPrime;
}
On x86 architecture, the return value of function is in %eax register.
Value present there would be regarded as the return value of the function checkPrime.
And in the %eax register, the value present would be '1', so '1' was treated as the return value.
Proof (Passing '2' to checkPrime() and at the end eax holds 1):-
Dump of assembler code for function checkPrime:
0x0000000000400526 <+0>: push %rbp
0x0000000000400527 <+1>: mov %rsp,%rbp
0x000000000040052a <+4>: mov %edi,-0x14(%rbp)
0x000000000040052d <+7>: movl $0x0,-0x8(%rbp)
0x0000000000400534 <+14>: movl $0x2,-0x4(%rbp)
0x000000000040053b <+21>: nop
0x000000000040053c <+22>: mov -0x14(%rbp),%eax
0x000000000040053f <+25>: mov %eax,%edx
0x0000000000400541 <+27>: shr $0x1f,%edx
0x0000000000400544 <+30>: add %edx,%eax
0x0000000000400546 <+32>: sar %eax
0x0000000000400548 <+34>: cmp -0x4(%rbp),%eax
0x000000000040054b <+37>: jl 0x400568 <checkPrime+66>
0x000000000040054d <+39>: mov -0x14(%rbp),%eax
0x0000000000400550 <+42>: cltd
0x0000000000400551 <+43>: idivl -0x4(%rbp)
0x0000000000400554 <+46>: mov %edx,%eax
0x0000000000400556 <+48>: test %eax,%eax
0x0000000000400558 <+50>: jne 0x400563 <checkPrime+61>
0x000000000040055a <+52>: movl $0x1,-0x8(%rbp)
0x0000000000400561 <+59>: jmp 0x400568 <checkPrime+66>
0x0000000000400563 <+61>: mov -0x8(%rbp),%eax
0x0000000000400566 <+64>: jmp 0x400568 <checkPrime+66>
0x0000000000400568 <+66>: pop %rbp
0x0000000000400569 <+67>: retq
(gdb) break *0x0000000000400569
Breakpoint 1 at 0x400569: file ./test.c, line 19.
(gdb) r
Starting program: /home/syed/Desktop/a.out
Breakpoint 1, 0x0000000000400569 in checkPrime (n=2) at ./test.c:19
19 }
(gdb) info registers eax
eax 0x1 1
Related
So a little background. I am a beginner with c and assembly code, we have an "bomb" assignment (written in c)which calls methods that require certain passwords, but the code is not visible and I need to determine the correct password by looking at the assembly code.
The code indicates the password for this method is 6 numbers, which is passed as "input" to method phase 2 (I am trying to avoid triggering ).
I am having trouble understanding what is going on here so if anyone can help me translate this into C code, or if i need to look in any particular registers/locations it would help greatly. There are 4 more phases which are each supposed to be more complex so I want to get a good understanding in how to approach reading these.
Also if anyone has a good resource (like a printable table) with assembly code keywords that would be helpful too, and also if there are any differences between 32-bit and 64-bit registers i need to worry about other than the register names..
(gdb) disas
Dump of assembler code for function phase_2:
0x0000000000400f49 <+0>: push %rbp
0x0000000000400f4a <+1>: push %rbx
0x0000000000400f4b <+2>: sub $0x28,%rsp
0x0000000000400f4f <+6>: mov %fs:0x28,%rax
0x0000000000400f58 <+15>: mov %rax,0x18(%rsp)
0x0000000000400f5d <+20>: xor %eax,%eax
0x0000000000400f5f <+22>: mov %rsp,%rsi
0x0000000000400f62 <+25>: callq 0x401708 <read_six_numbers>
0x0000000000400f67 <+30>: cmpl $0x0,(%rsp)
0x0000000000400f6b <+34>: jne 0x400f74 <phase_2+43>
0x0000000000400f6d <+36>: cmpl $0x1,0x4(%rsp)
0x0000000000400f72 <+41>: je 0x400f79 <phase_2+48>
0x0000000000400f74 <+43>: callq 0x4016d2 <explode_bomb>
0x0000000000400f79 <+48>: mov %rsp,%rbx
0x0000000000400f7c <+51>: lea 0x10(%rsp),%rbp
0x0000000000400f81 <+56>: mov 0x4(%rbx),%eax
0x0000000000400f84 <+59>: add (%rbx),%eax
0x0000000000400f86 <+61>: cmp %eax,0x8(%rbx)
0x0000000000400f89 <+64>: je 0x400f90 <phase_2+71>
=> 0x0000000000400f8b <+66>: callq 0x4016d2 <explode_bomb>
0x0000000000400f90 <+71>: add $0x4,%rbx
0x0000000000400f94 <+75>: cmp %rbp,%rbx
0x0000000000400f97 <+78>: jne 0x400f81 <phase_2+56>
0x0000000000400f99 <+80>: mov 0x18(%rsp),%rax
0x0000000000400f9e <+85>: xor %fs:0x28,%rax
0x0000000000400fa7 <+94>: je 0x400fae <phase_2+101>
0x0000000000400fa9 <+96>: callq 0x400b90 <__stack_chk_fail#plt>
0x0000000000400fae <+101>: add $0x28,%rsp
0x0000000000400fb2 <+105>: pop %rbx
0x0000000000400fb3 <+106>: pop %rbp
0x0000000000400fb4 <+107>: retq
End of assembler dump.
Your assembly is equivalent to this, see phase_2 function
#include <stdio.h>
__attribute__((noinline)) void read_six_numbers(void *xxx, int *num)
{
num[0] = 0;
num[1] = 1;
num[2] = 1;
num[3] = 2;
num[4] = 3;
num[5] = 5;
}
__attribute__((noinline)) void explode_bomb()
{
printf("explode_bomb.\n");
}
void phase_2(void *xxx)
{
int num[6];
int i;
read_six_numbers(xxx, num);
if (num[0] != 0 || num[1] != 1)
explode_bomb();
for (i = 0; i < 4; i++) {
if (num[i] + num[i + 1] == num[i + 2])
continue;
explode_bomb();
}
}
int main()
{
phase_2(NULL);
return 0;
}
I am having trouble this piece of code in assembly language.
Essentially I have to input 2 numbers that matches 2 numbers the code is comparing with.
On line 0x08048c47 in phase_4, it compares the first input with 2, so I know the first input has to be 2. It then moves 4 spaces from the first input to next input, which then gets 2 subtracted from it. Now the (input-2) is compared with 2. It will continue the instruction if the inputs are below than or equal to 2. I've tested this with numbers 2,3,4 which pass the comparison. Other numbers greater than 4 and less than 2 do not pass the comparison and will cause the bomb to explode.
I'm stuck on this part because the value being returned from func4 is not the same was the value represented at 0x08048c6e in phase_4, which is 8(%esp). On my computer when I debug it, it shows that it is 8, and the answers to my inputs 2,3,4 are 40, 60, 80 respectively.
disas func4
0x08048bda <+0>: push %edi
0x08048bdb <+1>: push %esi
0x08048bdc <+2>: push %ebx
0x08048bdd <+3>: mov 0x10(%esp),%ebx
0x08048be1 <+7>: mov 0x14(%esp),%edi
0x08048be5 <+11>: test %ebx,%ebx
0x08048be7 <+13>: jle 0x8048c14 <func4+58>
0x08048be9 <+15>: mov %edi,%eax
0x08048beb <+17>: cmp $0x1,%ebx
0x08048bee <+20>: je 0x8048c19 <func4+63>
0x08048bf0 <+22>: sub $0x8,%esp
0x08048bf3 <+25>: push %edi
0x08048bf4 <+26>: lea -0x1(%ebx),%eax
0x08048bf7 <+29>: push %eax
0x08048bf8 <+30>: call 0x8048bda <func4>
0x08048bfd <+35>: add $0x8,%esp
0x08048c00 <+38>: lea (%edi,%eax,1),%esi
0x08048c03 <+41>: push %edi
0x08048c04 <+42>: sub $0x2,%ebx
0x08048c07 <+45>: push %ebx
0x08048c08 <+46>: call 0x8048bda <func4>
0x08048c0d <+51>: add $0x10,%esp
0x08048c10 <+54>: add %esi,%eax
0x08048c12 <+56>: jmp 0x8048c19 <func4+63>
0x08048c14 <+58>: mov $0x0,%eax
0x08048c19 <+63>: pop %ebx
0x08048c1a <+64>: pop %esi
0x08048c1b <+65>: pop %edi
0x08048c1c <+66>: ret
disas phase_4
0x08048c1d <+0>: sub $0x1c,%esp
0x08048c20 <+3>: mov %gs:0x14,%eax
0x08048c26 <+9>: mov %eax,0xc(%esp)
0x08048c2a <+13>: xor %eax,%eax
0x08048c2c <+15>: lea 0x4(%esp),%eax
0x08048c30 <+19>: push %eax
0x08048c31 <+20>: lea 0xc(%esp),%eax
0x08048c35 <+24>: push %eax
0x08048c36 <+25>: push $0x804a25f
0x08048c3b <+30>: pushl 0x2c(%esp)
0x08048c3f <+34>: call 0x8048810 <__isoc99_sscanf#plt>
0x08048c44 <+39>: add $0x10,%esp
0x08048c47 <+42>: cmp $0x2,%eax
0x08048c4a <+45>: jne 0x8048c58 <phase_4+59>
0x08048c4c <+47>: mov 0x4(%esp),%eax
0x08048c50 <+51>: sub $0x2,%eax
0x08048c53 <+54>: cmp $0x2,%eax
0x08048c56 <+57>: jbe 0x8048c5d <phase_4+64>
0x08048c58 <+59>: call 0x8049123 <explode_bomb>
0x08048c5d <+64>: sub $0x8,%esp
0x08048c60 <+67>: pushl 0xc(%esp)
0x08048c64 <+71>: push $0x6
0x08048c66 <+73>: call 0x8048bda <func4>
0x08048c6b <+78>: add $0x10,%esp
0x08048c6e <+81>: cmp 0x8(%esp),%eax
0x08048c72 <+85>: je 0x8048c79 <phase_4+92>
0x08048c74 <+87>: call 0x8049123 <explode_bomb>
0x08048c79 <+92>: mov 0xc(%esp),%eax
0x08048c7d <+96>: xor %gs:0x14,%eax
0x08048c84 <+103>: je 0x8048c8b <phase_4+110>
0x08048c86 <+105>: call 0x8048790 <__stack_chk_fail#plt>
0x08048c8b <+110>: add $0x1c,%esp
0x08048c8e <+113>: ret
8(%esp) is the first number, under the framework of x86.
enter 40 2 or 60 3 or 80 4 should work.
Equivalent to the following logic
#include <stdio.h>
#include <stdlib.h>
void explode_bomb()
{
printf("explode bomb.\n");
exit(1);
}
unsigned func4(int val, unsigned num)
{
int ret;
if (val <= 0)
return 0;
if (num == 1)
return 1;
ret = func4(val - 1, num);
ret += num;
val -= 2;
ret += func4(val, num);
return ret;
}
void phase_4(const char *input)
{
unsigned num1, num2;
if (sscanf(input, "%u %u", &num1, &num2) != 2)
explode_bomb();
if (num2 - 2 > 2)
explode_bomb();
if (func4(6, num2) != num1)
explode_bomb();
}
int main()
{
phase_4("40 2");
phase_4("60 3");
phase_4("80 4");
printf("success.\n");
return 0;
}
I have binary Phase that is not returning required result i.e 12. Any suggestions?
Phase 4
Dump of assembler code for function phase_4:
0x000000000040100b <+0>: sub $0x18,%rsp
0x000000000040100f <+4>: lea 0x8(%rsp),%rcx
0x0000000000401014 <+9>: lea 0xc(%rsp),%rdx
0x0000000000401019 <+14>: mov $0x40278d,%esi
0x000000000040101e <+19>: mov $0x0,%eax
0x0000000000401023 <+24>: callq 0x400b90 <__isoc99_sscanf#plt>
0x0000000000401028 <+29>: cmp $0x2,%eax
=> 0x000000000040102b <+32>: je 0x401054 <phase_4+73>
0x000000000040102d <+34>: callq 0x401538 <explode_bomb>
0x0000000000401032 <+39>: mov $0xe,%edx
0x0000000000401037 <+44>: mov $0x0,%esi
0x000000000040103c <+49>: mov 0xc(%rsp),%edi
0x0000000000401040 <+53>: callq 0x400fd7 <func4>
0x0000000000401045 <+58>: cmp $0x12,%eax
0x0000000000401048 <+61>: je 0x40105d <phase_4+82>
0x000000000040104a <+63>: callq 0x401538 <explode_bomb>
0x000000000040104f <+68>: add $0x18,%rsp
0x0000000000401053 <+72>: retq
0x0000000000401054 <+73>: cmpl $0xe,0xc(%rsp)
0x0000000000401059 <+78>: jbe 0x401032 <phase_4+39>
0x000000000040105b <+80>: jmp 0x40102d <phase_4+34>
0x000000000040105d <+82>: cmpl $0x12,0x8(%rsp)
0x0000000000401062 <+87>: jne 0x40104a <phase_4+63>
0x0000000000401064 <+89>: jmp 0x40104f <phase_4+68>
End of assembler dump.
func4 is as follows:
Dump of assembler code for function func4:
=> 0x0000000000400fd7 <+0>: push %rbx
0x0000000000400fd8 <+1>: mov %edx,%eax
0x0000000000400fda <+3>: sub %esi,%eax
0x0000000000400fdc <+5>: mov %eax,%ebx
0x0000000000400fde <+7>: shr $0x1f,%ebx
0x0000000000400fe1 <+10>: add %eax,%ebx
0x0000000000400fe3 <+12>: sar %ebx
0x0000000000400fe5 <+14>: add %esi,%ebx
0x0000000000400fe7 <+16>: cmp %edi,%ebx
0x0000000000400fe9 <+18>: jg 0x400ff3 <func4+28>
0x0000000000400feb <+20>: cmp %edi,%ebx
0x0000000000400fed <+22>: jl 0x400fff <func4+40>
0x0000000000400fef <+24>: mov %ebx,%eax
0x0000000000400ff1 <+26>: pop %rbx
0x0000000000400ff2 <+27>: retq
0x0000000000400ff3 <+28>: lea -0x1(%rbx),%edx
0x0000000000400ff6 <+31>: callq 0x400fd7 <func4>
0x0000000000400ffb <+36>: add %eax,%ebx
0x0000000000400ffd <+38>: jmp 0x400fef <func4+24>
0x0000000000400fff <+40>: lea 0x1(%rbx),%esi
0x0000000000401002 <+43>: callq 0x400fd7 <func4>
0x0000000000401007 <+48>: add %eax,%ebx
0x0000000000401009 <+50>: jmp 0x400fef <func4+24>
End of assembler dump.
I have written a test C program that I believe equivalent to above assembly code for func4.
#include <stdio.h>
int main()
{
int i=0;
for(int i=0;i<15;i++)
{
int z=func4(i,0,14);
printf("in main program: For input %d -> %d\n",i,z);
}
return 0;
}
int func4(int x, int low, int high) {
int mid = (low + high) / 2;
if (x == mid) {
return (mid);
} else if (x < mid) {
int w=mid+func4(x, low, mid - 1);
return w;
} else {
int p=mid+func4(x, mid + 1, high);
return p;
}
}
This program returns OUTPUT as follows:
in main program: For input 0 -> 11
in main program: For input 1 -> 11
in main program: For input 2 -> 13
in main program: For input 3 -> 10
in main program: For input 4 -> 19
in main program: For input 5 -> 15
in main program: For input 6 -> 21
in main program: For input 7 -> 7
in main program: For input 8 -> 35
in main program: For input 9 -> 27
in main program: For input 10 -> 37
in main program: For input 11 -> 18
in main program: For input 12 -> 43
in main program: For input 13 -> 31
in main program: For input 14 -> 45
I figured out that function will take two arguments and the second argument should be 12. But I am not to get value 12 returned from func4.
Any suggestions??
The assembly code is actually expecting a value of 0x12 (18 rather than 12) from func4:
0x0000000000401040 <+53>: callq 0x400fd7 <func4>
0x0000000000401045 <+58>: cmp $0x12,%eax <- Compare result to 0x12
0x0000000000401048 <+61>: je 0x40105d <phase_4+82>
0x000000000040104a <+63>: callq 0x401538 <explode_bomb>
I haven't looked at your C translation of func4 for correctness, but assuming it's correct it looks like func4(11, 0, 14) gives you what you want.
I have this C code that is disassembled (AT&T) and I have some confusion with two things. The first, my understanding is that EBP-4 should be the first local variable (here, int i) on the stack. I is clearly in EBP-8 here. Why is this?
Second, is it necessary to move values into registers before performing arithmetic operations on them? (this is an x86 32 bit machine) example:
0x08048402 <+21>: mov 0x8(%ebp),%eax //move parameter a into eax
0x08048405 <+24>: add %eax,-0x4(%ebp) //r += a
Why cant this be :
0x08048405 <+24>: add 0x8(%ebp),-0x4(%ebp) //r += a
C code:
int loop_w (int a, int b){
int i = 0;
int r = a;
while ( i < 256){
r += a;
a -= b;
i += b;
}
return r;
Disassembly:
Dump of assembler code for function loop_w:
0x080483ed <+0>: push %ebp
0x080483ee <+1>: mov %esp,%ebp
0x080483f0 <+3>: sub $0x10,%esp
---------------Above is for stack setup-----------------
0x080483f3 <+6>: movl $0x0,-0x8(%ebp) //I=0
0x080483fa <+13>: mov 0x8(%ebp),%eax //move parameter a into eax
0x080483fd <+16>: mov %eax,-0x4(%ebp) //move a into local var (r=a)
0x08048400 <+19>: jmp 0x8048414 <loop_w+39> //start while loop
0x08048402 <+21>: mov 0x8(%ebp),%eax //move parameter a into eax
0x08048405 <+24>: add %eax,-0x4(%ebp) //r += a
0x08048408 <+27>: mov 0xc(%ebp),%eax //move parameter b into eax
0x0804840b <+30>: sub %eax,0x8(%ebp) //a += parameter b
0x0804840e <+33>: mov 0xc(%ebp),%eax //move parameter b into eax
0x08048411 <+36>: add %eax,-0x8(%ebp) //i+=b
0x08048414 <+39>: cmpl $0xff,-0x8(%ebp) //compare i to 256
0x0804841b <+46>: jle 0x8048402 <loop_w+21> //continue loop if failed condition
=> 0x0804841d <+48>: mov -0x4(%ebp),%eax //move r into eax
0x08048420 <+51>: leave
0x08048421 <+52>: ret //return eax
End of assembler dump.
The compiler can decide wherever it wants to place the local variable. It might have placed it at %ebp - 8 for alignment reasons.
For your second question - Do variables have to be loaded into registers before operation, depends on the operation and the instruction set provided by the architecture.
You mentioned x86. So particular to this architecture, X86 doesn't allow instructions with two memory operands (yes there are a few exceptions).
You can search per instruction basis to know what kind of operands they allow.
I'm performing a relative jump in some asm code in C. I've got the jump working as intended, but it goes back to right after the jump happens and finished running the code.
#include <stdio.h>
void function() {
asm("jmp .+0x31"); //this happens to be where I want to jump to from the function call
}
void main(int argc, char* argv[]) {
int x;
x = 0;
function();
x = 1;
x = x + 1;
printf("%d\n", x);
}
0x000000000040053f <+0>: push %rbp
0x0000000000400540 <+1>: mov %rsp,%rbp
0x0000000000400543 <+4>: sub $0x20,%rsp
0x0000000000400547 <+8>: mov %edi,-0x14(%rbp)
0x000000000040054a <+11>: mov %rsi,-0x20(%rbp)
0x000000000040054e <+15>: movl $0x0,-0x4(%rbp)
0x0000000000400555 <+22>: mov $0x0,%eax
0x000000000040055a <+27>: callq 0x400536 <function>
0x000000000040055f <+32>: movl $0x1,-0x4(%rbp)
0x0000000000400566 <+39>: addl $0x1,-0x4(%rbp)
0x000000000040056a <+43>: mov -0x4(%rbp),%eax
0x000000000040056d <+46>: mov %eax,%esi
0x000000000040056f <+48>: mov $0x400620,%edi
0x0000000000400574 <+53>: mov $0x0,%eax
0x0000000000400579 <+58>: callq 0x400410 <printf#plt>
0x000000000040057e <+63>: nop
0x000000000040057f <+64>: leaveq
0x0000000000400580 <+65>: retq
Following the call of function(), it prints a 0 as intended, but it then goes back through the code after function() is called and prints 2 as well. Am I missing how jmp works? Is there a way to exit via asm code?
The goal of this is to skip
x = 1;
x = x + 1;
and just print 0, then exit the file.
Since function doesn't execute a ret instruction, its return address is still there on the stack. That is, when main executes its ret, the return address it uses is in fact an address left by function, and lands back at x = 1; line.
To achieve your goal, function before doing a jump must adjust the stack pointer as if it has never been called.
That said, don't try this at home.