-1

I am including external asm into c, when I try to compile I am getting error.

I am compiling c file like this - g++ testing.c

Error:

cc0FHCkn.o:testing.c:(.text+0xe): undefined reference to helloWorld collect2.exe: error: ld returned 1 exit status

C code:

#include<stdio.h>
extern "C" int helloWorld();
int main() {
    printf("Its - ",helloWorld());
}

ASM code:

.code
helloWorld proc
    mov rax, 123
    ret
helloWorld endp
end
dpapadopoulos
  • 1,834
  • 5
  • 23
  • 34
Jason
  • 415
  • 1
  • 6
  • 16
  • 1
    That "C" code you show is actually C++. Try to compile it with `gcc` instead and you should get other errors. – Some programmer dude Feb 15 '19 at 12:10
  • @Someprogrammerdude then how to call in c? actually I am new in this – Jason Feb 15 '19 at 12:11
  • Does the assembler code need to make `helloWorld` public? – Weather Vane Feb 15 '19 at 12:12
  • 1
    And are you actually *linking* with the object file created from the assembly source? Please show us the *actual* and *complete* and *full* list of commands you use to build. – Some programmer dude Feb 15 '19 at 12:12
  • If you call `g++ testing.c` you don't tell the compiler/linker where to find the assembler code or the corresponding object file. It will only compile and try to link `testing.c`. – Bodo Feb 15 '19 at 12:14
  • @Someprogrammerdude I am just using g++ testing.c that's it. I found this way we can compile. – Jason Feb 15 '19 at 12:16
  • 3
    Then you're not even assembling the assembly source file into an object file that you can link to. The GCC frontend program won't automatically build unrelated source files it doesn't know about. You need to assemble it into an object file and specify that object file when building the C++ source. – Some programmer dude Feb 15 '19 at 12:19
  • @Someprogrammerdude How can I do that? – Jason Feb 15 '19 at 12:20
  • @Jason `g++ testing.c a.o` if _a.o_ is the object for your assembler file, or directly `g++ testing.c a.s` if _a.s_ is your assembler file – bruno Feb 15 '19 at 12:20
  • 1
    @Jason better to add something like _%d_ in the format of _printf_ ^^ – bruno Feb 15 '19 at 12:23
  • Also you seem to be on windows and have a masm assembly file and use cygwin. Not a good idea to mix stuff like that. – Jester Feb 15 '19 at 12:25
  • @bruno in my case I have given assembly file extension .asm now like you suggested `a.s` so what is this? – Jason Feb 15 '19 at 12:33
  • `.s` extension is the usual one for gnu assembler files. Your file is not gnu assembler though, it's `masm`. As such `gcc` won't know what to do with it. You need to assemble it with `masm` and hope your toolchain handles the object file format produced. – Jester Feb 15 '19 at 12:41
  • the extension _s_ is the default extension used by _gcc_ for assembler, when you compile with gcc/g++ with the option `-S` the assembler file is generated with the extension _s_. So it is logic gcc/g++ know that extension to assemble the file having that extension – bruno Feb 15 '19 at 12:41
  • @bruno How to compile .asm file using g++ to create .s extension file? as now I am using `g++ testing.c` – Jason Feb 15 '19 at 12:45
  • @Jason I just put an answer with a full example, please refer to it – bruno Feb 15 '19 at 12:50
  • The assembly code is obviously for 64-bit MASM. So, you have to install and use ML64.EXE to assemble it - after you have changed `PROC` to `PROC C PUBLIC`. ML64.EXE is only available for Windows. So, you have to install a 64-bit G++ compiler for Windows (MingGW or Cygwin) to compile the C++ code. And then you have to link the both files together. This is not a task for beginners. Sorry, I don't have a prepared example and no time to make one. Please take a look at my Visual Studio example instead: https://stackoverflow.com/a/33757749/3512216 – rkhb Feb 15 '19 at 16:51

2 Answers2

1

Note : I use that answer to be able to say more than it is possible through a remark, and using gcc.

First, just doing g++ testing.c g++ is not able to link with the assembler file which is not specified, so of course helloWorld is missing.


If I have the file hw.c :

int helloWorld()
{
  return 123;
}

I ask to produce the source assembler through the option -S (I also use -O to reduce the assembler source size), so I do not have to write the assembler file by hand and I am sure it is compatible with gcc :

/tmp % gcc -O -S hw.c

That produced the file hw.s :

/tmp % cat hw.s
    .file   "hw.c"
    .text
.globl helloWorld
    .type   helloWorld, @function
helloWorld:
.LFB0:
    .cfi_startproc
    movl    $123, %eax
    ret
    .cfi_endproc
.LFE0:
    .size   helloWorld, .-helloWorld
    .ident  "GCC: (GNU) 4.4.7 20120313 (Red Hat 4.4.7-16)"
    .section    .note.GNU-stack,"",@progbits
/tmp % 

Also having the file m.c :

#include <stdio.h>

extern int helloWorld();

int main()
{
  printf("%d\n", helloWorld());
  return 0;
}

I can do :

/tmp % gcc m.c hw.s
/tmp % ./a.out
123

I propose you to do the same as, write helloWorld in C then generate the assembler with option -S, doing that you are sure to follow the gcc requirements in the function definition

bruno
  • 32,421
  • 7
  • 25
  • 37
  • why you written `hw.s` in gcc and why you are creating two c file? – Jason Feb 15 '19 at 12:54
  • @Jason when I do `gcc -S hw.c` that produces `hw.s`, the other C file is the equivalent of your `testing.c`. – bruno Feb 15 '19 at 12:57
  • Okay now when I try to do `./a.out` getting an error `'.' is not recognized as an internal or external command, operable program or batch file.` – Jason Feb 15 '19 at 13:05
  • '.' ? Please note I do `./a.out` to specify I want to get `a.out` in the current directory, what is your OS ? – bruno Feb 15 '19 at 13:08
  • It's windows and yes I have a.out I checked in the folder – Jason Feb 15 '19 at 13:08
  • Another something strange, you say "C" and use extension "c" but you compile with g++ rather than gcc – bruno Feb 15 '19 at 13:09
  • Windows ? using _cygwin_ ? And doing just do`a.out` (in my case there is no space in `./a.out` I mean not `. /a.out` etc) – bruno Feb 15 '19 at 13:11
  • so what append when doing `a.out` ? May be your assembler is not compatible with what gcc code expect. This is why I not did by hand but using `gcc -S` – bruno Feb 15 '19 at 13:18
  • you don't have to ask me, just say ^^ – bruno Feb 15 '19 at 13:22
  • Actually I have a BubbleSort technique written in asm file what I am trying to do with I am including asm file in c file and trying to build it successfully, can you help me out to successfully achieve this? – Jason Feb 15 '19 at 13:26
  • @Jason oh so is more complicate than that question because you have parameters. To be sure you respect the gcc function call the best is probably to write a C function with the same parameters, to generate the assembler (-S) and look at it and to respect that in your definition written by hand – bruno Feb 15 '19 at 13:31
  • So it's not possible to do with .asm file? – Jason Feb 15 '19 at 13:34
  • I'd avoid giving the two source files the same basename stem - it makes it harder to use Make default rules (you should just need `hw: hw.o hw_asm.o` if you called them `hw.c` and `hw_asm.s`, for example). – Toby Speight Feb 15 '19 at 13:50
  • Bruno: @Jason is on Windows using MASM. C names are prefixed with a leading `_`, so the `.asm` should define `_helloWorld proc`. – Peter Cordes Feb 15 '19 at 15:33
  • @PeterCordes in fact I was surprised _gcc_ doesn't add some '_', in my (old) memories the compiler uses them – bruno Feb 15 '19 at 15:42
  • @bruno: GNU/Linux used to use the a.out file format (https://en.wikipedia.org/wiki/A.out), with leading underscore name mangling. When they switched to ELF sometime around 1996 or 1997 ([a.out replaced by ELF file format?](//stackoverflow.com/q/2352378)), that name mangling convention was dropped as unnecessary. (Your RedHat gcc is very old, but not *that* old!). Current Windows and OS X conventions do still prepend `_`, so you may have seen it there. – Peter Cordes Feb 15 '19 at 15:46
  • @PeterCordes yes when I posted I was on an old RedHat & gcc. I started development loooooong time ago, this is why I remember the use of '_', I do not look at assembler often since years. Thank you for the information – bruno Feb 15 '19 at 15:53
0

1.) Create an ELF object file from the assembly file

nasm -f elf64 -o assembly.o assembly.asm

2.) Create an ELF object file of testing.c file

gcc -c testing.c -o testing.o

3.) Link ELF object file together to create final executable file.

gcc -o testing assembly.o testing.o

4.) Run final executable file

./testing

use extern int hellowrold();

fuz
  • 88,405
  • 25
  • 200
  • 352
GBiradar
  • 161
  • 1
  • 11
  • 1
    The OP is using MASM directives like `proc`, so they're clearly not on Windows. Making a Linux ELF executable isn't going to help them. (ELF platforms like Linux don't prepend `_` to symbol names, but Windows does, hence the link error. Or, or it would still be a link error if the OP had passed the `.obj` from MASM to g++, but they didn't even do that!) – Peter Cordes Feb 15 '19 at 15:38