Your output is likely to be an address of "ordinary" argv
parameter, that is implicitely converted interpretedsee comment below as char
. In other words I suspect that what you have is equivalent to:
int main(int agrc, char **argv)
{
printf("%d", (char) argv);
return 0;
}
On my machine (CentOS 6 32-bit) disassembled object codes are as follows:
0x080483c4 <+0>: push %ebp
0x080483c5 <+1>: mov %esp,%ebp
0x080483c7 <+3>: and $0xfffffff0,%esp
0x080483ca <+6>: sub $0x10,%esp
0x080483cd <+9>: mov 0xc(%ebp),%eax
0x080483d0 <+12>: movsbl %al,%eax
0x080483d3 <+15>: mov %eax,0x4(%esp)
0x080483d7 <+19>: movl $0x80484b4,(%esp)
0x080483de <+26>: call 0x80482f4 <printf@plt>
and original code that you've posted:
0x080483c4 <+0>: push %ebp
0x080483c5 <+1>: mov %esp,%ebp
0x080483c7 <+3>: and $0xfffffff0,%esp
0x080483ca <+6>: sub $0x20,%esp
0x080483cd <+9>: mov 0xc(%ebp),%eax
0x080483d0 <+12>: mov %al,0x1c(%esp)
0x080483d4 <+16>: movsbl 0x1c(%esp),%eax
0x080483d9 <+21>: mov %eax,0x4(%esp)
0x080483dd <+25>: movl $0x80484b4,(%esp)
0x080483e4 <+32>: call 0x80482f4 <printf@plt>
In both cases $0x80484b4
stores "%d"
format specifier as string literal and 0xc(%ebp)
is responsible for actual value that is used by printf()
:
(gdb) x/db 0xbffff324
0xbffff324: -60
(gdb) p $al
$3 = -60
Notice that AL
(one byte accumulator, i.e. part of EAX
) "fetches" only the first byte (my CPU is little endian, so it's actually LSB) at $ebp+0xc
address. This means that (char)
conversion does "cut-off" of an argv
address.
As a consequence you may observe that each of these numbers have log2(n)
least significant bits unset. This due to alignment requirement for objects of pointer type. Typically for a 32-bit x86 machine alignof(char **) == 4
.
As already pointed in comments you violated C Standard, so it's an example of UB.