program:
#include <stdio.h>
#include <sstream>
int main()
{
std::stringstream ss;
ss << "hello world " << 1234 << "\n";
std::string str = ss.str();
printf(str.c_str());
return 0;
}
makefile:
CC=/usr/local/gcc-4.6.2/bin/g++
CFLAGS=-g -c -W -m32 -Wa,-mtune=pentiumiii
LINKFLAGS=-m32 -static-libgcc -static-libstdc++ -Wl,-rpath,./runtime,--dynamic-linker,./runtime/ld-linux.so.2
all:test
test: list_test.o
$(CC) $(LINKFLAGS) list_test.o -o test
list_test.o: list_test.cpp
$(CC) $(CFLAGS) list_test.cpp
clean:
rm *.o ./test -f
I build it in 64-bit linux. there is an illegal instruction when it run in 32-bit linux with pentinum(R) III cpu.
the illegal instruction is as follow:
(gdb) disas 0x0804f77a 0x0804f77b
Dump of assembler code from 0x804f77a to 0x804f77b:
0x0804f77a <std::basic_stringbuf<char, std::char_traits<char>, std::allocator<char> >::_M_sync(std::basic_stringbuf<char, std::char_traits<char>, std::allocator<char> >::char_type*, std::basic_stringbuf<char, std::char_traits<char>, std::allocator<char> >::__size_type, std::basic_stringbuf<char, std::char_traits<char>, std::allocator<char> >::__size_type)+138>: movq %xmm0,0xc(%esp)
End of assembler dump.
How to resolve this problem?
The instruction movq %xmm0,0xc(%esp) is part of the Streaming SIMD Extensions (SSE) instruction set. The Pentium III in theory supports SSE, but the processor you're trying to run it in apparently doesn't. You can disable the generation of SSE instructions on GCC with the -mno-sse compiler option. You can also try -march=pentium3 to generate code compatible with Pentium III and above.
Also, your printf call has a bug—you should (almost) never pass a non-constant string as the format argument (the first argument). If that string happens to contain any % signs in it, that will lead to undefined behavior. At best, this will crash, and at worst, you could have a silent security vulnerability. The fix is to do this:
printf("%s", str.c_str());
Or better yet, avoid the potential problems with the printf family of functions entirely, since you're using C++:
std::cout << str; // Optionally also do `<< std::flush'
It looks like a SSE instruction, which is apparently not supported by the processor. (Pentium 3 is supposed to support SSE though).
You can try compiling your code with -mno-sse and see if it helps.
Related
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.
In my open source software project, I call the gcc atomic builtins: __sync_add_and_fetch and __sync_sub_and_fetch to implement atomic increments and decrements on certain variables. I periodically get an email from someone trying to compile my code, but they get the following linker error:
refcountobject.cpp:(.text+0xb5): undefined reference to `__sync_sub_and_fetch_4'
refcountobject.cpp:(.text+0x115): undefined reference to `__sync_add_and_fetch_4'
After some digging, I narrowed down the root cause to the fact that their older version of gcc (4.1) defaults to a target architecture of i386. And evidently, gcc doesn't actually have an intrinsic for atomic addition on 80386, so it implicitly injects an undefined __sync_add_and_fetch_4 call in it place. A great description of how this works is here.
The easy workaround, as discussed here, is to tell them to modify the Makefile to append -march=pentium as one of the compiler flags. And all is good.
So what's the long term fix so users don't have to manually fix the Makefile?
I am considering a few ideas:
I don't want to hardcode -march=pentium as a compiler flag into the Makefile. I'm guessing that will break on anything that isn't Intel based. But I could certainly could add it if the Makefile had a rule to detect that the default target was i386. I'm thinking about having a rule in the Makefile that is a script that calls gcc -dumpmachine and parses out the first triplet. If the string is i386, it would add the compiler flag. I'm assuming no one will be actually be building for 80386 machines.
The other alternative is to actually supply an implementation for __sync_add_and_fetch_4 for the linker to fall back on. It could even be compiled conditionally based on the presence of GCC_HAVE_SYNC_COMPARE_AND_SWAP macros being defined. I prototyped an implementation with a global pthread_mutex. Likely not the best performance, but it works and resolves the issue nicely. A better idea might be to write the inline assembly myself to call "lock xadd" for the implementation if compiling for x86.
This is my other working solution. It might have it's place in certain situations, but I opted for the makefile+script solution above.
This solution is to provide local definitions for _sync_add_and_fetch_4, _sync_fetch_and_add_4, _sync_sub_and_fetch_4, and _sync_fetch_and_sub_4 in a separate source file. They get linked in only if the compiler couldn't natively generate them. Some assembly required, but Wikipedia of all places had a reasonable implementation that I could reference. (I also disassembled what the compiler normally generates to infer if everything else was correct).
#if defined(__i386) || defined(i386) || defined(__i386__)
extern "C" unsigned int xadd_4(volatile void* pVal, unsigned int inc)
{
unsigned int result;
unsigned int* pValInt = (unsigned int*)pVal;
asm volatile(
"lock; xaddl %%eax, %2;"
:"=a" (result)
: "a" (inc), "m" (*pValInt)
:"memory" );
return (result);
}
extern "C" unsigned int __sync_add_and_fetch_4(volatile void* pVal, unsigned int inc)
{
return (xadd_4(pVal, inc) + inc);
}
extern "C" unsigned int __sync_sub_and_fetch_4(volatile void* pVal, unsigned int inc)
{
return (xadd_4(pVal, -inc) - inc);
}
extern "C" unsigned int __sync_fetch_and_add_4(volatile void* pVal, unsigned int inc)
{
return xadd_4(pVal, inc);
}
extern "C" unsigned int __sync_fetch_and_sub_4(volatile void* pVal, unsigned int inc)
{
return xadd_4(pVal, -inc);
}
#endif
With no replies, I struck it out on my own to solve.
There are two possible solutions this is one of them.
First, add the following script, getfixupflags.sh, to the same directory as the Makefile. This script will detect if the compiler is likely targeting i386, and if so will echo out "-march=pentium" as output.
#!/bin/bash
_cxx=$1
_fixupflags=
_regex_i386='^i386'
if [[ ! -n $_cxx ]]; then echo "_cxx var is empty - exiting" >&2; exit; fi
_target=`$_cxx -dumpmachine`
if [[ $_target =~ $_regex_i386 ]]; then
_fixupflags="$_fixupflags -march=pentium"
fi
if [[ -n $_fixupflags ]]; then echo $_fixupflags; fi
Now fix the Makefile to use this script. Add the following line to the Makefile
FIXUP_FLAGS := $(shell getfixupflags.sh $(CXX))
Then modify the compiler directives in the Makefile to include the FIXUP_FLAGS when compiling code. For example:
%.o: %.cpp
$(COMPILE.cpp) $(FIXUP_FLAGS) $^
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.
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
I am building a 16 bit operating system. But character array does not seem to work.
Here is my example kernel code:
asm(".code16gcc\n");
void putchar(char);
int main()
{
char *str = "hello";
putchar('A');
if(str[0]== 'h')
putchar('h');
return 0;
}
void putchar(char val)
{
asm("movb %0, %%al\n"
"movb $0x0E, %%ah\n"
"int $0x10\n"
:
:"m"(val)
) ;
}
It prints:
A
that means putchar function is working properly but
if(str[0]== 'h')
putchar('h');
is not working.
I am compiling it by:
gcc -fno-toplevel-reorder -nostdinc -fno-builtin -I./include -c -o ./bin/kernel.o ./source/kernel.c
ld -Ttext=0x9000 -o ./bin/kernel.bin ./bin/kernel.o -e 0x0
What should I do?
Your data segment is probably not loaded in to the target. What are you doing after the link with your brand new kernel.bin file, which is in fact an elf file ?