I've written a piece of C code and I've disassembled it as well as read the registers to understand how the program works in assembly.
int test(char *this){
char sum_buf[6];
strncpy(sum_buf,this,32);
return 0;
}
The piece of my code that I've been examining is the test function. When I disassemble the output my test function I get ...
0x00000000004005c0 <+12>: mov %fs:0x28,%rax
=> 0x00000000004005c9 <+21>: mov %rax,-0x8(%rbp)
... stuff ..
0x00000000004005f0 <+60>: xor %fs:0x28,%rdx
0x00000000004005f9 <+69>: je 0x400600 <test+76>
0x00000000004005fb <+71>: callq 0x4004a0 <__stack_chk_fail@plt>
0x0000000000400600 <+76>: leaveq
0x0000000000400601 <+77>: retq
What I would like to know is what mov %fs:0x28,%rax
is really doing?
On x86_64, segmented addressing is no longer used, but the both the
FS
andGS
registers can be used as base-pointer addresses in order to access special operating system data-structures. So what you're seeing is a value loaded at an offset from the value held in theFS
register, and not bit manipulation of the contents of theFS
register.Specifically what's taking place, is that
FS:0x28
on Linux is storing a special sentinel stack-guard value, and the code is performing a stack-guard check. For instance, if you look further in your code, you'll see that the value atFS:0x28
is stored on the stack, and then the contents of the stack are recalled and anXOR
is performed with the original value atFS:0x28
. If the two values are equal, which means that the zero-bit has been set becauseXOR
'ing two of the same values results in a zero-value, then we jump to thetest
routine, otherwise we jump to a special function that indicates that the stack was somehow corrupted, and the sentinel value stored on the stack was changed.If using GCC, this can be disabled with
Looking at http://www.imada.sdu.dk/Courses/DM18/Litteratur/IntelnATT.htm, I think
%fs:28
is actually an offset of 28 bytes from the address in%fs
. So I think it's loading a full register size from location%fs + 28
into %rax.