C++-Assembly linking on x86 / ubuntu - undefined reference to ThreadRoot, SWITCH - linux

I am building Nachos source on Ubuntu 12.04
If we believe "lscpu" output, machine arch is x86. I am getting the following error at the last step of make:
$ make
g++ -m32 -P -I../network -I../filesys -I../userprog -I../threads -I../machine -I../lib -iquote -Dx86 -DLINUX -c ../threads/switch.S
g++ bitmap.o debug.o libtest.o sysdep.o interrupt.o stats.o timer.o console.o machine.o mipssim.o translate.o network.o disk.o alarm.o kernel.o main.o scheduler.o synch.o thread.o addrspace.o exception.o synchconsole.o directory.o filehdr.o filesys.o pbitmap.o openfile.o synchdisk.o post.o switch.o -m32 -o nachos
scheduler.o: In function `Scheduler::Run(Thread*, bool)':
/home/userx/nachos/NachOS-4.0/code/build.linux/../threads/scheduler.cc:133: undefined reference to `SWITCH'
thread.o: In function `Thread::StackAllocate(void ()(void), void*)':
/home/userx/nachos/NachOS-4.0/code/build.linux/../threads/thread.cc:345: undefined reference to `ThreadRoot'
/home/userx/nachos/NachOS-4.0/code/build.linux/../threads/thread.cc:356: undefined reference to `ThreadRoot'
collect2: ld returned 1 exit status
make: * [nachos] Error 1
$
Here is the switch.S that has the symbol defs --
/* We define two routines for each architecture:
*
* ThreadRoot(InitialPC, InitialArg, WhenDonePC, StartupPC)
<...>
#ifdef SOLARIS
.globl ThreadRoot
ThreadRoot:
#else
.globl _ThreadRoot
_ThreadRoot:
#endif
#ifdef x86
.text
.align 2
.globl ThreadRoot
.globl _ThreadRoot
_ThreadRoot:
ThreadRoot:
<...>
.globl SWITCH
.globl _SWITCH
_SWITCH:
SWITCH:
<...>
#endif
I have skipped the #ifdefs for more arch like DECMIPS, POWERPC, APPLEPOWERPC etc.
Yes, my env $PATH includes dir where switch.s resides :/home/userx/nachos/NachOS-4.0/code/threads/
Please let me know if any more info is needed to debug. Thanks a lot.

Try adding underscore in the C header file that have extern "C" SWITCH and ThreadRoot, and change too the .c file in where the error is. I mean use _SWITCH instead SWITCH and the same for ThreadRoot.

Related

Linking library (from assembly files) with main.c in Makefile

Im passionate about assembly and wanted to start coding from home on linux instead of mac I usually use.
I really struggle for 4 days about this issue.
you can find my makefile and clone repository at the following url:
<code>NAME = libfts.a
ASM_FILES = ft_isascii \
OS := $(shell uname)
ifeq ($(OS), Darwin)
ASM_COMPILER = ~/.brew/bin/nasm -f macho64 -g
else
ASM_COMPILER = nasm -f elf64 -g
endif
ASM_SRC_DIR = srcs/
ASM_OBJ_DIR_NAME = obj
ASM_OBJ_DIR = $(ASM_OBJ_DIR_NAME)/
ASM_OBJ := $(addsuffix .o,$(ASM_FILES))
ASM_OBJ := $(addprefix $(ASM_OBJ_DIR),$(ASM_OBJ))
TEST = maintest.out
TEST_FILES = maintest
C_COMPILER = clang -Wall -Werror -Wextra -O3
TEST_DIR_NAME = test
TEST_DIR = $(TEST_DIR_NAME)/
TEST_OBJ := $(addsuffix .o,$(TEST_FILES))
TEST_OBJ := $(addprefix $(TEST_DIR),$(TEST_OBJ))
OBJ_PATHS := $(ASM_OBJ) $(TEST_OBJ)
all: $(NAME)
$(NAME): $(ASM_OBJ)
ar rc $(NAME) $(ASM_OBJ)
test: re $(TEST_OBJ)
$(C_COMPILER) -L. $(NAME) $(TEST_OBJ) -o $(TEST)
$(ASM_OBJ): $(ASM_OBJ_DIR)%.o: $(ASM_SRC_DIR)%.s
#/bin/mkdir -p $(ASM_OBJ_DIR)
$(ASM_COMPILER) $< -o $#
$(TEST_OBJ): $(TEST_DIR)%.o: $(TEST_DIR)%.c
$(C_COMPILER) -c -I. $< -o $#
clean:
-/bin/rm -f $(OBJ_PATHS)
/usr/bin/find . -name "$(ASM_OBJ_DIR_NAME)" -maxdepth 1 -type d -empty -delete
fclean: clean
-/bin/rm -f $(NAME)
-/bin/rm -f $(TEST)
re: fclean all
.PHONY: all clean fclean re
I have this error message when I try "make test" on the linux:
test/maintest.o: In function `main':
test/maintest.c:(.text+0x33): undefined reference to `ft_isascii'
undefined reference to etc.
.h content:
#ifndef _LIBFTS
# define _LIBFTS
#include <stddef.h>
int ft_isascii(int c);
#endif
ft_isascii.s content:
global _ft_isascii
section .text
_ft_isascii: ; int ft_isascii
and edi, 0xffffff80 ; mask with the 128 firsts bits left to 0 as ASCII range from 0 to 7f in hexa (just below 80)
sete al ; SETE sets AL to 1 if above condition code means "equal", otherwise it sets AL to 0.
movzx eax, al
ret
I would REALLY be thanksful for any tips to solve this issue...
Regards,
There are two problems to be fixed:
First, on ELF targets (most Unixes except macOS), C functions are not decorated with an underscore. To fix your code, remove the leading underscore from all symbols. Make sure to remove it everywhere.
Second, the linker when looking at an archive (.a file) only picks files it needs right now to satisfy dependencies. So when you pass the archive before maintest.o, the linker doesn't take anything from the archive at all as it doesn't need any ft_... symbols at that point. These symbols are only needed once the linker has seen maintest.o. To fix this issue, move the $(NAME) operand to after $(TEST_OBJ). As a general rule of thumb, always place libraries after object files on the linker command line.
On macOS, you won't observe this problem because they use lld, the LLVM linker, which is a bit unconventional in that it defers the choice which objects to take out of archives until it has looked at the symbol tables of all operands, making your actually broken invocation work. Don't depend on this behaviour, please.

link error with "undefined lua_xxxxx" when building lsnes

In my ubuntu 14.xx, I try to compile lsnes emulator to use the mario-ai script from aleju/mario-ai, and I've tried to google many solutions to solve the problem below:
Here is the output from the console:
make[3]: __all__.files' is up to date.
make[3]: Leaving directory/home/pengsuyu/software/lsnes/sourcecode/src/platform/macosx'
make[2]: Leaving directory /home/pengsuyu/software/lsnes/sourcecode/src/platform'
g++ -o lsnescat all_common.files all_platform.files-pthread -lboost_iostreams -lboost_filesystem -lboost_system -lz -lgcrypt -lgpg-error -L/usr/lib/x86_64-linux-gnu -lcurl -rdynamic -ldlcat core/all.ldflags lua/all.ldflags fonts/all.ldflags library/all.ldflags interface/all.ldflags video/all.ldflags emulation/all.ldflags cmdhelp/all.ldflags platform/all.ldflags
core/multitrack.o: In functionlua::state::get_string(int, std::string const&)':
/home/pengsuyu/software/lsnes/sourcecode/src/core/../../include/library/lua-base.hpp:317: undefined reference to lua_tolstring'
core/multitrack.o: In functionlua::state::get_bool(int, std::string const&)':
/home/pengsuyu/software/lsnes/sourcecode/src/core/../../include/library/lua-base.hpp:334: undefined reference to lua_toboolean'
core/multitrack.o: In functionlua::state::type(int)':
.
.
/home/pengsuyu/software/lsnes/sourcecode/src/library/lua.cpp:536: undefined reference to lua_close'
library/lua.o: In functionlua::state::pushcfunction(int ()(lua_State))':
/home/pengsuyu/software/lsnes/sourcecode/src/library/../../include/library/lua-base.hpp:504: undefined reference to lua_pushcclosure'
library/lua.o: In functionlua::state::getfield(int, char const*)':
/home/pengsuyu/software/lsnes/sourcecode/src/library/../../include/library/lua-base.hpp:506: undefined reference to lua_getfield'
library/lua.o: In functionlua::state::insert(int)':
/home/pengsuyu/software/lsnes/sourcecode/src/library/../../include/library/lua-base.hpp:509: undefined reference to lua_insert'
collect2: error: ld returned 1 exit status
make[1]: *** [lsnes] Error 1
make[1]: Leaving directory/home/pengsuyu/software/lsnes/sourcecode/src'
make: *** [src/all_files] Error 2
==================================
At the beginning, I think, the linker cannot find my lua library. So I tried to compile my main.cpp with test.lua.
main.cpp:
#include <stdio.h>
#include <iostream>
//extern "C"
//{
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
//} // liblua5.1-c++.a
lua_State * L;
int main ()
{
L = lua_open();
luaL_openlibs(L);
luaL_dofile(L, "d:\\test.lua");
return 0;
}
test.lua:
print("Hello World");
I write a MakeFile to generate the executable file "main":
main:main.o
gcc -o $# $< -llua5.1 -lstdc++
main.o:
gcc -c main.cpp
clean:
-rm *.o
It works when I add the compile option "-llua5.1" and "-lstdc++" otherwise it throws the same error as I compiled lsnes
I am not familiar with gcc and Makefile. Please help me to solve this problem.
I've solved my question
The way to solve this problem is just to change one line in the file named "options.build".
1. find the line "LUA=lua" in options.build
2. change this line to "LUA=lua5.1"
because the needed library is 5.1, so if you want to build it successfully, you must use the "lua5.1" library however the default configuration is "lua" not "lua5.1"

Linking cuda object file

I have one .cu file that contains my cuda kernel, and a wrapper function that calls the kernel. I have a bunch of .c files as well, one of which contains the main function. One of these .c files calls the wrapper function from the .cu to invoke the kernel.
I compile these files as follows:
LIBS=-lcuda -lcudart
LIBDIR=-L/usr/local/cuda/lib64
CFLAGS = -g -c -Wall -Iinclude -Ioflib
NVCCFLAGS =-g -c -Iinclude -Ioflib
CFLAGSEXE =-g -O2 -Wall -Iinclude -Ioflib
CC=gcc
NVCC=nvcc
objects := $(patsubst oflib/%.c,oflib/%.o,$(wildcard oflib/*.c))
table-hash-gpu.o: table-hash.cu table-hash.h
$(NVCC) $(NVCCFLAGS) table-hash.cu -o table-hash-gpu.o
main: main.c $(objects) table-hash-gpu.o
$(CC) $(CFLAGSEXE) $(objects) table-hash-gpu.o -o udatapath udatapath.c $(LIBS) $(LIBDIR)
So far everything is fine. table-hash-gpu.cu calls a function from one of the .c files. When linking for main, I get the error that the function is not present. Can someone please tell me what is going on?
nvcc compiles both device and host code using the host C++ compiler, which implies name mangling. If you need to call a function compiled with a C compiler in C++, you must tell the C++ compiler that it uses C calling conventions. I presume that the errors you are seeing are analogous to this:
$ cat cfunc.c
float adder(float a, float b, float c)
{
return a + 2.f*b + 3.f*c;
}
$ cat cumain.cu
#include <cstdio>
float adder(float, float, float);
int main(void)
{
float result = adder(1.f, 2.f, 3.f);
printf("%f\n", result);
return 0;
}
$ gcc -m32 -c cfunc.c
$ nvcc -o app cumain.cu cfunc.o
Undefined symbols:
"adder(float, float, float)", referenced from:
_main in tmpxft_0000b928_00000000-13_cumain.o
ld: symbol(s) not found
collect2: ld returned 1 exit status
Here we have code compiled with nvcc (so the host C++ compiler) trying to call a C function and getting a link error, because the C++ code expects a mangled name for adder in the supplied object file. If the main is changed like this:
$ cat cumain.cu
#include <cstdio>
extern "C" float adder(float, float, float);
int main(void)
{
float result = adder(1.f, 2.f, 3.f);
printf("%f\n", result);
return 0;
}
$ nvcc -o app cumain.cu cfunc.o
$ ./app
14.000000
It works. Using extern "C" to qualify the declaration of the function to the C++ compiler, it will not use C++ mangling and linkage rules when referencing adder and the resulting code links correctly.

Why I'm not getting "Multiple definition" error from the g++?

I tried to link my executable program with 2 static libraries using g++. The 2 static libraries have the same function name. I'm expecting a "multiple definition" linking error from the linker, but I did not received. Can anyone help to explain why is this so?
staticLibA.h
#ifndef _STATIC_LIBA_HEADER
#define _STATIC_LIBA_HEADER
int hello(void);
#endif
staticLibA.cpp
#include "staticLibA.h"
int hello(void)
{
printf("\nI'm in staticLibA\n");
return 0;
}
output:
g++ -c -Wall -fPIC -m32 -o staticLibA.o staticLibA.cpp
ar -cvq ../libstaticLibA.a staticLibA.o
a - staticLibA.o
staticLibB.h
#ifndef _STATIC_LIBB_HEADER
#define _STATIC_LIBB_HEADER
int hello(void);
#endif
staticLibB.cpp
#include "staticLibB.h"
int hello(void)
{
printf("\nI'm in staticLibB\n");
return 0;
}
output:
g++ -c -Wall -fPIC -m32 -o staticLibB.o staticLibB.cpp
ar -cvq ../libstaticLibB.a staticLibB.o
a - staticLibB.o
main.cpp
extern int hello(void);
int main(void)
{
hello();
return 0;
}
output:
g++ -c -o main.o main.cpp
g++ -o multipleLibsTest main.o -L. -lstaticLibA -lstaticLibB -lstaticLibC -ldl -lpthread -lrt
The linker does not look at staticLibB, because by the time staticLibA is linked, there are no unfulfilled dependencies.
That's an easy one. An object is only pulled out of a library if the symbol referenced hasn't already been defined. Only one of the hellos are pulled (from A). You'd get errors if you linked with the .o files.
When the linker tries to link main.o into multipleLibsTest and sees that hello() is unresolved, it starts searching the libraries in the order given on the command line. It will find the definition of hello() in staticLibA and will terminate the search.
It will not look in staticLibB or staticLibC at all.
If staticLibB.o contained another symbol not in staticLibA and that was pulled into the final executable, you then get a multiple definition of hello error, as individual .o files are pulled out of the library and two of them would have hello(). Reversing the order of staticLibA and staticLibB on the link command line would then make that error go away.

gcc, static library, external assembly function becomes undefined symbol

I have a problem with g++ building an application which links to a static library, where the latter shall contain some global functions written in external asm-files, compiled with yasm. So in the library, I have
#ifdef __cplusplus
extern "C" {
#endif
extern void __attribute__((cdecl)) interp1( char *pSrc );
extern void __attribute__((cdecl)) interp2( char *pSrc );
#ifdef __cplusplus
}
#endif
which I reference elsewhere inside the library. Then, there is the implementation in an asm-file, like this:
section .data
; (some data)
section .text
; (some text)
global _interp1
_interp1:
; (code ...)
ret
global _interp2
_interp2:
; (code ...)
ret
Compiling and Linking work fine for the library, I do
yasm -f elf32 -O2 -o interp.o interp.asm
and then
ar -rc libInterp.a objs1.o [...] objsN.o interp.o
ranlib libInterp.a
Now finally, to link the library to the main application, I do
g++ -O4 -ffast-math -DNDEBUG -fomit-frame-pointer -DARCH_X86 -fPIC -o ../bin/interp this.o that.o -lboost_thread -lpthread ./libInterp.a
and I get the errors
undefined reference to `interp1'
undefined reference to `interp2'
What am I doing wrong here? any help is appreciated.
Depending on the target type, gcc will not prepend a leading underscore to external symbols. It appears that this is the case in your scenario.
The simple fix is probably to remove the underscores from the names in your assembly file.
A couple alternatives you might consder might be to use something like one of the following macros for your symbols in the assembly file:
from http://svn.xiph.org/trunk/oggdsf/src/lib/codecs/webm/libvpx/src/vpx_ports/x86_abi_support.asm
; sym()
; Return the proper symbol name for the target ABI.
;
; Certain ABIs, notably MS COFF and Darwin MACH-O, require that symbols
; with C linkage be prefixed with an underscore.
;
%ifidn __OUTPUT_FORMAT__,elf32
%define sym(x) x
%elifidn __OUTPUT_FORMAT__,elf64
%define sym(x) x
%elifidn __OUTPUT_FORMAT__,x64
%define sym(x) x
%else
%define sym(x) _ %+ x
%endif
from http://www.dcs.warwick.ac.uk/~peter/otherstuff.html
%macro public_c_symbol 1
GLOBAL %1,_%1
%1:
_%1:
%endmacro
public_c_symbol my_external_proc:
; ...
RET

Resources