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/
Related
I'm using a book, and now I'm studying external variables. I'm supposed to use a function located in another file and return a value from that function. But I don't understand how does this happens exactly. This is the code provided by the book:
This is the code in the first file:
#include <stdio.h>
double getCircum(double);
double PI = 3.14;
int gi;
int main(void)
{
double r = 5.87;
const double PI = 3.14;
printf("%.f", getCircum(r));
}
This is the code in the other file:
external double PI;
double getCircum(double r)
{
return 2 * r * PI;
}
The output is supposed to be 36.88. but I keep getting an error message that the file is not the directory. I don't know what file it that. Also, I don't really get how the code is supposed to look for a function in a different file, is the code missing something?
This is possible through to the linking process.
When reading your C first file, the compiler will output an object file which contain unresolved references to symbols like printf, getCircum because they are declared (printf in <stdio.h> and getCircum in your first file) but not implemented (you didn't wrote them code in the first file).
When reading the second file, the compiler will miss the definition of PI.
This doesn't prevent him from producing valid object files. After removing the line double PI = 3.14 (it miss a ;), compile without linking with :
cc -c -o 1st_file.o 1st_file.c
cc -c -o 2nd_file.o 2nd_file.c
This will output two object files, if you run obj-dump -t 1st_file.o 2st_file.o you will see a list of provided and unresolved symbols of both files.
Now we will link with cc -o program.exe 1st_file.o 2nd_file.o. The C compiler will link both objects and some system-wide ones inside program.exe.
And voilà !
In your case cc -o program.exe 1st_file.c 2nd_file.c will do the job. But in real program, recompiling the whole program at each test take a lot of time, I have a private project which take 3,5 seconds to link vs 17,5 to recompile everything for 4k lines of code, Linux itself has more than a 2M lines of code...
Finally, post the console output and build command in the question, my answer make the important assumption that you are on a Linux with a working C compiler and GNU binutils, StackOverflow has a great doc here https://stackoverflow.com/help/how-to-ask to ask good question which have more chances to be solved
Edit: Defining PI 2 times here is not an error
$ 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.
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 -
I have a program entirely written in C that uses multiple object (.o) files in it. These files are all packed inside an archive file (.a) which, in turn, is used at compile-time of the program's main (.c) file.
I want to write a new file for this project in Go. My idea is to write this .go file and then create an object (.o) file from it. Afterwards, I want to put this object file inside the already mentioned archive (.a) file.
This basically means that I want to call Go functions from a C program. I've read this question, and while it showed me that what I want is possible via GCCGO, it's not 100% clear as to how to do it.
Even with the most basic of tests, I get errors during the linking phase. More specifically, here's one of such basic example:
printString.go
package main
import
(
"fmt"
)
func PrintString(buff string) int {
fmt.Printf(buff)
return 1
}
c_caller.c
#define _GNU_SOURCE
#include <stdio.h>
extern int PrintString(char*) __asm__ ("print.main.PrintString");
int main() {
char *string_to_pass= NULL;
asprintf(&string_to_pass, "This is a test.");
int result= PrintString(string_to_pass);
if(result) {printf("Everything went as expected!\n");}
else {printf("Uh oh, something went wrong!\n");}
return result;
}
Compiling
In order to compile the Go file, I used this command:
gccgo -c printString.go -o printString.o -fgo-prefix=print -Wall -Werror -march=native
In order to compile the entire thing, I used this command:
gccgo -o main c_caller.c printString.o -Wall -Werror -march=native
The return message I'm getting is:
/usr/lib64/libgo.so.4.0.0: undefined reference to `main.main'
/usr/lib64/libgo.so.4.0.0: undefined reference to `__go_init_main'
collect2: error: ld returned 1 exit status
Which means that GCCGO's expecting a main function in the Go file instead of the C one.
Using the --static-libgo, -static and -Wl,-R,/path/to/libgo.so's_folder options on the second command yield a different result:
/usr/bin/ld: cannot find -lgo
collect2: error: ld returned 1 exit status
Which makes no sense, since I have the LD_LIBRARY_PATH environment variable properly pointing to libgo.so's folder.
I realize that I'm probably doing something wrong here, but I just can't see what that is. There's next to no examples of GCCGO and its interaction with C out there, and the only reference I could find was this page, which I personally feel like it's not enough.
I ask kindly for some advice on this matter and thank you for your time. :)
This may not be what you want, but in Go 1.5, that's coming this August, you'll be able to build C-compatible libraries with the go tool. So with this in your _main.c
#include <stdio.h>
int main()
{
char *string_to_pass = NULL;
if (asprintf(&string_to_pass, "This is a test.") < 0) {
printf("asprintf fail");
return -1;
}
PrintString(string_to_pass);
return 0;
}
and this in your main.go
package main
import "C"
import "fmt"
//export PrintString
func PrintString(cs *C.char) {
s := C.GoString(cs)
fmt.Println(s)
}
func main() {}
You can do, for static library:
go build -buildmode c-archive -o mygopkg.a
gcc -o main _main.c mygopkg.a -lpthread
For shared library:
go build -buildmode c-shared -o mygopkg.so
LD_RUN_PATH=$(pwd) gcc -o main _main.c mygopkg.so -lpthread
(LD_RUN_PATH is here to make the linker look for the shared library in the same directory you're building.)
See the Go execution modes design document for more info.
There currently isn't a supported way to do what you want. Go always needs the support of its runtime, and the entry point for that is always main. AFAIK, gccgo also makes these same assumptions, and doesn't provide a way to easily link into from other programs.
If you want to do this in a supported manner, you will have to wait until go1.5+ where work is being done to compile shared libraries from Go code.
If you really want to hack on this now, you can look into how the Android port works using the default gc toolchain with -linkmode external, which renames main in the object file and calls it externally.
i'm trying to link a simple c program on an arm debian machine (a raspberry pi) and when linking the ogject file the linker returns me the error in the subject.
my program is as simple as
simple.c:
int main(){
int a = 2;
int b = 3;
int c = a+b;
}
i compile it with
$>gcc -o simple.obj simple.c
and then link it with
$>ld -o simple.elf simple.obj
ld: simple.obj: access beyond end of merged section (33872)
i can't understand why...
if i try to read the elf file with objdump -d it doesn't manage to decompile the .text section (it only prints address, value, .word and again value preceded by 0x) but the binary data is the same as the one i get from the decompiled simple.obj.
the only difference is in the loading start (and consequent) addresses of the binary data: the elf file starts at 0x8280, the object file starts at 0x82a0.
what does all this mean?
EDIT:
this is the dump for the obj file: http://pastebin.com/YZ94kRk4
and this is the dump for the elf file: http://pastebin.com/3C3sWqrC
i tried compiling with -c option that makes gcc stop after assembly time (it already did the linking part) but now i have a different problem: it says that there is no _start section in my object file...
the new dumps are:
simple.obj: http://pastebin.com/t0TqmgPa
simple.elf: http://pastebin.com/qD35cnqw
You are misunderstanding the effect of the commands you ran. If you run:
$ gcc -o simple.obj simple.c
it already creates the program you want to run, it's already linked. You don't need to link it again, especially by running ld directly unless you know what you are doing. Even if its extension is obj, it doesn't matter, it's just the name of the file, but the content of the file is already a complete Linux program. So if you run:
$ ./simple.obj
it will execute your code.
You usually don't call ld directly, but instead you use gcc as a front-end to compile and link. This is because gcc takes care of linking also important libraries that you are not linking such as the startup code, and that's the reason why your second attempt resulted in "no _start section" or something like that.
Could you print the output of the objdump -d command?
Btw, notice that 33872 == 0x8450.
I am not familiar with raspberry PI's memory map, so if you'r following any tutorials about this or have some other resource to help me help you out - it would be great :)