Skip to content

Commit

Permalink
Merge pull request #1761 from guwirth/asm-label
Browse files Browse the repository at this point in the history
improve inline assembler support for VC & GCC
  • Loading branch information
guwirth committed Sep 2, 2019
2 parents 0417d08 + 3a3c588 commit c66c820
Show file tree
Hide file tree
Showing 6 changed files with 151 additions and 12 deletions.
23 changes: 17 additions & 6 deletions cxx-squid/src/main/java/org/sonar/cxx/parser/CxxGrammarImpl.java
Expand Up @@ -173,6 +173,7 @@ public enum CxxGrammarImpl implements GrammarRuleKey {
usingDeclarator,
usingDirective,
asmDefinition,
asmLabel,
linkageSpecification,
attributeSpecifierSeq,
attributeSpecifier,
Expand Down Expand Up @@ -1227,16 +1228,26 @@ private static void declarations(LexerfulGrammarBuilder b) {
b.rule(usingDirective).is(
b.optional(attributeSpecifierSeq), CxxKeyword.USING, CxxKeyword.NAMESPACE, b.optional(nestedNameSpecifier), namespaceName, ";" // C++
);

b.rule(asmDefinition).is(
CxxKeyword.ASM,
b.firstOf(
b.sequence("(", STRING, ")", ";"), // C++
b.sequence("{", b.oneOrMore(b.nextNot(b.firstOf("}", EOF)), b.anyToken()), "}", b.optional(";")), // VS
b.sequence(b.oneOrMore(b.nextNot(b.firstOf(";", EOF)), b.anyToken()), ";") // VS
b.sequence(
b.firstOf(CxxKeyword.ASM, "__asm__"), // C++ asm; GCC: __asm__
b.optional(b.firstOf(CxxKeyword.VIRTUAL, CxxKeyword.INLINE, "__virtual__")), // GCC asm qualifiers
"(", STRING, ")", ";"
),
b.sequence(b.firstOf("__asm", CxxKeyword.ASM), b.firstOf( // VS
b.sequence("{", b.oneOrMore(b.nextNot(b.firstOf("}", EOF)), b.anyToken()), "}", b.optional(";")), // VS __asm block
b.sequence(b.oneOrMore(b.nextNot(b.firstOf(";", EOF)), b.anyToken()), ";") // VS __asm ... ;
)
)
)
);

b.rule(asmLabel).is(
b.firstOf(CxxKeyword.ASM, "__asm__"), "(", STRING, ")" // GCC ASM label
);

b.rule(linkageSpecification).is(
CxxKeyword.EXTERN, STRING,
b.firstOf(
Expand Down Expand Up @@ -1319,7 +1330,7 @@ private static void declarators(LexerfulGrammarBuilder b) {
);

b.rule(initDeclarator).is(
declarator, b.optional(initializer) // C++
declarator, b.optional(asmLabel), b.optional(initializer) // C++ (asmLabel: GCC ASM label)
);

b.rule(declarator).is(
Expand Down
50 changes: 45 additions & 5 deletions cxx-squid/src/test/java/org/sonar/cxx/parser/AssemblerTest.java
Expand Up @@ -30,34 +30,74 @@ public void asmIsoStandard() {
assertThat(p).matches("asm(\"mov eax, num\");");
}

@Test
public void asmGcc() {
p.setRootRule(g.rule(CxxGrammarImpl.asmDefinition));
assertThat(p).matches("asm(\"mov eax, num\");");
assertThat(p).matches("__asm__(\"mov eax, num\");");
assertThat(p).matches("asm virtual(\"mov eax, num\");");
assertThat(p).matches("asm inline(\"mov eax, num\");");
assertThat(p).matches("__asm__ __virtual__(\"mov eax, num\");");
}

@Test
public void asmVcAssemblyInstruction1() {
p.setRootRule(g.rule(CxxGrammarImpl.asmDefinition));
assertThat(p).matches("__asm mov eax, num ;");
assertThat(p).matches("asm mov eax, num ;");
}

@Test
public void asmVcAssemblyInstructionList1() {
p.setRootRule(g.rule(CxxGrammarImpl.asmDefinition));
assertThat(p).matches("__asm { mov eax, num }");
assertThat(p).matches("asm { mov eax, num }");
}

@Test
public void asmVcAssemblyInstructionList2() {
p.setRootRule(g.rule(CxxGrammarImpl.asmDefinition));
assertThat(p).matches("__asm { mov eax, num };");
assertThat(p).matches("asm { mov eax, num };");
}

@Test
public void asmVcAssemblyInstructionList3() {
p.setRootRule(g.rule(CxxGrammarImpl.asmDefinition));
assertThat(p).matches(
"asm {\n"
+ "mov eax, num ; Get first argument\n"
+ "mov ecx, power ; Get second argument\n"
+ "shl eax, cl ; EAX = EAX * ( 2 to the power of CL )\n"
+ "}"
"__asm {\n"
+ "mov eax, num ; Get first argument\n"
+ "mov ecx, power ; Get second argument\n"
+ "shl eax, cl ; EAX = EAX * ( 2 to the power of CL )\n"
+ "}"
);
assertThat(p).matches(
"asm {\n"
+ "mov eax, num ; Get first argument\n"
+ "mov ecx, power ; Get second argument\n"
+ "shl eax, cl ; EAX = EAX * ( 2 to the power of CL )\n"
+ "}"
);
}

@Test
public void asmGccLabel() {
p.setRootRule(g.rule(CxxGrammarImpl.asmLabel));
assertThat(p).matches("asm (\"myfoo\")");
assertThat(p).matches("__asm__ (\"myfoo\")");
}

@Test
public void asmGccLabel_reallife() {
p.setRootRule(g.rule(CxxGrammarImpl.simpleDeclaration));

assertThat(p).matches("extern const char cert_start[] asm(\"_binary_firmware_pho_by_crt_start\");");
assertThat(p).matches("int func (int x, int y) asm (\"MYFUNC\");");
assertThat(p).matches("int foo asm (\"myfoo\") = 2;");

assertThat(p).matches("extern const char cert_start[] __asm__(\"_binary_firmware_pho_by_crt_start\");");
assertThat(p).matches("int func (int x, int y) __asm__ (\"MYFUNC\");");
assertThat(p).matches("int foo __asm__ (\"myfoo\") = 2;");
}

}
Expand Up @@ -42,7 +42,7 @@
public class CxxParserTest {

String errSources = "/parser/bad/error_recovery_declaration.cc";
String[] goodFiles = {"own", "VC", "cli", "cuda", "examples"};
String[] goodFiles = {"own", "VC", "GCC", "cli", "cuda", "examples"};
String[] preprocessorFiles = {"preprocessor"};
String[] cCompatibilityFiles = {"C", "C99"};
String rootDir = "src/test/resources/parser";
Expand Down
14 changes: 14 additions & 0 deletions cxx-squid/src/test/java/org/sonar/cxx/parser/DeclaratorsTest.java
Expand Up @@ -24,6 +24,20 @@

public class DeclaratorsTest extends ParserBaseTestHelper {

@Test
public void initDeclarator() {
p.setRootRule(g.rule(CxxGrammarImpl.initDeclarator));

mockRule(CxxGrammarImpl.declarator);
mockRule(CxxGrammarImpl.asmLabel);
mockRule(CxxGrammarImpl.initializer);

assertThat(p).matches("declarator");
assertThat(p).matches("declarator initializer");
assertThat(p).matches("declarator asmLabel");
assertThat(p).matches("declarator asmLabel initializer");
}

@Test
public void initDeclaratorList() {
p.setRootRule(g.rule(CxxGrammarImpl.initDeclaratorList));
Expand Down
46 changes: 46 additions & 0 deletions cxx-squid/src/test/resources/parser/GCC/inline-assembler.cc
@@ -0,0 +1,46 @@
void main()
{
asm("movl %ecx %eax"); /* moves the contents of ecx to eax */
__asm__("movb %bh (%eax)"); /*moves the byte from bh to the memory pointed by eax */

__asm__ ("movl %eax, %ebx\n\t"
"movl $56, %esi\n\t"
"movl %ecx, $label(%edx,%ebx,$4)\n\t"
"movb %ah, (%ebx)");

// Qualifiers
asm volatile ( "movl %ecx %eax" )
asm __volatile__ ( "movl %ecx %eax" )
asm inline ( "movl %ecx %eax" )
__asm__ volatile ( "movl %ecx %eax" )
__asm__ __inline__ ( "movl %ecx %eax" )
__asm__ inline ( "movl %ecx %eax" )

// Extended Asm
int a=10, b;
asm ("movl %1, %%eax;
movl %%eax, %0;"
:"=r"(b) /* output */
:"r"(a) /* input */
:"%eax" /* clobbered register */
);
}

// Asm Labels:

// Assembler names for data:
int foo1 asm ("myfoo1") = 2;
int foo2 __asm__ ("myfoo2") = 2;
extern const char cert_start1[] asm("_binary_firmware_pho_by_crt_start1");
extern const char cert_start2[] __asm__("_binary_firmware_pho_by_crt_start2");

// Assembler names for functions:
int func2 (int x, int y) asm ("MYFUNC1");
int func3 (int x, int y) __asm__ ("MYFUNC2");

// support workaround
#define __asm__ asm
void func()
{
__asm__("movl %ecx %eax");
}
28 changes: 28 additions & 0 deletions cxx-squid/src/test/resources/parser/VC/inline-assembler.cc
@@ -0,0 +1,28 @@
// asm_overview.cpp
// processor: x86
void main()
{
// Naked functions must provide their own prolog...
__asm {
push ebp
mov ebp, esp
sub esp, __LOCAL_SIZE
}

// ... and epilog
__asm {
pop ebp
ret
}

__asm push ebp;
__asm mov ebp, esp;
__asm sub esp, __LOCAL_SIZE;
}

// support workaround
#define __asm asm
void func()
{
__asm push ebp;
}

0 comments on commit c66c820

Please sign in to comment.