-7

I tried to replace char** in main argument to long **. However, the compiler complains about it with the following warning :

> add2.c:3:5: error: second parameter of 'main' (argument array) must be
>       of type 'char **' int main(int i, long **a) {

Is there anyway that I can compile this code by adding some gcc flags?

As this post is receiving too many negative votes, I would like to explain more about why I am asking this question. I have this question because Im facing this problem in a CTF (Capture the flag) practice competition. I reckon this maybe worth asking because 1. It may let people know more about the arguments in C main function

  1. I have googled around and never seen this problem being asked before( Everyone just accept char** as an argument for C main function)

  2. We maybe able to disable the checking using GCC flags, this may help others to learn more about how much GCC can do too

I am sorry that this question receiving so many downvotes and I have no idea why people downvoting this. I still think this question is worth to discuss.

I ran this code on the server SUCCESSFULLY and I have posted my result as an answer here. If anyone knows how to make this work, I would be so happy to hear that.


level3@io64:/tmp$ cat add2.c
#include <unistd.h>

int main(int i, long **a) {
    if(*a[1] * 0xabcdabcdabcdu == 0x123412341234u)
        execl("/bin/sh", "sh", 0);
    return 0;
}
level3@io64:/tmp$ gcc -o a add2.c
/usr/bin/ld: cannot open output file a: Permission denied
collect2: error: ld returned 1 exit status
level3@io64:/tmp$ gcc add2.c
/usr/bin/ld: cannot open output file a.out: Permission denied
collect2: error: ld returned 1 exit status
level3@io64:/tmp$ gcc -o abc add2.c
level3@io64:/tmp$ gcc -v -o abcd add2.c
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/4.7/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Debian 4.7.2-5' --with-bugurl=file:///usr/share/doc/gcc-4.7/README.Bugs --enable-languages=c,c++,go,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.7 --enable-shared --enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.7 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --enable-plugin --enable-objc-gc --with-arch-32=i586 --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 4.7.2 (Debian 4.7.2-5)
COLLECT_GCC_OPTIONS='-v' '-o' 'abcd' '-mtune=generic' '-march=x86-64'
 /usr/lib/gcc/x86_64-linux-gnu/4.7/cc1 -quiet -v -imultiarch x86_64-linux-gnu add2.c -quiet -dumpbase add2.c -mtune=generic -march=x86-64 -auxbase add2 -version -o ./ccyNP1XF.s
GNU C (Debian 4.7.2-5) version 4.7.2 (x86_64-linux-gnu)
    compiled by GNU C version 4.7.2, GMP version 5.0.5, MPFR version 3.1.0-p10, MPC version 0.9
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=100000
ignoring nonexistent directory "/usr/local/include/x86_64-linux-gnu"
ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../../x86_64-linux-gnu/include"
#include "..." search starts here:
#include <...> search starts here:
 /usr/lib/gcc/x86_64-linux-gnu/4.7/include
 /usr/local/include
 /usr/lib/gcc/x86_64-linux-gnu/4.7/include-fixed
 /usr/include/x86_64-linux-gnu
 /usr/include
End of search list.
GNU C (Debian 4.7.2-5) version 4.7.2 (x86_64-linux-gnu)
    compiled by GNU C version 4.7.2, GMP version 5.0.5, MPFR version 3.1.0-p10, MPC version 0.9
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=100000
Compiler executable checksum: 7fa7c2a970be5e19ce72b2057c14800d
COLLECT_GCC_OPTIONS='-v' '-o' 'abcd' '-mtune=generic' '-march=x86-64'
 as -v --64 -o ./ccJEfzc6.o ./ccyNP1XF.s
GNU assembler version 2.22 (x86_64-linux-gnu) using BFD version (GNU Binutils for Debian) 2.22
COMPILER_PATH=/usr/lib/gcc/x86_64-linux-gnu/4.7/:/usr/lib/gcc/x86_64-linux-gnu/4.7/:/usr/lib/gcc/x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/4.7/:/usr/lib/gcc/x86_64-linux-gnu/
LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/4.7/:/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../../lib/:/lib/x86_64-linux-gnu/:/lib/../lib/:/usr/lib/x86_64-linux-gnu/:/usr/lib/../lib/:/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../:/lib/:/usr/lib/
COLLECT_GCC_OPTIONS='-v' '-o' 'abcd' '-mtune=generic' '-march=x86-64'
 /usr/lib/gcc/x86_64-linux-gnu/4.7/collect2 --sysroot=/ --build-id --no-add-needed --eh-frame-hdr -m elf_x86_64 --hash-style=both -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o abcd /usr/lib/gcc/x86_64-linux-gnu/4.7/../../../x86_64-linux-gnu/crt1.o /usr/lib/gcc/x86_64-linux-gnu/4.7/../../../x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/4.7/crtbegin.o -L/usr/lib/gcc/x86_64-linux-gnu/4.7 -L/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../x86_64-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../../lib -L/lib/x86_64-linux-gnu -L/lib/../lib -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/4.7/../../.. ./ccJEfzc6.o -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc/x86_64-linux-gnu/4.7/crtend.o /usr/lib/gcc/x86_64-linux-gnu/4.7/../../../x86_64-linux-gnu/crtn.o
Timothy Leung
  • 1,247
  • 5
  • 17
  • 36
  • 8
    Why do you want to do that? – Spikatrix Aug 28 '15 at 05:45
  • 3
    Why is the question tagged both `C` and `C++`? – CinCout Aug 28 '15 at 05:46
  • The code can be compiled it you remove the `-Werror` flag. But it doesn't make sense why you want to do this... – Spikatrix Aug 28 '15 at 05:48
  • 1
    No reason to do this .Even if you want `long` types take value as char at command line and you can easily store value in `long variable` using `sscanf` . – ameyCU Aug 28 '15 at 05:50
  • You can trick the compiler into accepting it. But the standard program loader will still call into main with a `char**` and you will have trouble at runtime. – Thilo Aug 28 '15 at 05:56
  • I suspect that what you really want to do is pass floats as arguments to your program from the command line. You need to do the conversion yourself from the strings it receives. – molbdnilo Aug 28 '15 at 06:12
  • "Everyone just accept char** as an argument for C main function": be uase it is *declared* to do so. Function declarations are an integral part of the language. – Jongware Aug 28 '15 at 06:37
  • "Im facing this problem in a CTF". Really? Did they say "make a C program where main takes a second argument of type long **"? Or did you translate a different set of requirements into that? – kaylum Aug 28 '15 at 06:46
  • @AlanAu They provided the above C code, and I am able to compile the code on their machine without errors. I ran the command gcc -o a levelx.c I am not sure why this is possible thats why i am asking – Timothy Leung Aug 28 '15 at 06:51
  • Interesting. What is their machine running and what toolchain are they using? BTW, perhaps take this as a lesson on how to ask a question. The way your question is currently written sounds like "I want to do this weird/invalid thing, how can I do it"? Perhaps it would have been better to say: "here's this weird/invalid code that compiles without error on this system, why is it so"? – kaylum Aug 28 '15 at 06:52
  • `Linux io64 3.2.0-4-amd64 #1 SMP Debian 3.2.63-2+deb7u1 x86_64 GNU/Linux` What toolchain? what do you mean? For GCC, it is 4.7.2, the setting is too long to be post here I will update my post with the config of the macine – Timothy Leung Aug 28 '15 at 06:56
  • Although this is a practice comp, I do not want to expose too much about the situation, as the practice comp maybe reuse in future. @AlanAu I am sorry for being inconsiderate. – Timothy Leung Aug 28 '15 at 06:59

4 Answers4

4

These are the only allowed main declarations, there is no int main(int i, long **a) and we cannot invent one as it is simply not supported.

From C++ Standard,

3.6.1 Main function

An implementation shall not predefine the main function. This function shall not be overloaded. It shall have a return type of type int, but otherwise its type is implementation-defined. All implementations shall allow both

— a function of () returning int and

— a function of (int, pointer to pointer to char) returning int

Arun
  • 2,025
  • 1
  • 18
  • 33
  • It is not supported but its not that it can't be done . But one should avoid it at any case :) – ameyCU Aug 28 '15 at 06:06
  • 2
    @ameyCU, even if we force it, it just another undefined behaviour – Arun Aug 28 '15 at 06:09
  • 2
    @ameyCU If it is not supported, it can't be done. There are a couple of versions of C and C++ that allow implementation-defined forms of main(), but implementation-defined means that, if supported, the compiler tells _you_, through documentation, about what forms that are allowed, not the other way around. – Lundin Aug 28 '15 at 06:19
3

It depends on what system you are compiling this for. In a hosted environment, you are usually not allowed to change the parameters of main. In case you are changing them, the compiler must support it and document how.

  • GCC does not support non-standard arguments of main() in any gcc port I know of.
  • There exists no compiler which allows the programmer to invent their own, crazy format of main(). If such a compiler existed, it would not follow the C and C++ standards.

Complete reference for the allowed forms of main in C and C++.

Community
  • 1
  • 1
Lundin
  • 155,020
  • 33
  • 213
  • 341
0

The operating system, the shell, the compiler, and the startup code all work together to pass a char ** as the second parameter to main, in accordance with the C and C++ specifications.

If you want to change the second parameter to main, you need to write

  • your own operating system
  • your own shell
  • your own compiler, and
  • your own startup code

Good luck with that! We'll see you in 50 years when you're done.

user3386109
  • 32,020
  • 7
  • 41
  • 62
0

I tested this on the server (I AM NOT ABLE TO RUN THIS CODE ON MY MACHINE). And apparently, the parameter a is stored in stack like char.

If I am calling my program like this

./a 12345678 

and print out *a[1] as long in hex format, I got the value 0x3837363534333231 I will say that the program did not consider my input as long even the argument type is long.

The usual way to do this is set argv as char** type and cast it back to long using pointer.

I hope this can help someone who face the same problem and please let me know if you have ideas why this code can be compiled.

According to all the answers/comments/c spec provided, it seems like it is impossible to do that.

Timothy Leung
  • 1,247
  • 5
  • 17
  • 36