Linking error when compiling basic x86 code with gcc - c

I am attempting to write very basic x86 code and call it in a C program. I'm running OSX 10.8.2. Here is the code I have:
start.c:
#include <stdio.h>
void _main(); // inform the compiler that Main is an external function
int main(int argc, char **argv) {
_main();
return 0;
}
code.s
.text
.globl _main
_main:
ret
I run the following commands to attempt compilation:
gcc -c -o code.o code.s
gcc -c -o start.o start.c
gcc -o start start.o code.o
Which then returns this output after the final command:
Undefined symbols for architecture x86_64:
"__main", referenced from:
_main in start.o
ld: symbol(s) not found for architecture x86_64
collect2: ld returned 1 exit status
Am I missing something in my compiler calls? Do I need to update something/install something different? I just can't find a definitive answer anywhere since this is such a general output. Thanks!

You need an extra underscore in your asm _main symbol:
.text
.globl __main
__main:
ret
C symbols get an underscore prefix when compiled, so your C main is actually _main and an extern C _main actually needs to be defined as __main if you write it in asm.

Related

Call an assembler function from C code in linux [duplicate]

This question already has answers here:
32-bit absolute addresses no longer allowed in x86-64 Linux?
(1 answer)
What happens if you use the 32-bit int 0x80 Linux ABI in 64-bit code?
(1 answer)
Assembling 32-bit binaries on a 64-bit system (GNU toolchain)
(2 answers)
Closed 3 years ago.
I want to call a print function from my C program.
assembler prog:
#test.s
.text
.global _start
.global print
.type print, #function
_start:
call print
# and exit.
movl $0,%ebx # first argument: exit code.
movl $1,%eax # system call number (sys_exit).
int $0x80 # call kernel.
print:
# write our string to stdout.
movl $len,%edx # third argument: message length.
movl $msg,%ecx # second argument: pointer to message to write.
movl $1,%ebx # first argument: file handle (stdout).
movl $4,%eax # system call number (sys_write).
int $0x80 # call kernel.
mov $0, %eax
ret
.data
msg:
.ascii "Hello, world!\n" # the string to print.
len = . - msg # length of the string.
I can assemble and link it using:
$as test.s -o test.o
$ld test.o -o test
And I can execute it as a program, and it outputs "Hello, world!"
But when I tried to call a print from C code like this:
#include <stdio.h>
extern int print();
int main(){
int g;
g = print();
printf("Hello from c!, %d\n", g);
}
It was compiled using:
$gcc -c main.c test
It just prints "Hello from c, 13", that means that the function was called and return a number of chars, but does not print anything!
What am I doing wrong?
P.S.
When I trying to compile prog like this:
$as test.s -o test.o
$gcc -c main.c -o main.o
$gcc main.c test.o
I have a error:
/usr/bin/ld: test.o: in function `_start':
(.text+0x0): multiple definition of `_start'; /usr/lib/gcc/x86_64-pc-linux-gnu/9.2.0/../../../../lib/Scrt1.o:(.text+0x0): first defined here
/usr/bin/ld: test.o: relocation R_X86_64_32 against `.data' can not be used when making a PIE object; recompile with -fPIE
/usr/bin/ld: final link failed: nonrepresentable section on output
collect2: error: ld returned 1 exit status
Ok, done! Thanks clearlight
I can compile all use
$as test.s -o test.o
$gcc -c main.c -o main.o
$gcc -no-pie main.c test.o
And all will work fine!

Can't link an assembly file (.s) with GCC on macOS Sierra

I have 2 files to compile.
The first is main.c and the 2nd is a function that does sums and multiplications in assembly (work.s).
This is the code :
main.c file:
#include <stdio.h>
short work();
int main() {
short z = work();
printf("work(); -> %hd\n", z);
return 0;
}
work.s file:
.globl work;
work :
xorl %eax,%eax;
xorl %ecx,%ecx;
movw $20,%ax;
subw $2,%ax;
movw $7,%cx;
addw $3,%cx;
movw $10,%cx;
subw $3,%cx;
shl $1,%cx;
addw %cx,%ax;
ret;
From command line using gcc : gcc -m32 main.c work.s -o main
This is the output :
Undefined symbols for architecture i386:
"_work", referenced from:
_main in main-fbbcca.o
ld: symbol(s) not found for architecture i386
clang: error: linker command failed with exit code 1 (use -v to see
invocation)
While on Linux with same files and commands it works, why and how I can fix it?
Maybe change your global to the name gcc is looking for?
.globl _work;
_work :
...
There are other approaches, too:
https://montcs.bloomu.edu/~bobmon/Code/Asm.and.C/C-asm/Asm-C-example0.shtml
<= Different compiler, same principles...
In work.s, change work to _work both places it appears. The compiler prefixes an underscore to C names. Assembly language is more bare bones, so you have to prefix the underscore yourself.

Symbol not found when static linking on MacOSX

I am trying to create a static library and link it on MacOS X (several versions):
File foo.c:
char foo[111];
File bar.c:
#include <string.h>
extern char foo[];
int bar(char *src) {
strcpy(foo, src);
return strlen(foo);
}
Create a library:
$ cc -c foo.c bar.c
$ ar r libfoobar.a foo.o bar.o
ar: creating archive libfoobar.a
$ ranlib libfoobar.a
$ nm libfoobar.a
libfoobar.a(foo.o):
000000000000006f C _foo
libfoobar.a(bar.o):
U ___strcpy_chk
0000000000000000 T _bar
U _foo
U _strlen
Create a small test program:
File main.c:
#include <stdio.h>
int bar(char *);
int main(void) {
printf("foobarbar = %i\n", bar("123"));
return 0;
}
Compile and link:
$ cc -c main.c
$ cc -o m main.o -L. -lfoobar
Undefined symbols for architecture x86_64:
"_foo", referenced from:
_bar in libfoobar.a(bar.o)
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Why is the symbol not found? It is defined in foo.c? Shouldn't at least ranlib create an index in the library that allows a random order of the files there?
The same code works well under Linux (gcc), and also when the symbol in foo.c is not a char array, but an int.
There is a similar question: Object files not properly added to archive on mac which has this answer:
Option 1:
ar -rs my_archive.a foo.o bar.o other_object_files.o
ranlib -c my_archive.a
Option 2:
libtool -c -static -o my_archive.a foo.o bar.o other_object_files.o
It is -c flag that makes a difference for both options on ranlib and libtool respectively:
-c
Include common symbols as definitions with respect to the table
of contents. This is seldom the intended behavior for linking
from a library, as it forces the linking of a library member
just because it uses an uninitialized global that is undefined
at that point in the linking. This option is included only
because this was the original behavior of ranlib. This option
is not the default.

Why doesn't arm-none-eabi-gcc search for my custom _start symbol?

I am compiling the below code with "-nostdlib". My understanding was that arm-none-eabi-gcc will not use the _start in "crt0.o" but it will use the user defined _start. For this I was expecting to create a start.S file and put the _start symbol.
But if I compile the below shown code without the _start symbol defined from my side, I am not getting any warning. I was expecting "warning: cannot find entry symbol _start;"
Questions:
1) Why am I not getting the warning ? From where did GCC get the _start symbol ?
2) If gcc got the _start symbol from a file from somewhere, could you let me know how to ask GCC to use the _start from my start.S file ?
$ cat test.c
int main()
{
volatile int i=0;
i = i+1;
return 0;
}
$ cat linker.ld
MEMORY
{
ram : ORIGIN = 0x8000, LENGTH = 20K
}
SECTIONS
{
.text : { *(.text*) } > ram
.bss : { *(.bss*) } > ram
}
$ arm-none-eabi-gcc -Wall -Werror -O2 -mfpu=neon-vfpv4 -mfloat-abi=hard -march=armv7-a -mtune=cortex-a7 -nostdlib -T linker.ld test.c -o test.o
$ arm-none-eabi-gcc --version
arm-none-eabi-gcc (GNU Tools for ARM Embedded Processors) 4.9.3 20150529 >(release) [ARM/embedded-4_9-branch revision 224288]
Compile and link with arm-none-eabi-gcc -v -Wall -Werror -O2.... to understand what the compiler is doing (and which crt0 it is using; that crt0 probably has a _start calling your main, also _start might be the default entry point for your linker)
Notice that -nostdlib is related to the (lack of) C standard library; perhaps you want to compile in a freestanding environment (see this), then use -ffreestanding (and in that case main has no particular meaning, you need to define your starting function[s], and no standard C functions like malloc or printf are available except perhaps setjmp).
Read the C99 standard n1256 draft. It explains what freestanding means in ยง5.1.2.1

GNU Linker and architecture i386

So I'm running on OS X and I want to link two Mach-O objects i386.
The first is generated from NASM (it's an assembly file)
nasm -f macho -o kernel.o kernel.asm
The second is generated from GCC
gcc -c -arch i386 screen.c
But when I try to link them...
ld -o myprogram screen.o kernel.o
...I get this error :
Undefined symbols for architecture i386:
"print", referenced from:
start in kernel.o
ld: symbol(s) not found for inferred architecture i386
I don't understand why, because my two files are Mach-O object i386 :
$ file screen.o
screen.o: Mach-O object i386
$ file kernel.o
kernel.o: Mach-O object i386
If you need it, here's kernel.asm :
[BITS 32]
EXTERN print
GLOBAL start
start:
mov eax, msg
push eax
call print
pop eax
end:
jmp end
msg db 'Hello world!', 10, 0
And here's screen.c :
void putcar(uchar c)
{
/* Some code here */
}
void print(char *string)
{
while(*string != 0){
putcar(*string);
string++;
}
}
You need to use the symbol _print in your asm file, i.e.
start:
mov eax, msg
push eax
call _print
pop eax
This is because C function names get a leading underscore when compiled.

Resources