Skip to content

Instantly share code, notes, and snippets.

@nominolo
Created May 9, 2012 12:49
Show Gist options
  • Save nominolo/2644270 to your computer and use it in GitHub Desktop.
Save nominolo/2644270 to your computer and use it in GitHub Desktop.
Clang Ubuntu compilation error.
#include <stdio.h>
#include <stdint.h>
/*
This file tests a direct-threaded interpreter with the ability to
switch the mode (by modifying the dispatch table).
It uses one non-standard feature supported by GCC and Clang on Darwin,
namely "Labels as Values" (the syntax "&&label_name").
It compiles fine in GCC and Clang for Mac, but fails on Ubuntu's Clang with
duplicated labels:
/tmp/cc-wUdEEL.s: Assembler messages:
/tmp/cc-wUdEEL.s:46: Error: symbol `.LBA11_interp_send_' is already defined
/tmp/cc-wUdEEL.s:54: Error: symbol `.LBA11_interp_send_' is already defined
clang: error: assembler command failed with exit code 1 (use -v to see invocation)
Clang Ubuntu version:
$ clang --version
clang version 1.1 (branches/release_27)
Target: x86_64-pc-linux-gnu
Thread model: posix
Clang Mac version:
$ clang --version
Apple clang version 2.0 (tags/Apple/clang-139) (based on LLVM 2.9svn)
Target: x86_64-apple-darwin10
Thread model: posix
It works fine with GCC (both Mac and Ubuntu) and llvm-gcc on Ubuntu.
$ llvm-gcc --version
llvm-gcc (GCC) 4.2.1 (Based on Apple Inc. build 5658) (LLVM build)
Copyright (C) 2007 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.
$ gcc --version
gcc (Ubuntu 4.4.3-4ubuntu5.1) 4.4.3
Copyright (C) 2009 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.
*/
typedef void *Impl;
typedef enum {
OP_STOP,
OP_BEEP,
OP_MOO,
OP__MAX
} Opcode;
typedef uint8_t Instr;
typedef struct _VM {
Impl dispatch[OP__MAX];
int *sp;
Instr *pc;
} VM;
Impl dispatch[OP__MAX];
typedef enum {
IM_INIT_DISPATCH,
IM_RUN,
IM_TOGGLE,
} InterpMessage;
void interp_send(InterpMessage msg, VM *vm) {
int *sp;
Instr *pc;
Impl *dispatch = &vm->dispatch[0];
static const Impl default_dispatch[OP__MAX] = {
&&op_stop, &&op_beep, &&op_moo
};
switch (msg) {
case IM_INIT_DISPATCH:
{
int opc;
for (opc = 0; opc < OP__MAX; opc++) {
dispatch[opc] = default_dispatch[opc];
}
return;
}
case IM_TOGGLE:
{
Impl tmp = dispatch[OP_BEEP];
dispatch[OP_BEEP] = dispatch[OP_MOO];
dispatch[OP_MOO] = tmp;
return;
}
default:
sp = vm->sp;
pc = vm->pc;
}
#define DISPATCH_NEXT goto *dispatch[*pc++]
/* Dispatch first instruction. */
DISPATCH_NEXT;
op_stop:
vm->sp = sp;
vm->pc = pc;
/* dispatch pointer itself never changes */
return;
op_beep:
printf("beep!\n");
DISPATCH_NEXT;
op_moo:
printf("moo!\n");
DISPATCH_NEXT;
/* Unreachable */
}
inline void initInterp(VM *vm) { interp_send(IM_INIT_DISPATCH, vm); }
inline void runInterp(VM *vm) { interp_send(IM_RUN, vm); }
inline void toggleInterpMode(VM *vm) { interp_send(IM_TOGGLE, vm); }
int main(int argc, char *argv[]) {
Instr code[] = { OP_BEEP, OP_BEEP, OP_STOP };
VM vm;
vm.pc = &code[0];
vm.sp = NULL;
initInterp(&vm);
runInterp(&vm); /* Should print: beep, beep */
toggleInterpMode(&vm); /* Should print: moo, moo */
vm.pc = &code[0];
runInterp(&vm);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment