Cmake compile __asm assembly inline code - c

I am trying to compile quake2 code which uses the __asm keyword like so:
__declspec( naked ) int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs,
struct cplane_s *p)
{
static int bops_initialized;
static int Ljmptab[8];
__asm {
push ebx
cmp bops_initialized, 1
je initialized
mov bops_initialized, 1
// more code...
I am using Clion which uses Cmake internally to compile. The thing is that in the code above I get the following errors
C:\Users\Shiro\ClionProjects\quake2\src\game\q_shared.c: In function
'BoxOnPlaneSide':
C:\Users\Shiro\ClionProjects\quake2\src\game\q_shared.c:423:8: error:
expected '(' before '{' token
__asm {
^
and the errors go on from there. So, how can I make this compile ? any changes to my CMakeLists.txt perhaps ? Here is part of what I have now
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Traditional -std=gnu89")

Related

Undefined symbol error when trying to mov into variable which defined in C code above assembly

I am trying to run assembly code inside C code(on CLion). I defined variable x outside of assembly insert and tried to mov a number into it but compiler says x is undefined. I don't get how to make it see variables. Also I have to use intel syntax.
int main(int argc, char** argv) {
short int x = 0;
__asm__ (
".intel_syntax noprefix\n\t"
"mov eax, 0x02\n\t"
"mov x, eax\n\t"
".att_syntax prefix\n\t"
);
printf("%d", x);
}
And there is error
[ 50%] Building CXX object CMakeFiles/ass_lab_2.dir/main.cpp.o
[100%] Linking CXX executable ass_lab_2
/usr/bin/ld: CMakeFiles/ass_lab_2.dir/main.cpp.o: relocation R_X86_64_32S against undefined symbol `x' can not be used when making a PIE object; recompile with -fPIC
/usr/bin/ld: final link failed: Nonrepresentable section on output
collect2: error: ld returned 1 exit status
...
P.S. I solved problem. This link was extremely helpful. You just need to pass your variables into asm function using it's syntax.
(Editor's note: the first couple pages of that, about using GNU C Basic asm statements to modify global variables, are unsafe (because there's no "memory" clobber) and only happen to work. The only safe way to modify C variables is with Extended asm with input/output operands; later sections of that article cover that.)
Your main issue is that x is a local variable. You will have to use extended assembly to modify it (and use -masm=intel to use Intel syntax):
int main(void)
{
short int x = 0;
__asm__("mov %0, 0x02\n\t" : "=r"(x));
printf("%d", x);
}
Also, you can use AT&T syntax. It will look like this:
int main(void)
{
short int x = 0;
__asm__("mov $0x02, %0\n\t" : "=r"(x));
printf("%d", x);
}
Because I'm using the =r constraint here, this will be stored in a register; therefore, you don't need to use eax (which should be ax, by the way) as an intermediate storage place to store the value.

How to compile C functions that start with __asm in arm-none-eabi?

I'm trying to compile this PTPD code https://github.com/mpthompson/stm32_f4_ptpd . Unfortunately, it requires premium version of Keil. Therefore, I am migrating it to use arm-none-eabi and Makefile.
I have managed to get the rest of the program to compile, except for https://github.com/mpthompson/stm32_f4_ptpd/blob/master/libraries/RTX-v4.73/SRC/ARM/HAL_CM4.c .
Example problem place:
__asm void rt_set_PSP (U32 stack) {
MSR PSP,R0
BX LR
}
This file fails with:
../libraries/rtx-v4.73/SRC/ARM/HAL_CM4.c:50:7: error: expected '(' before 'void'
__asm void rt_set_PSP (U32 stack) {
^~~~
../libraries/rtx-v4.73/SRC/ARM/HAL_CM4.c:72:20: error: stray '#' in program
LSLS R0,#31
It seems like it is related to the compiler (GNU compiler not supporting this syntax?) or some flags, but googling hasn't been fertile so far.

Clang integrated assembler and “unknown token in expression” during negate

We are using Clang in a default configuration. In the default configuration, Clang's Integrated Assembler is used (and not the system assembler, like GAS). I'm having trouble determining the exact problem (and fix) for:
make
...
clang++ -DNDEBUG -g2 -O3 -Wall -fPIC -arch i386 -arch x86_64 -pipe -Wno-tautological-compare -c integer.cpp
integer.cpp:542:2: error: unknown token in expression
AS1( neg %1)
^
./cpu.h:220:17: note: expanded from macro 'AS1'
#define AS1(x) GNU_AS1(x)
^
./cpu.h:215:24: note: expanded from macro 'GNU_AS1'
#define GNU_AS1(x) "\n\t" #x ";"
^
<inline asm>:3:6: note: instantiated into assembly here
neg %rcx;
^
The code in question is below.
I think the error above may be related to Inline Assembly and Compatibility. A simple negq %1 did not work as expected:
integer.cpp:543:2: error: unknown token in expression
AS1( negq %1)
^
./cpu.h:220:17: note: expanded from macro 'AS1'
#define AS1(x) GNU_AS1(x)
^
./cpu.h:215:24: note: expanded from macro 'GNU_AS1'
#define GNU_AS1(x) "\n\t" #x ";"
^
<inline asm>:3:7: note: instantiated into assembly here
negq %rcx;
^
Since its Intel assembly, I also tried negq [%1], neg DWORD PTR [%1] and negq DWORD PTR [%1] with no joy.
“unknown token in expression” appears to be a bogus message since the assembly instruction its complaining about does not seem to have a problem. So I suspect there is something else the Clang integrated assembler finds offensive.
What is the problem with the code?
Code causing the compile error:
int Baseline_Add(size_t N, word *C, const word *A, const word *B)
{
word result;
__asm__ __volatile__
(
".intel_syntax;" "\n"
AS1( neg %1)
ASJ( jz, 1, f)
AS2( mov %0,[%3+8*%1])
AS2( add %0,[%4+8*%1])
AS2( mov [%2+8*%1],%0)
ASL(0)
AS2( mov %0,[%3+8*%1+8])
AS2( adc %0,[%4+8*%1+8])
AS2( mov [%2+8*%1+8],%0)
AS2( lea %1,[%1+2])
ASJ( jrcxz, 1, f)
AS2( mov %0,[%3+8*%1])
AS2( adc %0,[%4+8*%1])
AS2( mov [%2+8*%1],%0)
ASJ( jmp, 0, b)
ASL(1)
AS2( mov %0, 0)
AS2( adc %0, %0)
".att_syntax;" "\n"
: "=&r" (result), "+c" (N)
: "r" (C+N), "r" (A+N), "r" (B+N)
: "memory", "cc"
);
return (int)result;
}
This appears to be an issue in the Integrated Assembler. One of the LLVM developers opened a PR after the question was asked on the CFE-dev mailing list. Also see LLVM Bug 24232 - [X86] Inline assembly operands don't work with .intel_syntax.
I think that means Michael's comment could be a solution if we had the time and energy to rewrite blocks with 1000's of lines.

how to call assembly program inside c program- Visual studio 2010

I need to call inline asm function in my c program "mainFunction.c"
#include<stdio.h>
#include<math.h>
double inline __declspec (naked) __fastcall sqrt14(double n)
{
_asm fld qword ptr [esp+4]
_asm fsqrt
_asm ret 8
}
int main(){
double a=10.5;
double b;
b=sqrt14(a);
return 0;
}
When I compile this program I am getting syntax errors.
error C2143: syntax error : missing ';' before '{'
error C2085: 'sqrt14' : not in formal parameter list
error C2054: expected '(' to follow 'inline'
if I change the file name to "mainFunction.cpp" means the program works fine.
You didn't specify which errors you got, but the function definition seems a little suspicious. See - http://msdn.microsoft.com/en-us/library/h5w10wxs.aspx
The compiler cannot generate an inline function for a function marked with the naked attribute, even if the function is also marked with the __forceinline keyword.
It also doesn't make a lot of sense to try stripping a function that's going to be inlined anyway, inlining already does most of the job for you.

Can I use Intel syntax of x86 assembly with GCC?

I want to write a small low level program. For some parts of it I will need to use assembly language, but the rest of the code will be written on C/C++.
So, if I will use GCC to mix C/C++ with assembly code, do I need to use AT&T syntax or can
I use Intel syntax? Or how do you mix C/C++ and asm (intel syntax) in some other way?
I realize that maybe I don't have a choice and must use AT&T syntax, but I want to be sure..
And if there turns out to be no choice, where I can find full/official documentation about the AT&T syntax?
Thanks!
If you are using separate assembly files, gas has a directive to support Intel syntax:
.intel_syntax noprefix # not recommended for inline asm
which uses Intel syntax and doesn't need the % prefix before register names.
(You can also run as with -msyntax=intel -mnaked-reg to have that as the default instead of att, in case you don't want to put .intel_syntax noprefix at the top of your files.)
Inline asm: compile with -masm=intel
For inline assembly, you can compile your C/C++ sources with gcc -masm=intel (See How to set gcc to use intel syntax permanently? for details.) The compiler's own asm output (which the inline asm is inserted into) will use Intel syntax, and it will substitute operands into asm template strings using Intel syntax like [rdi + 8] instead of 8(%rdi).
This works with GCC itself and ICC, but for clang only clang 14 and later.
(Not released yet, but the patch is in current trunk.)
Using .intel_syntax noprefix at the start of inline asm, and switching back with .att_syntax can work, but will break if you use any m constraints. The memory reference will still be generated in AT&T syntax. It happens to work for registers because GAS accepts %eax as a register name even in intel-noprefix mode.
Using .att_syntax at the end of an asm() statement will also break compilation with -masm=intel; in that case GCC's own asm after (and before) your template will be in Intel syntax. (Clang doesn't have that "problem"; each asm template string is local, unlike GCC where the template string truly becomes part of the text file that GCC sends to as to be assembled separately.)
Related:
GCC manual: asm dialect alternatives: writing an asm statement with {att | intel} in the template so it works when compiled with -masm=att or -masm=intel. See an example using lock cmpxchg.
https://stackoverflow.com/tags/inline-assembly/info for more about inline assembly in general; it's important to make sure you're accurately describing your asm to the compiler, so it knows what registers and memory are read / written.
AT&T syntax: https://stackoverflow.com/tags/att/info
Intel syntax: https://stackoverflow.com/tags/intel-syntax/info
The x86 tag wiki has links to manuals, optimization guides, and tutorials.
You can use inline assembly with -masm=intel as ninjalj wrote, but it may cause errors when you include C/C++ headers using inline assembly. This is code to reproduce the errors on Cygwin.
sample.cpp:
#include <cstdint>
#include <iostream>
#include <boost/thread/future.hpp>
int main(int argc, char* argv[]) {
using Value = uint32_t;
Value value = 0;
asm volatile (
"mov %0, 1\n\t" // Intel syntax
// "movl $1, %0\n\t" // AT&T syntax
:"=r"(value)::);
auto expr = [](void) -> Value { return 20; };
boost::unique_future<Value> func { boost::async(boost::launch::async, expr) };
std::cout << (value + func.get());
return 0;
}
When I built this code, I got error messages below.
g++ -E -std=c++11 -Wall -o sample.s sample.cpp
g++ -std=c++11 -Wall -masm=intel -o sample sample.cpp -lboost_system -lboost_thread
/tmp/ccuw1Qz5.s: Assembler messages:
/tmp/ccuw1Qz5.s:1022: Error: operand size mismatch for `xadd'
/tmp/ccuw1Qz5.s:1049: Error: no such instruction: `incl DWORD PTR [rax]'
/tmp/ccuw1Qz5.s:1075: Error: no such instruction: `movl DWORD PTR [rcx],%eax'
/tmp/ccuw1Qz5.s:1079: Error: no such instruction: `movl %eax,edx'
/tmp/ccuw1Qz5.s:1080: Error: no such instruction: `incl edx'
/tmp/ccuw1Qz5.s:1082: Error: no such instruction: `cmpxchgl edx,DWORD PTR [rcx]'
To avoid these errors, it needs to separate inline assembly (the upper half of the code) from C/C++ code which requires boost::future and the like (the lower half). The -masm=intel option is used to compile .cpp files that contain Intel syntax inline assembly, not to other .cpp files.
sample.hpp:
#include <cstdint>
using Value = uint32_t;
extern Value GetValue(void);
sample1.cpp: compile with -masm=intel
#include <iostream>
#include "sample.hpp"
int main(int argc, char* argv[]) {
Value value = 0;
asm volatile (
"mov %0, 1\n\t" // Intel syntax
:"=r"(value)::);
std::cout << (value + GetValue());
return 0;
}
sample2.cpp: compile without -masm=intel
#include <boost/thread/future.hpp>
#include "sample.hpp"
Value GetValue(void) {
auto expr = [](void) -> Value { return 20; };
boost::unique_future<Value> func { boost::async(boost::launch::async, expr) };
return func.get();
}

Resources