I wrote this original article because I saw an article by geeks titled interesting programming languages implementing 2 + 2 = 5, where C is implemented in this way:
int main() {char __func_version__[] = “5″; // For source controlchar b[]=”2″, a=2;printf(“%d + %s = %s\n”, a, b, a+b);return 0;}
Some children's shoes may say that this is not a concept of stealing and replacing them with strings and int. But here, please make these shoes humorous for the moment, think about why a + B will produce 5 results? Have you actually compiled it? Is the result 5?
I compiled it by hand. The result is not 5. It is definitely an printable ascii character. Therefore, the console displays 2 + 2 =. I know a little about the C STACK layout, in fact, this Code finally tries to print the "5" string in _ func_version _, but unfortunately different compilers, even the stack layout generated by the same compiler without the compilation option is completely different, which cannot ensure that the precise positioning of the 3 bytes after B exactly points to _ func_version __.
So what is the layout under gcc-O3? Let's slightly modify the code:
#include
int main() {//char b[]="2", a=2;char __func_version__[] = "5"; // For source controlchar b[]="2", a=2;printf("%p %p %p\n",__func_version__,b,&a);/*for(int i=0;i<100;++i){printf("%d + %s = %s\n", i, b, i+b);}*/printf("%d + %s = %s\n", a, b, a+b);return 0;}
Let's take a look at the results:
Gcc-v
Using built-in specs.
COLLECT_GCC = gcc
COLLECT_LTO_WRAPPER =/usr/local/Cellar/gcc48/4.8.2/libexec/gcc/x86_64-apple-darwin13.0.0/4.8.2/lto-wrapper
Target: x86_64-apple-darwin13.0.0
Configured :.. /configure -- build = x86_64-apple-darwin13.0.0 -- prefix =/usr/local/Cellar/gcc48/4.8.2 -- enable-languages ages = c, c ++, objc, obj-c ++ -- program-suffix =-4.8 -- with-gmp =/usr/local/opt/gmp4 -- with-mpfr =/usr/local/opt/mpfr2 -- -mpc =/usr/local/opt/libmpc08 -- with-cloog =/usr/local/opt/cloog018 -- with-isl =/usr/local/opt/isl011 --- system-zlib -- enable-version-specific-runtime-libs -- enable-libstdcxx-time = yes -- enable-stage1-checking -- enable-checking = release -- enable-lto -- disable-werror -- enable- plugin -- disable-nls -- disable-multilib
Thread model: posix
Gcc version 4.8.2 (GCC)
Cs $ gcc-std = c99-Wall-O3-g0-o 5 5.c
Apple @ kissAir: cs $./5
0x7fff504fa920 0x7fff504fa930 0x7fff504fa910
2 + 2 = OP?
Nana! Swollen _ func_version _ is smaller than B, so no matter what positive number B adds, it cannot point to the former. Of course some people will say, it can be an integer round back, I am sorry. That's not the case. It's not the "2 + 2 = 5" bird, but the "2 + xxxxxxxxxx = 5" bird. Although the location of two character array variables can be changed to solve this problem, that is, B [] is defined before _ func_version, but it also requires "2 + 16 = 5". I don't know if gcc has any compilation options to pack the stack variable drops, But I know # pragma pack (1) we can package the structure variable drops. so we can simply add the following code:
#pragma pack(1)typedef struct __foo {char *b;char a;char *__func_version__;}foo;void print_5_by_struct(void){foo foo_v = {"2",(char)2,"5"};printf("%p %p\n",foo_v.__func_version__,foo_v.b);printf("%d + %s = %s\n",foo_v.a,foo_v.b,foo_v.a+foo_v.b);}
In the end, "2 + 2 = 5" is printed as expected ",
If you have other children's shoes that know how to pack variables, please let me know. Thank you.
Some children's shoes will say again, you are too cumbersome, too ink, not happy! Well, we didn't say we could only use gcc. Let's try clang :)
#include
int main() {char __func_version__[] = "5"; // For source controlchar b[]="2", a=2;printf("%p %p %p\n",__func_version__,b,&a);printf("%d + %s = %s\n", a, b, a+b);return 0;}
Shell compilation and running are as follows:
Clang-v
Apple LLVM version 5.1 (clang-503.0.40) (based on LLVM 3.4svn)
Target: x86_64-apple-darwin13.2.0
Thread model: posix
Apple @ kissAir: cs $ clang-std = c99-Wall-O3-g0-o 5 5.c
Apple @ kissAir: cs $./5
0x7fff57925936 0x7fff57925934 0x7fff57925933
2 + 2 = 5
Therefore, I am not sure whether I want to learn C. I want to learn how to use it. Thank you for your attention.