I have an inner function in a larger program that is somehow changing a float value to "nan" when I expect it to be zero. I have trimmed the function down to the simplest form, with no parameters:
static void func(void)
{
int a = 1;
float x = 0.0f;
float v = 0.0f;
printf("x(%f), ", x);
x += (float)a * v;
printf("x(%f), ", x);
printf("(int)x: %d, ", (int)x);
}
This gives the output:
x(0.000000), x(nan), (int)x: -2147483648
If I remove the variable a and hardcode the value (1), the nan value goes away. Similarly, if I remove the line x += (float)a * v;, everything prints as expected (all zeroes).
The frustrating part is that I can't reproduce this by just creating a new program and tossing this in main(). When I try that, the program works perfectly and outputs:
x(0.000000), x(0.000000), (int)x: 0
Disassembly from the function in the actual program:
00000029 <_func>:
29: 55 push %ebp
2a: 89 e5 mov %esp,%ebp
2c: 83 ec 38 sub $0x38,%esp
2f: c7 45 f4 01 00 00 00 movl $0x1,-0xc(%ebp)
36: a1 18 00 00 00 mov 0x18,%eax
3b: 89 45 f0 mov %eax,-0x10(%ebp)
3e: a1 18 00 00 00 mov 0x18,%eax
43: 89 45 ec mov %eax,-0x14(%ebp)
46: d9 45 f0 flds -0x10(%ebp)
49: dd 5c 24 04 fstpl 0x4(%esp)
4d: c7 04 24 00 00 00 00 movl $0x0,(%esp)
54: e8 a7 ff ff ff call 0 <_printf>
59: d9 45 f0 flds -0x10(%ebp)
5c: db 45 f4 fildl -0xc(%ebp)
5f: d9 5d e4 fstps -0x1c(%ebp)
62: d9 45 e4 flds -0x1c(%ebp)
65: d9 45 ec flds -0x14(%ebp)
68: de c9 fmulp %st,%st(1)
6a: de c1 faddp %st,%st(1)
6c: d9 5d f0 fstps -0x10(%ebp)
6f: d9 45 f0 flds -0x10(%ebp)
72: dd 5c 24 04 fstpl 0x4(%esp)
76: c7 04 24 00 00 00 00 movl $0x0,(%esp)
7d: e8 7e ff ff ff call 0 <_printf>
82: d9 45 f0 flds -0x10(%ebp)
85: d9 7d e2 fnstcw -0x1e(%ebp)
88: 0f b7 45 e2 movzwl -0x1e(%ebp),%eax
8c: b4 0c mov $0xc,%ah
8e: 66 89 45 e0 mov %ax,-0x20(%ebp)
92: d9 6d e0 fldcw -0x20(%ebp)
95: db 5d dc fistpl -0x24(%ebp)
98: d9 6d e2 fldcw -0x1e(%ebp)
9b: 8b 45 dc mov -0x24(%ebp),%eax
9e: 89 44 24 04 mov %eax,0x4(%esp)
a2: c7 04 24 08 00 00 00 movl $0x8,(%esp)
a9: e8 52 ff ff ff call 0 <_printf>
ae: c9 leave
af: c3 ret
Disassembly from stand-alone function (as main()):
00000000 <_main>:
0: 55 push %ebp
1: 89 e5 mov %esp,%ebp
3: 83 e4 f0 and $0xfffffff0,%esp
6: 83 ec 30 sub $0x30,%esp
9: e8 00 00 00 00 call e <_main+0xe>
e: c7 44 24 2c 01 00 00 movl $0x1,0x2c(%esp)
15: 00
16: a1 18 00 00 00 mov 0x18,%eax
1b: 89 44 24 28 mov %eax,0x28(%esp)
1f: a1 18 00 00 00 mov 0x18,%eax
24: 89 44 24 24 mov %eax,0x24(%esp)
28: d9 44 24 28 flds 0x28(%esp)
2c: dd 5c 24 04 fstpl 0x4(%esp)
30: c7 04 24 00 00 00 00 movl $0x0,(%esp)
37: e8 00 00 00 00 call 3c <_main+0x3c>
3c: db 44 24 2c fildl 0x2c(%esp)
40: d8 4c 24 24 fmuls 0x24(%esp)
44: d9 44 24 28 flds 0x28(%esp)
48: de c1 faddp %st,%st(1)
4a: d9 5c 24 28 fstps 0x28(%esp)
4e: d9 44 24 28 flds 0x28(%esp)
52: dd 5c 24 04 fstpl 0x4(%esp)
56: c7 04 24 00 00 00 00 movl $0x0,(%esp)
5d: e8 00 00 00 00 call 62 <_main+0x62>
62: d9 44 24 28 flds 0x28(%esp)
66: d9 7c 24 1e fnstcw 0x1e(%esp)
6a: 0f b7 44 24 1e movzwl 0x1e(%esp),%eax
6f: b4 0c mov $0xc,%ah
71: 66 89 44 24 1c mov %ax,0x1c(%esp)
76: d9 6c 24 1c fldcw 0x1c(%esp)
7a: db 5c 24 18 fistpl 0x18(%esp)
7e: d9 6c 24 1e fldcw 0x1e(%esp)
82: 8b 44 24 18 mov 0x18(%esp),%eax
86: 89 44 24 04 mov %eax,0x4(%esp)
8a: c7 04 24 08 00 00 00 movl $0x8,(%esp)
91: e8 00 00 00 00 call 96 <_main+0x96>
96: b8 00 00 00 00 mov $0x0,%eax
9b: c9 leave
9c: c3 ret
9d: 90 nop
9e: 90 nop
9f: 90 nop
This issue is often the result of undefined behavior. In this specific instance, there was an implicit function declaration (a header file hadn't been included elsewhere in the program) which caused UB, and resulted in this bug.
Related
I'm working on an assignment for class where I have to interpret assembly. I know the input to defuse the bomb is 442, but I'm not exactly sure why.
8048c80: 83 ec 2c sub $0x2c,%esp
8048c83: c7 44 24 1c 00 00 00 movl $0x0,0x1c(%esp)
8048c8a: 00
8048c8b: 8d 44 24 1c lea 0x1c(%esp),%eax
8048c8f: 89 44 24 08 mov %eax,0x8(%esp)
8048c93: c7 44 24 04 64 a7 04 movl $0x804a764,0x4(%esp)
8048c9a: 08
8048c9b: 8b 44 24 30 mov 0x30(%esp),%eax
8048c9f: 89 04 24 mov %eax,(%esp)
8048ca2: e8 59 fc ff ff call 8048900 <__isoc99_sscanf#plt>
8048ca7: 83 f8 01 cmp $0x1,%eax
8048caa: 74 05 je 8048cb1 <phase_1+0x31>
8048cac: e8 e4 07 00 00 call 8049495 <explode_bomb>
8048cb1: 81 7c 24 1c ba 01 00 cmpl $0x1ba,0x1c(%esp)
8048cb8: 00
8048cb9: 74 05 je 8048cc0 <phase_1+0x40>
8048cbb: e8 d5 07 00 00 call 8049495 <explode_bomb>
8048cc0: 83 c4 2c add $0x2c,%esp
8048cc3: c3 ret
Sscanf takes two values, "%d" and my inputted value, but I'm not sure where it stores the value or why %eax is 1 or why 0x1c(%esp) has the value. We store 0x0 there at the beginning, and then move 0x30(%esp), %eax, so shouldn't it be 0? Any help understanding this would be very much appreciated.
To be clear, this is x86 in at&t syntax.
I've been trying to decompile the following asm snippet(that's all I have):
55 push %rbp
48 89 e5 mov %rsp,%rbp
48 81 ec d0 00 00 00 sub $0xd0,%rsp
64 48 8b 04 25 28 00 mov %fs:0x28,%rax
00 00
48 89 45 f8 mov %rax,-0x8(%rbp)
31 c0 xor %eax,%eax
48 c7 85 30 ff ff ff movq $0x0,-0xd0(%rbp)
00 00 00 00
48 8d b5 38 ff ff ff lea -0xc8(%rbp),%rsi
b8 00 00 00 00 mov $0x0,%eax
ba 18 00 00 00 mov $0x18,%edx
48 89 f7 mov %rsi,%rdi
48 89 d1 mov %rdx,%rcx
f3 48 ab rep stos %rax,%es:(%rdi)
48 8b 15 19 06 20 00 mov 0x200619(%rip),%rdx
48 8d 85 30 ff ff ff lea -0xd0(%rbp),%rax
be ce 0f 40 00 mov $0x400fce,%esi
48 89 c7 mov %rax,%rdi
b8 00 00 00 00 mov $0x0,%eax
e8 4e fc ff ff callq 4008a0 <sprintf#plt>
Here is my attempt:
char buf[192] = {0};
sprintf(buf, "hello %s", name);
I've compiled this with gcc 4.8.5, and it gave me:
55 push %rbp
48 89 e5 mov %rsp,%rbp
48 81 ec d0 00 00 00 sub $0xd0,%rsp
64 48 8b 04 25 28 00 mov %fs:0x28,%rax
00 00
48 89 45 f8 mov %rax,-0x8(%rbp)
31 c0 xor %eax,%eax
48 8d b5 30 ff ff ff lea -0xd0(%rbp),%rsi
b8 00 00 00 00 mov $0x0,%eax
ba 18 00 00 00 mov $0x18,%edx
48 89 f7 mov %rsi,%rdi
48 89 d1 mov %rdx,%rcx
f3 48 ab rep stos %rax,%es:(%rdi)
48 8b 15 14 14 20 00 mov 0x201414(%rip),%rdx
48 8d 85 30 ff ff ff lea -0xd0(%rbp),%rax
be 2e 10 40 00 mov $0x40102e,%esi
48 89 c7 mov %rax,%rdi
b8 00 00 00 00 mov $0x0,%eax
e8 cb fb ff ff callq 4008a0 <sprintf#plt>
I'm struggling to figure out why this exists:
movq $0x0,-0xd0(%rbp)
and also the subsequent usage of -0xd0(%rbp) as a pointer for the argument to sprintf. I'm puzzled because the rep stos begin at -0xc8(%rbp) and not -0xd0(%rbp).
This is probably compiler specific, but still I'm curious what could possibly be the original code that produced that asm.
I imagine something like:
char buf[192] = {0, 0, 0, 0, 0, 0, 0, 0};
sprintf(buf + 8, "hello %s", name);
... would give you that output.
The movq instruction you refer to stores 0 (an 8-byte quantity) at the beginning of an array. The -0xc8(%rbp) comes from copying a string to an offset within the array.
Profiling the code with ocount shows more cycles with penalty on and lesser cycles with penalty off. I'm trying to understand why there is more penalty when the penalty flag is on?
uint16_t arr[1010];
uint32_t r[500];
void func()
{
uint32_t i = 0;
for (i = 0; i < 1000; i+=2)
{
arr[i] = i;
arr[i+1] = i+10;
#ifdef PENALTY_ON
r[i/2] = *(uint32_t *)((uint16_t *)&arr[i+1]);
#endif
}
#ifndef PENALTY_ON
for (i = 0; i < 1000; i+=2)
{
r[i/2] = *(uint32_t *)((uint16_t *)&arr[i+1]);
}
#endif
}
Compiling both with gcc on a 32-bit machine with -O3
With PENALTY_ON
00000000 <func>:
0: 31 c0 xor %eax,%eax
2: 8d b6 00 00 00 00 lea 0x0(%esi),%esi
8: 8d 50 0a lea 0xa(%eax),%edx
b: 66 89 94 00 02 00 00 mov %dx,0x2(%eax,%eax,1)
12: 00
13: 8b 8c 00 02 00 00 00 mov 0x2(%eax,%eax,1),%ecx
1a: 89 c2 mov %eax,%edx
1c: 66 89 84 00 00 00 00 mov %ax,0x0(%eax,%eax,1)
23: 00
24: 83 c0 02 add $0x2,%eax
27: d1 ea shr %edx
29: 3d e8 03 00 00 cmp $0x3e8,%eax
2e: 89 0c 95 00 00 00 00 mov %ecx,0x0(,%edx,4)
35: 75 d1 jne 8 <func+0x8>
37: f3 c3 repz ret
Without PENALTY_ON
00000000 <func>:
0: 31 c0 xor %eax,%eax
2: 8d b6 00 00 00 00 lea 0x0(%esi),%esi
8: 8d 50 0a lea 0xa(%eax),%edx
b: 66 89 84 00 00 00 00 mov %ax,0x0(%eax,%eax,1)
12: 00
13: 66 89 94 00 02 00 00 mov %dx,0x2(%eax,%eax,1)
1a: 00
1b: 83 c0 02 add $0x2,%eax
1e: 3d e8 03 00 00 cmp $0x3e8,%eax
23: 75 e3 jne 8 <func+0x8>
25: 66 31 c0 xor %ax,%ax
28: 8b 8c 00 02 00 00 00 mov 0x2(%eax,%eax,1),%ecx
2f: 89 c2 mov %eax,%edx
31: 83 c0 02 add $0x2,%eax
34: d1 ea shr %edx
36: 3d e8 03 00 00 cmp $0x3e8,%eax
3b: 89 0c 95 00 00 00 00 mov %ecx,0x0(,%edx,4)
42: 75 e4 jne 28 <func+0x28>
44: f3 c3 repz ret
I think the reason is that a Read-after-Write stall occurs with PENALTY_ON
b: 66 89 94 00 02 00 00 mov %dx,0x2(%eax,%eax,1)
12: 00
13: 8b 8c 00 02 00 00 00 mov 0x2(%eax,%eax,1),%ecx
I'm learning Assembly. I wrote the below c program containing switch case, created the object file(gcc -o filename filename.c), then took the object dump. But I didn't find the Labels and jump tables in the object dump.
Can anybody tell me why the jump table is not getting generated ? Like the ones mention here
Link
Code
C file
int main() {
int i = 0;
int n = 9, z = 99 , p = 999;
switch( i )
{
case -1:
n++;
printf("value n=%d",n);
break;
case 0 :
z++;
printf("value z=%d",z);
break;
case 1 :
p++;
printf("value p=%d",p);
break;
case 2 :
p++;
printf("value p=%d",p);
break;
case 3 :
p++;
printf("value p=%d",p);
break;
case 4 :
p++;
printf("value p=%d",p);
break;
case 5 :
p++;
printf("value p=%d",p);
break;
}
printf("Values n=%d z=%d p=%d \n",n,z,p);
return 0;
}
Below is the main section
0804841d <main>:
804841d: 55 push %ebp
804841e: 89 e5 mov %esp,%ebp
8048420: 83 e4 f0 and $0xfffffff0,%esp
8048423: 83 ec 20 sub $0x20,%esp
8048426: c7 44 24 1c 00 00 00 movl $0x0,0x1c(%esp)
804842d: 00
804842e: c7 44 24 10 09 00 00 movl $0x9,0x10(%esp)
8048435: 00
8048436: c7 44 24 14 63 00 00 movl $0x63,0x14(%esp)
804843d: 00
804843e: c7 44 24 18 e7 03 00 movl $0x3e7,0x18(%esp)
8048445: 00
8048446: 8b 44 24 1c mov 0x1c(%esp),%eax
804844a: 83 c0 01 add $0x1,%eax
804844d: 83 f8 06 cmp $0x6,%eax
8048450: 0f 87 cb 00 00 00 ja 8048521 <main+0x104>
8048456: 8b 04 85 1c 86 04 08 mov 0x804861c(,%eax,4),%eax
804845d: ff e0 jmp *%eax
804845f: 83 44 24 10 01 addl $0x1,0x10(%esp)
8048464: 8b 44 24 10 mov 0x10(%esp),%eax
8048468: 89 44 24 04 mov %eax,0x4(%esp)
804846c: c7 04 24 e0 85 04 08 movl $0x80485e0,(%esp)
8048473: e8 78 fe ff ff call 80482f0 <printf#plt>
8048478: e9 a4 00 00 00 jmp 8048521 <main+0x104>
804847d: 83 44 24 14 01 addl $0x1,0x14(%esp)
8048482: 8b 44 24 14 mov 0x14(%esp),%eax
8048486: 89 44 24 04 mov %eax,0x4(%esp)
804848a: c7 04 24 eb 85 04 08 movl $0x80485eb,(%esp)
8048491: e8 5a fe ff ff call 80482f0 <printf#plt>
8048496: e9 86 00 00 00 jmp 8048521 <main+0x104>
804849b: 83 44 24 18 01 addl $0x1,0x18(%esp)
80484a0: 8b 44 24 18 mov 0x18(%esp),%eax
80484a4: 89 44 24 04 mov %eax,0x4(%esp)
80484a8: c7 04 24 f6 85 04 08 movl $0x80485f6,(%esp)
80484af: e8 3c fe ff ff call 80482f0 <printf#plt>
80484b4: eb 6b jmp 8048521 <main+0x104>
80484b6: 83 44 24 18 01 addl $0x1,0x18(%esp)
80484bb: 8b 44 24 18 mov 0x18(%esp),%eax
80484bf: 89 44 24 04 mov %eax,0x4(%esp)
80484c3: c7 04 24 f6 85 04 08 movl $0x80485f6,(%esp)
80484ca: e8 21 fe ff ff call 80482f0 <printf#plt>
80484cf: eb 50 jmp 8048521 <main+0x104>
80484d1: 83 44 24 18 01 addl $0x1,0x18(%esp)
80484d6: 8b 44 24 18 mov 0x18(%esp),%eax
80484da: 89 44 24 04 mov %eax,0x4(%esp)
80484de: c7 04 24 f6 85 04 08 movl $0x80485f6,(%esp)
80484e5: e8 06 fe ff ff call 80482f0 <printf#plt>
80484ea: eb 35 jmp 8048521 <main+0x104>
80484ec: 83 44 24 18 01 addl $0x1,0x18(%esp)
80484f1: 8b 44 24 18 mov 0x18(%esp),%eax
80484f5: 89 44 24 04 mov %eax,0x4(%esp)
80484f9: c7 04 24 f6 85 04 08 movl $0x80485f6,(%esp)
8048500: e8 eb fd ff ff call 80482f0 <printf#plt>
8048505: eb 1a jmp 8048521 <main+0x104>
8048507: 83 44 24 18 01 addl $0x1,0x18(%esp)
804850c: 8b 44 24 18 mov 0x18(%esp),%eax
8048510: 89 44 24 04 mov %eax,0x4(%esp)
8048514: c7 04 24 f6 85 04 08 movl $0x80485f6,(%esp)
804851b: e8 d0 fd ff ff call 80482f0 <printf#plt>
8048520: 90 nop
8048521: 8b 44 24 18 mov 0x18(%esp),%eax
8048525: 89 44 24 0c mov %eax,0xc(%esp)
8048529: 8b 44 24 14 mov 0x14(%esp),%eax
804852d: 89 44 24 08 mov %eax,0x8(%esp)
8048531: 8b 44 24 10 mov 0x10(%esp),%eax
8048535: 89 44 24 04 mov %eax,0x4(%esp)
8048539: c7 04 24 01 86 04 08 movl $0x8048601,(%esp)
8048540: e8 ab fd ff ff call 80482f0 <printf#plt>
8048545: b8 00 00 00 00 mov $0x0,%eax
804854a: c9 leave
804854b: c3 ret
804854c: 66 90 xchg %ax,%ax
804854e: 66 90 xchg %ax,%ax
Below is the .rodata section
Disassembly of section .rodata:
080485d8 <_fp_hw>:
80485d8: 03 00 add (%eax),%eax
...
Can anybody let me know why this is behaving like this?
Thanks in Advance
Your jump table is located at address 0x804861c. If you dump this address, I'm pretty sure, you'll find the values 0x804845f, 0x804847d, 0x804849b, etc. since these values correspond to the addresses of the branches of the switch statement.
What happens is that first it is ensured that the value of i (0x1c(%esp))is between 0 and 6 (and jump if above, ja, to last printf) and if it is between, uses its value multiplied by 4 (sizeof addresses on your architecture) as an offset into the jump table (0x804861c(,%eax,4),%eax).
I'm not sure what you're looking for exactly, or what you're trying to achieve, but as #Jens Gustedt pointed out, you should use the -S switch if you want to observe the assembly generated.
Additionally, beware that your code can easily be optimised by the compiler, i.e. as soon as you use the -O switch your assembly will probably shrink down to the last printf and the return statement, since the whole code execution can be predicted and useless parts can be omitted.
How do I disassemble an object program made on C(linux)?
Can anyone please help me with the command line.
Use objdump:
objdump -d -C file.o
Sample output:
...
0000015e <add_exclude>:
15e: 55 push %ebp
15f: 89 e5 mov %esp,%ebp
161: 83 ec 08 sub $0x8,%esp
164: a1 10 00 00 00 mov 0x10,%eax
169: 3b 05 14 00 00 00 cmp 0x14,%eax
16f: 7f 54 jg 1c5 <add_exclude+0x67>
171: 83 3d 10 00 00 00 00 cmpl $0x0,0x10
178: 75 1f jne 199 <add_exclude+0x3b>
17a: 83 ec 0c sub $0xc,%esp
17d: c7 05 10 00 00 00 40 movl $0x40,0x10
184: 00 00 00
187: 68 00 01 00 00 push $0x100
18c: e8 fc ff ff ff call 18d <add_exclude+0x2f>
191: 83 c4 10 add $0x10,%esp
...