I'm compiling a c file in xv6 and I used their Makefile to compile. I used readelf and found out the ELF it outputs has just one program header.
ryan#ubuntu:~/Documents/xv6-OS-for-arm-v8-fixed/xv6-armv8/usr$ readelf -l _init --wide
Elf file type is EXEC (Executable file)
Entry point 0x0
There is 1 program header, starting at offset 64
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x000078 0x0000000000000000 0x0000000000000000 0x0011a8 0x0011c0 RWE 0x8
Section to Segment mapping:
Segment Sections...
00 .text .rodata .data .bss
This program header has just 4 sections: .text .rodata .data .bss
I checked its CFLAGS and it's showed below:
CROSSCOMPILE := aarch64-none-elf-
# try linux eabi
# CROSSCOMPILE := arm-linux-gnueabi-
CC = $(CROSSCOMPILE)gcc
AS = $(CROSSCOMPILE)as
LD = $(CROSSCOMPILE)ld
OBJCOPY = $(CROSSCOMPILE)objcopy
OBJDUMP = $(CROSSCOMPILE)objdump
CFLAGS = -march=armv8-a -mtune=cortex-a57 -fno-pic -static -fno-builtin -fno-strict-aliasing -Wall -I. -g
LDFLAGS = -L.
ASFLAGS = -march=armv8-a
But I don't know which of these flags make it this way.
I'm build a ARM-based OS. How can I compile one of this ELF in ARM by myself?
Related
SQlite seems to use an own varian of libtool. Now I have added an extension to SQLite depends on some C++ code. However, I'm not able to link the C and C++ code. The error I get is:
c++ -Wl,-undefined,error -o libsqlite3.la sqlite3.lo -lz extsql.lo \
-rpath "/usr/local/lib"
ld: warning: ignoring file sqlite3.lo, building for macOS-x86_64 but attempting to link with file built for unknown-unsupported file format ( 0x23 0x20 0x73 0x71 0x6C 0x69 0x74 0x65 0x33 0x2E 0x6C 0x6F 0x20 0x2D 0x20 0x61 )
ld: warning: ignoring file extsql.lo, building for macOS-x86_64 but attempting to link with file built for unknown-unsupported file format ( 0x23 0x20 0x65 0x64 0x67 0x65 0x73 0x71 0x6C 0x2E 0x6C 0x6F 0x20 0x2D 0x20 0x61 )
Undefined symbols for architecture x86_64:
"_main", referenced from:
implicit entry/start for main executable
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Thesee are my changes to the Makefile.in:
LTCOMPILECXX = $(LIBTOOL) --mode=compile --tag=CXX $(TCC) $(LTCOMPILE_EXTRAS)
LTLINKCXX = $(LIBTOOL) --tag=CXX --mode=link $(TCXX) $(LTCOMPILE_EXTRAS) #LDFLAGS# $(LTLINK_EXTRAS)
libsqlite3.la: $(LIBOBJ)
$(CXX) -Wl,-undefined,error -o $# $(LIBOBJ) $(TLIBS) \
${ALLOWRELEASE} -rpath "$(libdir)"
libtclsqlite3.la: tclsqlite.lo libsqlite3.la
$(CXX) -Wl,-undefined,error -o $# tclsqlite.lo \
libsqlite3.la #TCL_STUB_LIB_SPEC# $(TLIBS) \
-rpath "$(TCLLIBDIR)" \
-avoid-version
extsql$(TEXE): shell.c libsqlite3.la
$(CXX) $(READLINE_FLAGS) $(SHELL_OPT) -o $# \
shell.c libsqlite3.la \
$(LIBREADLINE) $(TLIBS) -rpath "$(libdir)"
extsql.lo: $(TOP)/extsql/extsql extsql_ext.h
$(LTCOMPILECXX) -c $(TOP)/extsql/extsql.cpp
Note the use of CXX instead of the original LTLINK command for the original makefile:
libsqlite3.la: $(LIBOBJ)
$(LTLINK) -no-undefined -o $# $(LIBOBJ) $(TLIBS) \
${ALLOWRELEASE} -rpath "$(libdir)" -version-info "8:6:8"
libtclsqlite3.la: tclsqlite.lo libsqlite3.la
$(LTLINK) -no-undefined -o $# tclsqlite.lo \
libsqlite3.la #TCL_STUB_LIB_SPEC# $(TLIBS) \
-rpath "$(TCLLIBDIR)" \
-version-info "8:6:8" \
-avoid-version
sqlite3$(TEXE): shell.c sqlite3.c
$(LTLINK) $(READLINE_FLAGS) $(SHELL_OPT) -o $# \
shell.c sqlite3.c \
$(LIBREADLINE) $(TLIBS) -rpath "$(libdir)"
The original makefile can be found here:
https://github.com/sqlite/sqlite/blob/branch-3.39/Makefile.in
Having the following assembly source:
# hello_asm.s
# as hello_asm.s -o hello_asm.o
# ld hello_asm.o -e _main -o hello_asm
.section __DATA,__data
str:
.asciz "Hello world!\n"
.section __TEXT,__text
.globl _main
_main:
movl $0x2000004, %eax # preparing system call 4
movl $1, %edi # STDOUT file descriptor is 1
movq str#GOTPCREL(%rip), %rsi # The value to print
movq $100, %rdx # the size of the value to print
syscall
#
# EXITING
#
movl $0, %ebx
movl $0x2000001, %eax # exit 0
syscall
by compiling and linking with the following instructions:
as sum.s -g -o sum.o
ld -arch x86_64 -e main -L /Library/Developer/CommandLineTools/SDKs/MacOSX10.15.sdk/usr/lib -lSystem sum.o -o sum
and by trying to debug it on LLDB, I get the following result:
❯❯❯❯ lldb sum.o ~/D/test
(lldb) target create "sum.o"
Current executable set to '/Users/mbertamini/Downloads/test/sum.o' (x86_64).
(lldb) list
(lldb) b 16
error: No selected frame to use to find the default file.
error: No file supplied and no default file available.
(lldb)
This is the dwarf:
❯❯❯❯ dwarfdump sum.o ~/D/t/summ
sum.o: file format Mach-O 64-bit x86-64
.debug_info contents:
0x00000000: Compile Unit: length = 0x00000094 version = 0x0004 abbr_offset = 0x0000 addr_size = 0x08 (next unit at 0x00000098)
0x0000000b: DW_TAG_compile_unit
DW_AT_stmt_list (0x00000000)
DW_AT_low_pc (0x0000000000000000)
DW_AT_high_pc (0x0000000000000026)
DW_AT_name ("sum.s")
DW_AT_comp_dir ("<filepath>")
DW_AT_producer ("Apple clang version 12.0.0 (clang-1200.0.32.27)")
DW_AT_language (DW_LANG_Mips_Assembler)
0x0000007e: DW_TAG_label
DW_AT_name ("main")
DW_AT_decl_file ("<filepath-file>")
DW_AT_decl_line (10)
DW_AT_low_pc (0x0000000000000000)
DW_AT_prototyped (0x00)
0x00000095: DW_TAG_unspecified_parameters
0x00000096: NULL
0x00000097: NULL
❯❯❯❯ as -v ~/D/t/summ
Apple clang version 12.0.0 (clang-1200.0.32.27)
Target: x86_64-apple-darwin20.2.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang" -cc1as -triple x86_64-apple-macosx11.0.0 -filetype obj -main-file-name - -target-cpu penryn -fdebug-compilation-dir /Users/mbertamini/Downloads/test/summ -dwarf-debug-producer "Apple clang version 12.0.0 (clang-1200.0.32.27)" -dwarf-version=4 -mrelocation-model pic -o a.out -
what's the problem? How am I supposed to do?
The issue is that the source file for which the debugging info is mapped should be used (sum.s):
$ as sum.s -g -o sum.o
$ ld -arch x86_64 -e _main -macosx_version_min 10.13 -lSystem sum.o -o sum
$ lldb sum
(lldb) target create "sum"
Current executable set to 'sum' (x86_64).
(lldb) b sum.s:16
Breakpoint 1: where = sum`main + 26, address = 0x0000000100000fac
(lldb)
When assembling use the -O0 optimization along the -g Code Generation Option.(This is important only when compiling with clang; this doesn't apply with as)
↳ lldb: resolving breakpoints to locations
Today I met a really interesting problem with my NixOS distro. I just wanted to create a statically compiled OCaml progam and couldn`t do that. Then I tried to do that with an ANSI C canonical toy "hello world!" application:
$> cat mytest.c
#include <stdio.h>
int
main ()
{
puts ("hello world!") ;
}
My distro:
$> uname -a
Linux cat 4.19.36 #1-NixOS SMP Sat Apr 20 07:16:05 UTC 2019 x86_64 GNU/Linux
Compiler:
$> gcc -v
Using built-in specs.
COLLECT_GCC=/nix/store/myq0x6mjbdzxr9fckqn6kgy89kz19nkp-gfortran-7.4.0/bin/gcc
COLLECT_LTO_WRAPPER=/nix/store/myq0x6mjbdzxr9fckqn6kgy89kz19nkp-gfortran-7.4.0/libexec/gcc/x86_64-unknown-linux-gnu/7.4.0/lto-wrapper
Target: x86_64-unknown-linux-gnu
Configured with:
Thread model: posix
gcc version 7.4.0 (GCC)
Cannot produce static exec :
$> gcc -static mytest.c -o hello
/nix/store/0y7jmqnj48ikjh37n3dl9kqw9hnn68nq-binutils-2.31.1/bin/ld: cannot find -lc
collect2: error: ld returned 1 exit status
Any ideas?
Usually a "dynamically linked" program hello is generated by gccwithout a problem.
No such issues on Lubuntu. I was advised to try a different distro and test that exec is running on NixOS. I did it - produced an exec with gcc on Lubuntu and started it on NixOS. Therefore I think that the problem is not with gcc but with NixOS.
How does NixOS treat this problem (i.e., generation of statically compiled exec files)?
And, of course, I'm also interested in the results concerning ocamlopt compiler rather then gcc but I think that the problem is common for all compilers (I tried Haskell ghc too by the way with the same results).
brgs
UPDATE: from a discussion on another thread:
1 #Ston17 You may have the .so but not the .a – norok2
2
3 yes - i have .so what the difference? can the presence of .a improve the situation? – Ston17
4
5 Yes. You typically need .a library to have the static linking work correctly – norok2
$> find /nix/store/ -name *libc.a.*
$>
can this be the reason?
UPDATE2: as concerning ocamlopt:
source file
$> cat mytest.ml
print_string "hello world!" ;;
print_newline () ;;
as you can see no special calls to anything. let try to make static exec:
$> ocamlopt -ccopt -static mytest.ml -o ocaml_test
/nix/store/0y7jmqnj48ikjh37n3dl9kqw9hnn68nq-binutils-2.31.1/bin/ld: cannot find -lm
/nix/store/0y7jmqnj48ikjh37n3dl9kqw9hnn68nq-binutils-2.31.1/bin/ld: cannot find -ldl
/nix/store/0y7jmqnj48ikjh37n3dl9kqw9hnn68nq-binutils-2.31.1/bin/ld: cannot find -lc
collect2: error: ld returned 1 exit status
so ld just cannot link to static version of libc. and i cannot find libc.a in the hole system
any suggetions?
here https://vaibhavsagar.com/blog/2018/01/03/static-haskell-nix/ is explained how you could obtain in NixOS statical versions of sys libraries
nix-shell config file:
let
pkgs = import <nixpkgs> {} ;
in pkgs.buildFHSUserEnv {
name = "fhs" ;
targetPkgs = pkgs: with pkgs; [
pkgs.glibc.static
pkgs.zlib.static
pkgs.libffi
pkgs.libtool
pkgs.musl
pkgs.ghc
pkgs.gcc
pkgs.ocaml
] ;
}
after that in nix-shell you start chroot FHS and copy needed sys libs into your folder and close chroot FHS
and after that compile your file staticaly
good with gcc:
$> gcc -static -L/home/.local/lib/ mytest.c -o ansiC_test
$> ldd ansiC_test
not a dynamic executable
not so good but maybe working with ocaml:
ocamlopt -ccopt -static -cclib -L/home/.local/lib mytest.ml -o ocaml_test
ocamlopt -ccopt -static -cclib -L/home/nomad/.local/lib mytest.ml -o ocaml_test
/nix/store/0y7jmqnj48ikjh37n3dl9kqw9hnn68nq-binutils-2.31.1/bin/ld: /nix/store/j1v6kkxq081q4m4fw7gazaf6rb3vy87p-ocaml-4.06.1/lib/ocaml/libasmrun.a(unix.o): in function `caml_dlopen':
/build/ocaml-4.06.1/asmrun/unix.c:273: warning: Using 'dlopen' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
$> ldd ocaml_test
not a dynamic executable
dont work with ghc though :
ghc -static -optl-static -L/home/.local/lib/ mytest.hs -o haskell_test
[1 of 1] Compiling Main ( mytest.hs, mytest.o )
Linking haskell_test ...
/nix/store/0y7jmqnj48ikjh37n3dl9kqw9hnn68nq-binutils-2.31.1/bin/ld: /nix/store/wfgrz42bpcl1r635dasfk7r236hm83az-ghc-8.6.4/lib/ghc-8.6.4/rts/libHSrts.a(Linker.o): in function `internal_dlopen':
Linker.c:(.text.internal_dlopen+0x7): warning: Using 'dlopen' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
/nix/store/0y7jmqnj48ikjh37n3dl9kqw9hnn68nq-binutils-2.31.1/bin/ld: cannot find -lffi
collect2: error: ld returned 1 exit status
`cc' failed in phase `Linker'. (Exit code: 1)
make: *** [makefile:5: haskell] Error 1
ok. ocaml works:
lubuntu#lubuntu:~/Documents$ ./ocaml_hello_nix
hello world!
lubuntu#lubuntu:~/Documents$ readelf -l ocaml_hello_nix
Elf file type is EXEC (Executable file)
Entry point 0x4017a0
There are 9 program headers, starting at offset 64
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
LOAD 0x0000000000000000 0x0000000000400000 0x0000000000400000
0x00000000000005d8 0x00000000000005d8 R 0x1000
LOAD 0x0000000000001000 0x0000000000401000 0x0000000000401000
0x0000000000107275 0x0000000000107275 R E 0x1000
LOAD 0x0000000000109000 0x0000000000509000 0x0000000000509000
0x00000000000db191 0x00000000000db191 R 0x1000
LOAD 0x00000000001e5140 0x00000000005e6140 0x00000000005e6140
0x0000000000008a18 0x000000000001dfe0 RW 0x1000
NOTE 0x0000000000000238 0x0000000000400238 0x0000000000400238
0x0000000000000020 0x0000000000000020 R 0x4
NOTE 0x0000000000000258 0x0000000000400258 0x0000000000400258
0x0000000000000020 0x0000000000000020 R 0x8
TLS 0x00000000001e5140 0x00000000005e6140 0x00000000005e6140
0x0000000000000020 0x0000000000000060 R 0x8
GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 RW 0x10
GNU_RELRO 0x00000000001e5140 0x00000000005e6140 0x00000000005e6140
0x0000000000002ec0 0x0000000000002ec0 R 0x1
Section to Segment mapping:
Segment Sections...
00 .note.ABI-tag .note.gnu.property .rela.plt
01 .init .plt .text __libc_freeres_fn __libc_thread_freeres_fn .fini
02 .rodata .eh_frame .gcc_except_table
03 .tdata .init_array .fini_array .data.rel.ro .got .got.plt .data __libc_subfreeres __libc_IO_vtables __libc_atexit __libc_thread_subfreeres .bss __libc_freeres_ptrs
04 .note.ABI-tag
05 .note.gnu.property
06 .tdata .tbss
07
08 .tdata .init_array .fini_array .data.rel.ro .got
haskell works. the reason was that binary NixOS packet was built without FFI support. i installed ghc from sources and all become fine:
lubuntu#lubuntu:~/Documents$ ./haskell_hello_nix
hello world!
lubuntu#lubuntu:~/Documents$ readelf -l haskell_hello_nix
Elf file type is EXEC (Executable file)
Entry point 0x405d40
There are 6 program headers, starting at offset 64
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
LOAD 0x0000000000000000 0x0000000000400000 0x0000000000400000
0x0000000000188ba4 0x0000000000188ba4 R E 0x1000
LOAD 0x0000000000188ec0 0x0000000000589ec0 0x0000000000589ec0
0x00000000000104c0 0x000000000001ac98 RW 0x1000
NOTE 0x0000000000000190 0x0000000000400190 0x0000000000400190
0x0000000000000020 0x0000000000000020 R 0x4
GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 RW 0x10
TLS 0x0000000000188ec0 0x0000000000589ec0 0x0000000000589ec0
0x0000000000000070 0x00000000000000b8 R 0x8
GNU_RELRO 0x0000000000188ec0 0x0000000000589ec0 0x0000000000589ec0
0x0000000000003140 0x0000000000003140 RW 0x20
Section to Segment mapping:
Segment Sections...
00 .note.ABI-tag .rela.plt .init .plt .text __libc_thread_freeres_fn .fini .rodata .gcc_except_table .eh_frame
01 .tdata .data.rel.ro.local .fini_array .init_array .data.rel.ro .preinit_array .got .got.plt .data .tm_clone_table __libc_IO_vtables __libc_atexit __libc_thread_subfreeres .bss __libc_freeres_ptrs
02 .note.ABI-tag
03
04 .tdata .tbss
05 .tdata .data.rel.ro.local .fini_array .init_array .data.rel.ro .preinit_array .got
good. tnx to all who was concerned. you save my a$$
I have to compile c++ code with g++ 6.4.0 (Homebrew g++-6) to a static lib, which is then wrapped into a C static lib (Homebrew gcc-6) and linked to a clang++ (clang 8.1.0) app on macos sierra. So the picture is:
c++ (gcc) wrapped in c (gcc) linked to clang app.
As a testcase I use shared-lib.cpp:
#include <iostream>
using namespace std;
void foo()
{
cerr << "Hi from the shared lib" << endl;
}
together with shared-lib.h
extern void foo();
and wrapper-lib.c
#include "shared-lib.h"
int wrapper()
{
foo();
return 123;
}
along with wrapper-lib.h
#ifdef __cplusplus
extern "C"
{
#endif
extern int wrapper();
#ifdef __cplusplus
}
#endif
The main.cpp that uses all the libs looks like
#include <iostream>
#include <string>
#include "shared-lib.h"
#include "wrapper-lib.h"
using namespace std;
int main()
{
auto s = "Hello world from main";
cout << s << endl;
foo(); // from c++ lib
int result = wrapper(); // from c wrapper lib
cout << "wrapper returned " << result << endl;
return 0;
}
My test built script is
g++-6 --version
echo -----------------------
echo build shared-lib .o with g++
g++-6 -c -Wall -fpic -std=c++11 shared-lib.cpp
echo build a wrapper library in C with gcc
gcc-6 -c -Wall -fpic wrapper-lib.c
echo build static libshared-lib.a
ar rcs libshared-lib.a shared-lib.o
echo build static libwrapper-lib.a
ar rcs libwrapper-lib.a wrapper-lib.o
echo build main with clang
clang++ --version
echo ----------------------
clang++ -v -L/Users/worker -Wall -std=c++11 -stdlib=libstdc++ -lwrapper-lib -lshared-lib main.cpp -o main
echo start the app
./main
If I only call the gcc c++ function foo() then everything works fine.
If I call the C wrapper function wrapper(), then clang comes up with:
Undefined symbols for architecture x86_64:
"_foo", referenced from:
_wrapper in libwrapper-lib.a(wrapper-lib.o)
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Maybe someone can simply spot, what's wrong with my workflow?
Note, for completeness the whole build script output
Note2, since ar in the gcc#6 toolchain does not work (liblto_plugin.so missing) I use clang's ar tool...
mac-mini:~ worker$ ./build-test.sh
g++-6 (Homebrew GCC 6.4.0) 6.4.0
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-----------------------
build shared-lib .o with g++
build a wrapper library in C with gcc
build static libshared-lib.a
build static libwrapper-lib.a
build main with clang
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 8.1.0 (clang-802.0.41)
Target: x86_64-apple-darwin16.7.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
----------------------
Apple LLVM version 8.1.0 (clang-802.0.41)
Target: x86_64-apple-darwin16.7.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
clang: warning: libstdc++ is deprecated; move to libc++ [-Wdeprecated]
"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang" -cc1 -triple x86_64-apple-macosx10.12.0 -Wdeprecated-objc-isa-usage -Werror=deprecated-objc-isa-usage -emit-obj -mrelax-all -disable-free -disable-llvm-verifier -discard-value-names -main-file-name main.cpp -mrelocation-model pic -pic-level 2 -mthread-model posix -mdisable-fp-elim -masm-verbose -munwind-tables -target-cpu penryn -target-linker-version 278.4 -v -dwarf-column-info -debugger-tuning=lldb -resource-dir /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/clang/8.1.0 -stdlib=libstdc++ -Wall -std=c++11 -fdeprecated-macro -fdebug-compilation-dir /Users/worker -ferror-limit 19 -fmessage-length 166 -stack-protector 1 -fblocks -fobjc-runtime=macosx-10.12.0 -fencode-extended-block-signature -fcxx-exceptions -fexceptions -fmax-type-align=16 -fdiagnostics-show-option -fcolor-diagnostics -o /var/folders/18/m18t0kxx03d7__31kg3wrsr40000gq/T/main-337db7.o -x c++ main.cpp
clang -cc1 version 8.1.0 (clang-802.0.41) default target x86_64-apple-darwin16.7.0
ignoring nonexistent directory "/usr/include/c++/4.2.1/i686-apple-darwin10/x86_64"
ignoring nonexistent directory "/usr/include/c++/4.0.0"
ignoring nonexistent directory "/usr/include/c++/4.0.0/i686-apple-darwin8/"
ignoring nonexistent directory "/usr/include/c++/4.0.0/backward"
#include "..." search starts here:
#include <...> search starts here:
/usr/include/c++/4.2.1
/usr/include/c++/4.2.1/backward
/usr/local/include
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/clang/8.1.0/include
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include
/usr/include
/System/Library/Frameworks (framework directory)
/Library/Frameworks (framework directory)
End of search list.
"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld" -demangle -lto_library /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/libLTO.dylib -no_deduplicate -dynamic -arch x86_64 -macosx_version_min 10.12.0 -o main -L/Users/worker -lwrapper-lib -lshared-lib /var/folders/18/m18t0kxx03d7__31kg3wrsr40000gq/T/main-337db7.o -lstdc++ -lSystem /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/clang/8.1.0/lib/darwin/libclang_rt.osx.a
Undefined symbols for architecture x86_64:
"_foo", referenced from:
_wrapper in libwrapper-lib.a(wrapper-lib.o)
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
You compile shared-lib.cpp with:
g++-6 -c -Wall -fpic -std=c++11 shared-lib.cpp
And you compile wrapper-lib.c with:
gcc-6 -c -Wall -fpic wrapper-lib.c
Have a look at the symbol table of shared-lib.o. It's something like:
$ readelf -s shared-lib.o
Symbol table '.symtab' contains 24 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FILE LOCAL DEFAULT ABS shared-lib.cpp
2: 0000000000000000 0 SECTION LOCAL DEFAULT 1
3: 0000000000000000 0 SECTION LOCAL DEFAULT 3
4: 0000000000000000 0 SECTION LOCAL DEFAULT 4
5: 0000000000000000 0 SECTION LOCAL DEFAULT 5
6: 0000000000000000 1 OBJECT LOCAL DEFAULT 5 _ZStL19piecewise_construc
7: 0000000000000000 1 OBJECT LOCAL DEFAULT 4 _ZStL8__ioinit
8: 0000000000000032 73 FUNC LOCAL DEFAULT 1 _Z41__static_initializati
9: 000000000000007b 21 FUNC LOCAL DEFAULT 1 _GLOBAL__sub_I_shared_lib
10: 0000000000000000 0 SECTION LOCAL DEFAULT 6
11: 0000000000000000 0 SECTION LOCAL DEFAULT 9
12: 0000000000000000 0 SECTION LOCAL DEFAULT 10
13: 0000000000000000 0 SECTION LOCAL DEFAULT 8
14: 0000000000000000 50 FUNC GLOBAL DEFAULT 1 _Z3foov
15: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND _GLOBAL_OFFSET_TABLE_
16: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND _ZSt4cerr
17: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND _ZStlsISt11char_traitsIcE
18: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND _ZSt4endlIcSt11char_trait
19: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND _ZNSolsEPFRSoS_E
20: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND _ZNSt8ios_base4InitC1Ev
21: 0000000000000000 0 NOTYPE GLOBAL HIDDEN UND __dso_handle
22: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND _ZNSt8ios_base4InitD1Ev
23: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND __cxa_atexit
(I'm working on Ubuntu, not OS X.)
Note that there is only one global function defined in this object file and
its name is _Z3foov.
That's the mangled name of the C++ function called foo in shared-lib.cpp. That's
the name the linker sees.
Now the symbol table of wrapper-lib.o:
Symbol table '.symtab' contains 11 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FILE LOCAL DEFAULT ABS wrapper-lib.c
2: 0000000000000000 0 SECTION LOCAL DEFAULT 1
3: 0000000000000000 0 SECTION LOCAL DEFAULT 3
4: 0000000000000000 0 SECTION LOCAL DEFAULT 4
5: 0000000000000000 0 SECTION LOCAL DEFAULT 6
6: 0000000000000000 0 SECTION LOCAL DEFAULT 7
7: 0000000000000000 0 SECTION LOCAL DEFAULT 5
8: 0000000000000000 21 FUNC GLOBAL DEFAULT 1 wrapper
9: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND _GLOBAL_OFFSET_TABLE_
10: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND foo
This object file makes an undefined reference to foo, because wrapper-lib.c
is a C source file and you compiled it as such. C does not mangle names. No definition
of foo is provided by any object file in your linkage, so it fails with that
symbol unresolved.
To avoid this and accomplish your linkage, you can direct the C++ compiler
not to mangle the name foo, when compiling shared-lib.cpp. You do so like:
shared-lib.cpp
#include <iostream>
using namespace std;
extern "C" {
void foo()
{
cerr << "Hi from the shared lib" << endl;
}
} //extern "C"
Enclosing the definition of foo in extern "C" {...} has no effect on
C++ compilation except the one you want: the symbol foo will be emitted
as a C symbol; not mangled.
Having done that, you must of course follow suit in shared-lib.h:
shared-lib.h
#ifndef SHARED_LIB_H
#define SHARED_LIB_H
#ifdef __cplusplus
extern "C" {
#endif
void foo();
#ifdef __cplusplus
}
#endif
#endif
With those corrections, let's try again:
$ g++-6 -c -Wall -fpic -std=c++11 shared-lib.cpp
and check the symbol table:
$ readelf -s shared-lib.o | grep foo
14: 0000000000000000 50 FUNC GLOBAL DEFAULT 1 foo
Now the one global function defined is foo, not _Z3foov, and your
linkage will succeed.
If you want to write a C++ library that exports a C++ API and not a C API to
the linker, then you cannot call its API from C except by discovering the
mangled names of the API (with readelf, nm, objdump) and explicitly
calling those mangled names from C. Thus without those extern "C" fixes,
your linkage would also succeed with:
wrapper-lib.c
extern void _Z3foov(void);
int wrapper()
{
_Z3foov();
return 123;
}
I've been writing C for 2-3 years and recently picked up assembly but as I use Windows I've never needed to use make files before as I've just used Visual Studio. I'm trying to use Cygwin and an i686 cross compiler to compile c and assembly files, and then link them together into a binary file representing my operating system. I am new to make files so I don't know how to do this properly. This is what I've got so far for the Makefile:
CC = i686-elf-gcc
CC_FLAGS = -c -std=gnu99 -ffreestanding -O2 -Wall -Wextra -I./include
AS = i686-elf-as
LD = i686-elf-gcc -T linker.ld -o myos.bin
LD_FLAGS = -ffreestanding -O2 -nostdlib -lgcc
O_FILES = $(wildcard src/*.o)
all: $(O_FILES)
$(LD) $(LD_FLAGS) $(O_FILES)
src/%.o: src/%.c
$(CC) $(CC_FLAGS) -o $# $<
src/%.o: src/%.asm
$(AS) -o $# $<
I'm getting an error stating that the linker can't find the entry symbol _start so obviously nothing is compiling. How would I fix this?
My src/linker.ld file that defines _start as the entry point is:
ENTRY(_start)
SECTIONS
{
. = 1M;
.text BLOCK(4K) : ALIGN(4K)
{
*(.multiboot)
*(.text)
}
.rodata BLOCK(4K) : ALIGN(4K)
{
*(.rodata)
}
.data BLOCK(4K) : ALIGN(4K)
{
*(.data)
}
.bss BLOCK(4K) : ALIGN(4K)
{
*(COMMON)
*(.bss)
}
}
The src/boot.asmfile I'm using that defines my _start label is:
# Declare constants for the multiboot header.
.set ALIGN, 1<<0 # align loaded modules on page boundaries
.set MEMINFO, 1<<1 # provide memory map
.set FLAGS, ALIGN | MEMINFO # this is the Multiboot 'flag' field
.set MAGIC, 0x1BADB002 # 'magic number' lets bootloader find the header
.set CHECKSUM, -(MAGIC + FLAGS) # checksum of above, to prove we are multiboot
.section .multiboot
.align 4
.long MAGIC
.long FLAGS
.long CHECKSUM
.section .bss
.align 16
stack_bottom:
.skip 16384 # 16 KiB
stack_top:
.section .text
.global _start
.type _start, #function
_start:
mov $stack_top, %esp
call kernel_main
cli
1: hlt
jmp 1b
.size _start, . - _start
You will need to modify your Makefile to something like this:
CC = i686-elf-gcc
AS = i686-elf-as
LD = i686-elf-gcc
AS_FLAGS =
LD_FLAGS = -ffreestanding -nostdlib -lgcc -Tlinker.ld
CC_FLAGS = -c -std=gnu99 -ffreestanding -O2 -Wall -Wextra -I./include
C_FILES := $(wildcard src/*.c)
ASM_FILES := $(wildcard src/*.asm)
O_FILES := $(C_FILES:.c=.o) $(ASM_FILES:.asm=.o)
KERNEL_BIN := myos.bin
all: $(KERNEL_BIN)
clean:
rm -f $(KERNEL_BIN) $(O_FILES)
$(KERNEL_BIN): $(O_FILES)
$(LD) $(LD_FLAGS) -o $# $^
%.o: %.c
$(CC) $(CC_FLAGS) -o $# $<
%.o: %.asm
$(AS) $(AS_FLAGS) -o $# $<
This Makefile is different in that we construct a list of ASM files and C files. I also cleaned up the LD_FLAGS a bit and added an extra rule to create myos.bin and to clean the object and bin files.
In your current code you'd have the Makefile variables with this in them after expansion:
C_FILES = src/string.c src/tty.c src/kernel.c
ASM_FILES = src/boot.asm
O_FILES = src/string.o src/tty.o src/kernel.o src/boot.o
O_FILES was derived from concatenating both file lists together and replacing the .c and .asm extensions with .o. This is the list of all the objects that need to be generated from their source files.
With GNU Assembler it is customary to use files with .s extensions (or .S if you want to use the C preprocessor) rather than .asm
The reason the _start label wasn't found is because the assembly files were not being processed. This means that boot.asm was not becoming boot.o and thus wasn't being linked at all.