Compiling C code without having it saved in a file - c

Inspired by this PCG challange: https://codegolf.stackexchange.com/q/61836/31033
I asked my self, if one would try to leave as few trace as possible when compiling such kind of tool (no matter of a browser or something else), is there some way (aimed for gcc/clang as this probably are the preinstalled commandline compillers in such a working enviroment) to hand over source code to the compiler as command line argument or equal mechanism, without need for the source code beeing saved as *.c file, as the user would usually do?
(ofcourse the compiler will produce temp files while compiling, but those probably won't get scanned.)

At least gcc can as it is able to read source from the standard input. You can also use Unix here string bash construction :
gcc -xc - << "int main() { exit(0); }"
or here file sh construction :
gcc -xc - <<MARK
int main() {
exit(0);
}
MARK
----EDIT----
You can also imagine using cryptography to encode your source, uncipher the content on the fly and inject the result to the standard input of gcc, something like:
uncipher myfile.protected | gcc -xc -

Related

Compile and Link to .com file with Turbo C

I'm trying to compile and link a simple program to a DOS .com file using Turbo C compiler and linker. By that I try the simplest C-program I can think of.
void main()
{}
Are there command line arguments to link to com files in the Turbo C Linker?
The Error Message I get from the Linker is the following:
"Fatal: Cannot generate COM file: invalid entry point address"
I know that com files need entry point to be at 100h. Does Turbo C have an option to set this address?
It has been a long time since I have genuinely tried to use Turbo-C for this kind of thing. If you are compiling and linking on the command line separately with TCC.EXE and TLINK.EXE then this may work for you.
To compile and link to a COM file you can do this for each one of your C source files creating an OBJ file for each:
tcc -IF:\TURBOC3\INCLUDE -c -mt file1.c
tcc -IF:\TURBOC3\INCLUDE -c -mt file2.c
tcc -IF:\TURBOC3\INCLUDE -c -mt file3.c
tlink -t -LF:\TURBOC3\LIB c0t.obj file1.obj file2.obj file3.obj,myprog.com,myprog.map,cs.lib
Each C file is compiled individually using -mt (tiny memory model) to a corresponding OBJ file. The -I option specifies the path of the INCLUDE directory in your environment (change accordingly). The -c option tell TCC to compile to a OBJ file only.
When linking -t tells the linker to generate a COM program (and not an EXE), -LF:\TURBOC3\LIB is the path to the library directory in your environment (change accordingly). C0T.OBJ is the C runtime file for the tiny memory model. This includes the main entry point that you are missing. You then list all the other OBJ files separated by a space. After the first comma is the output file name. If using -t option name the program with a COM extension. After the second comma is the MAP file name (you can leave the file name blank if you don't want a MAP file). After the third comma is the list of libraries separated by spaces. With the tiny model you want to use the small model libraries. The C library for the small memory model is called CS.LIB .
As an example if we have a single source file called TEST.C that looks like:
#include<stdio.h>
int main()
{
printf("Hello, world!\n");
return 0;
}
If we want to compile and link this the commands would be:
tcc -IF:\TURBOC3\INCLUDE -c -mt test.c
tlink -t -LF:\TURBOC3\LIB c0t.obj test.obj,test.com,test.map,cs.lib
You will have to use the paths for your own environment. These commands should produce a program called TEST.COM. When run it should print:
Hello, world!
You can generate COM file while still using IDE to generate EXE. Following worked on TC 2.01. Change memory model to Tiny in the options, then compile the program and generate EXE file, then go to command prompt, and run EXE2BIN PROG.EXE PROG.COM. Replace PROG with your program name.
Your problem is about "entry point"
some compiler or linker can recognize void main() like entry point omiting a return value but no all of them.
You shoud use int main() entry point instead for better control of app and compiler can recognize main function as entry point
example:
int main() {
/* some compiler return 0 when you don't for main,
they can ask for return value */
}
from geekforgeeks:
A conforming implementation may provide more versions of main(), but they must all have return type int. The int returned by main() is a way for a program to return a value to “the system” that invokes it. On systems that doesn’t provide such a facility the return value is ignored, but that doesn’t make “void main()” legal C++ or legal C. Even if your compiler accepts “void main()” avoid it, or risk being considered ignorant by C and C++ programmers.
In C++, main() need not contain an explicit return statement. In that case, the value returned is 0, meaning successful execution.
source: https://www.geeksforgeeks.org/fine-write-void-main-cc/

How is rustc able to compile source code from bash process substitution but gcc cannot?

$ rustc <(echo 'fn main(){ print!("Hello world!");}')
$ ls
63
$ gcc <(echo '#include<stdio.h> int main(){ printf("Hello world!\n"); return 0;}')
/dev/fd/63: file not recognized: Illegal seek
collect2: error: ld returned 1 exit status
Why can't ld link the program?
The gcc command is mostly a dispatch engine. For each input file, it determines what sort of file it is from the filename's extension, and then passes the file on to an appropriate processor. So .c files are compiled by the C compiler, .h files are assembled into precompiled headers, .go files are sent to the cgo compiler, and so on.
If the filename has no extension or the extension is not recognised, gcc assumes that it is some kind of object file which should participate in the final link step. These files are passed to the collect2 utility, which then invokes ld, possibly twice. This will be the case with process substitution, which produces filenames like /dev/fd/63, which do not include extensions.
ld does not rely on the filename to identify the object file format. It is generally built with several different object file recognisers, each of which depends on some kind of "magic number" (that is, a special pattern at or near the beginning of the file). It calls these recognisers one at a time until it finds one which is happy to interpret the file. If the file is not recognised as a binary format, ld assumes that it is a linker script (which is a plain text file) and attempts to parse it as such.
Naturally, between attempts ld needs to rewind the file, and since process substitution arranges for a pipe to be passed instead of a file, the seek will fail. (The same thing would happen if you attempted to pass the file through redirection of stdin to a pipe, which you can do: gcc will process stdin as a file if you specify - as a filename. But it insists that you tell it what kind of file it is. See below.)
Since ld can't rewind the file, it will fail after the file doesn't match its first guess. Hence the error message from ld, which is a bit misleading since you might think that the file has already been compiled and the subsequent failure was in the link step. That's not the case; because the filename had no extension, gcc skipped directly to the link phase and almost immediately failed.
In the case of process substitution, pipes, stdin, and badly-named files, you can still manually tell gcc what the file is. You do that with the -x option, which is documented in the GCC manual section on options controlling the kind of output (although in this case, the option actually controls the kind of input).
There are a number of answers to questions like this floating around the Internet, including various answers here on StackOverflow, which claim that GCC attempts to detect the language of input files. It does not do that, and it never has. (And I doubt that it ever will, since some of the languages it compiles are sufficiently similar to each other that accurate detection would be impossible.) The only component which does automatic detection is ld, and it only does that once GCC has irrevocably decided to treat the input file as an object file or linker script.
At least in your case, you can use process substition when specifying the input language manually, using -xc. However, you should put a newline after the include statement.
$ gcc -xc <(echo '#include<stdio.h>
int main(){ printf("Hello world!\n"); return 0;}')
$ ls
a.out
$ ./a.out
Hello world!
For a possible reason why this works, see Charles' answer and the comments on this answer.

Syntax error near unexpected token '('

As a beginner, I am trying to write a simple c program to learn and execute the "write" function.
I am trying to execute a simple c program simple_write.c
#include <unistd.h>
#include <stdlib.h>
int main()
{
if ((write(1, “Here is some data\n”, 18)) != 18)
write(2, “A write error has occurred on file descriptor 1\n”,46);
exit(0);
}
I also execute chmod +x simple_write.c
But when i execute ./simple_write.c, it gives me syntax error near unexpected token '('
Couldn't figure out why this happens ??
P.S: The expected output is:-
$ ./simple_write
Here is some data
$
You did
$ chmod +x simple_write.c
$ ./simple_write.c
when you should have done
$ cc simple_write.c -o simple_write
$ chmod +x simple_write # On second thought, you probably don’t need this.
$ ./simple_write
In words: compile the program to create an executable simple_write
(without .c) file, and then run that. 
What you did was attempt to execute your C source code file
as a shell script.
Notes:
The simple_write file will be a binary file. 
Do not look at it with tools meant for text files
(e.g., cat, less, or text editors such as gedit).
cc is the historical name for the C compiler. 
If you get cc: not found (or something equivalent),
try the command again with gcc (GNU C compiler). 
If that doesn’t work,
If you’re on a shared system (e.g., school or library),
ask a system administrator how to compile a C program.
If you’re on your personal computer (i.e., you’re the administrator),
you will need to install the compiler yourself (or get a friend to do it). 
There’s lots of guidance written about this; just search for it.
When you get to writing more complicated programs,
you are going to want to use
make simple_write
which has the advantages of
being able to orchestrate a multi-step build,
which is typical for complex programs, and
it knows the standard ways of compiling programs on that system
(for example, it will probably “know” whether to use cc or gcc).
And, in fact, you should be able to use the above command now. 
This may (or may not) simplify your life.
P.S. Now that this question is on Stack Overflow,
I’m allowed to talk about the programming aspect of it. 
It looks to me like it should compile, but
The first write line has more parentheses than it needs.
if (write(1, "Here is some data\n", 18) != 18)
should work.
In the second write line,
I count the string as being 48 characters long, not 46.
By the way, do you know how to make the first write fail,
so the second one will execute?  Try
./simple_write >&-
You cannot execute C source code in Linux (or other systems) directly.
C is a language that requires compilation to binary format.
You need to install C compiler (the actual procedure differs depending on your system), compile your program and only then you can execute it.
Currently it was interpreted by shell. The first two lines starting with # were ignored as comments. The third line caused a syntax error.
Ok,
I got what i was doing wrong.
These are the steps that I took to get my problem corrected:-
$ gedit simple_write.c
Write the code into this file and save it (with .c extension).
$ make simple_write
$ ./simple_write
And I got the desired output.
Thanks!!

gcc on Windows: generated "a.exe" file vanishes

I'm using GCC version 4.7.1, but I've also tried this on GCC 4.8. Here is the code I'm trying to compile:
#include <stdio.h>
void print(int amount) {
int i;
for (i = 0; i < 5; i++) {
printf("%d", i);
}
}
int main(int argc, char** argv) {
print(5);
return 0;
}
It looks like it should work, and when I compile with...
gcc main.c
It takes a while to compile, produces an a.exe file and the the a.exe file disappears. It isn't giving me any errors with my code.
Here's a gif of proof, as some people are misinterpreting this:
(Since ahoffer's deleted answer isn't quite correct, I'll post this, based on information in the comments.)
On Windows, gcc generates an executable named a.exe by default. (On UNIX-like systems, the default name, for historical reasons, is a.out.) Normally you'd specify a name using the -o option.
Apparently the generated a.exe file generates a false positive match in your antivirus software, so the file is automatically deleted shortly after it's created. I see you've already contacted the developers of Avast about this false positive.
Note that antivirus programs typically check the contents of a file, not its name, so generating the file with a name other than a.exe won't help. Making some changes to the program might change the contents of the executable enough to avoid the problem, though.
You might try compiling a simple "hello, world" program to see if the same thing happens.
Thanks to Chrono Kitsune for linking to this relevant Mingw-users discussion in a comment.
This is not relevant to your problem, but you should print a newline ('\n') at the end of your program's output. It probably doesn't matter much in your Windows environment, but in general a program's standard output should (almost) always have a newline character at the end of its last line.
Try to compile with gcc but without all standard libraries using a command like this:
gcc -nostdlib -c test.c -o test.o; gcc test.o -lgcc -o test.exe
One of the mingw libraries binary must generate a false positive, knowing which library would be useful.
There is no issue with your code it is just exiting properly.
You have to run it in the command line which will show you all the info.
start->run->cmd, then cd to your directory. then a.exe. If you don't want to do that you can add a sleep() before the return in main.
More over, in your code when you pass print(5) to your function it's not being used.
I confirm is due to Antivirus.
I did this test:
compile helloworld.c at t=0;
within 1 second tell McAfee not consider helloworld.exe a threat. >> the file is still there
If I am too slow, the file will be deleted.
If suppose you get the error near a.exe while running the file ,
Theen follow the below steps:
1.open virus & threat protection
2.there select manage settings in virus & threat protection settings
3.there is real time protection and cloud delivered protection is in ON then OFF the real time protection and cloud delivered protection.!
(https://i.stack.imgur.com/mcIio.jpg)
a.exe is also the name of a virus. I suspect your computer's security software is deleting or quarantining the file because it believes it is a virus. Use redFIVE's suggestion to rename your output file to "print.exe" so that the virus scanner does not delete it.
You try:
gcc -o YOUR_PROGRAM.exe main.c
You can stop your antivirus software from deleting your .exe by specifying the full file path (for eg: c:\MyProject) in the 'paths to be excluded from scanning' section of the antivirus software.

__FILE__ not giving full path

If I do this below:
#include <stdio.h>
int main()
{
printf ("%s\n",__FILE__);
return 0;
}
>gcc cfilename.c
>./a.out
>cfilename.c
>pwd
>/home/tek/cpp
> gcc -v
> gcc version 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5)
only file name is printed, I think it should print it with complete path, google search tells me people asking help to get only file name?
The ISO C standard (currently C11) has this to say about the content of the __FILE__ predefined macro:
__FILE__: The presumed name of the current source file (a character string literal).
And that's about it. There is no mandate on the format of the content so I suspect a implementation could probably get away with setting it to "some file I found in the /src tree" and still claim conformance.
So it's basically up to the implementation as to what it puts in there. You'll need to investigate specific implementations to see how they handle it. The gcc compiler, for example, uses the file exactly as you specified on the command line so, if you want the full path, it's the command line you'll have to change, something like:
gcc -o myexec $(pwd)/myexec.c
It's interesting to note that gcc seems to do the opposite for included files. When you use:
#include "myheader.h"
the __FILE__ macro is set to the full expansion of the header file.
If you have an implementation that doesn't set __FILE__ in the manner you need, there's nothing stopping you from creating your own with something like:
dodgycc -o myexec -DMY_FILE_NAME=$(pwd)/myexec.c myexec.c
(where the -D option of the dodgycc compiler defines a preprocessor token to be what you need).

Resources