Is there a way of generating asm code in a .S file using C macros? - c

I have to generate redundant asm code which keeps calling different C functions
i am trying to do something like
#define CODE_GEN(func) push a \
call func
pop a
invoking something like
CODE_GEN(foo)
will generate
bash-4.1$ gcc -E mk.S
# 1 "mk.S"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "mk.S"
# 1 "asm_gen.h" 1
# 2 "mk.S" 2
# 13 "mk.S"
pusha call foo popa iret
but this fails in compilation
bash-4.1$ gcc -m32 mk.S
mk.S: Assembler messages:
mk.S:13: Error: junk `foo popa iret' after expression
mk.S:13: Error: suffix or operands invalid for `pusha'
is there a way to delimit asm code written in a single line in a .S file ?

semicolons ';' can be used in place of line breaks.
So something like
#define CODE_GEN(func) push a; \
call func; \
pop a;
will compile and work

Yes, by using semicolons, see the other answer. C macros expand to a single string with no line breaks, but semicolons get around that.
You can also use GNU Assembler macros. This is totally untested, could be wrong:
.macro CODEGEN func
push a
call \func
pop a
.endm

Related

What is the use of the argument num in this code?

The "os161" operating system contains the following code. Specifically, where the syscalls are defined:
...
#include <kern/syscall.h>
...
#define SYSCALL(sym, num) \
.set noreorder ; \
.globl sym ; \
.type sym,#function ; \
.ent sym ; \
sym: ; \
j __syscall ; \
addiu v0, $0, SYS_##sym ; \
.end sym ; \
.set reorder
...
SYSCALL(fork, 0)
SYSCALL(vfork, 1)
SYSCALL(execv, 2)
SYSCALL(_exit, 3)
SYSCALL(waitpid, 4)
SYSCALL(getpid, 5)
...
At the bottom, each syscall gets a number. I can't seem to figure out what is the use of these numbers.
I'm not asking about the use of syscall numbers, I'm asking for the use of the argument num to the macro SYSCALL. I can't find where it's being used.
Even when the syscall number is moved to v0, the argument num is not used. Instead, it moves a constant defined in the file kern/syscall.h:
...
#define SYS_fork 0
#define SYS_vfork 1
#define SYS_execv 2
#define SYS__exit 3
#define SYS_waitpid 4
#define SYS_getpid 5
...
How can the argument num be useful somehow?
It is used for other tools to ease the maintenance of the source code.
The following is a quote from Understanding System Calls
syscalls.S: This file is created from syscalls-mips.S at compile time and is the actual file assembled into the C library. The actual names of the system calls are placed in this file using a script called callno-parse.sh that reads them from the kernel's header files. This avoids having to make a second list of the system calls. In a real system, typically each system call stub is placed in its own source file, to allow selectively linking them in. OS/161 puts them all together to simplify the makefiles. Adding new entries to callno.h automatically causes new user-level system call procedures to be defined when you re-build the user-level code. Each "SYSCALL(name,num)" macro statement in this file is expanded by the C pre-processor into a declaration of the appropriate system call function.
kern/syscall.h most likely is produce by one of those tools.

Understanding the different #define Declarations

I have a code base which uses #define in a different way then I am accustomed to.
I know that, for example, #define a 5 will replace variable a with 5 in the code.
But what would this mean:
'#define MSG_FLAG 5, REG, MSGCLR'
I tried doing it in a simple code and compiling it. It takes the last value (like the third argument as MSGCLR).
Preprocessing is largely just string replacement that happens before the "real" compilation starts. So we don't have any idea of what a variable is at this point.
The commas here are not any special syntax. This will cause any appearance of MSG_FLAG in the code to be replaced by 5, REG, MSGCLR
Most compilers have a flag that will just run the preprocessor, so you can see for yourself. On gcc, this is -E.
So to verify this, we can have some nonsense source:
#define MSG_FLAG 5, REG, MSGCLR
MSG_FLAG
Compile with gcc -E test.c
And the output is:
# 1 "test.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "test.c"
5, REG, MSGCLR

C; Inline assembly syntax mistake "Expected string literal before numerical constant"

When I compile the following example code (these are essentially junk assembly statements with no real purpose) I get the following error;
def-asm-pop.c:13:3: error: expected string literal before numeric
constant
Line 13 is the uncommented "ASM" line;
#define iMOV "mov %eax,%ebx\n\t"
#define iNOP "nop\n\t"
#define iASM __asm__(iMOV iNOP)
#define MOV 0xB8
#define NOP 0x90
#define ASM __asm__(MOV NOP)
int main() {
//iASM; /* This one works when uncommented */
ASM; /* The one causes the error when uncommented */
return 0;
}
There maybe an error in my Hello World style attempt at inline assembly, but that is another stepping stone for me to overcome. At this point in time it seems I can't define a list of opcodes and then define an assembly statement list built from them, in the same way I can by defining the text commands. How can I make ASM work like the iASM statement?
As the error message states, the __asm__ operator wants a string and not a number, and in that string it wants valid assembler.
You are trying to directly write binary opcodes, this has not much to do with assembler.
This might work:
#define MOV ".byte 0xB8\n"
#define NOP ".byte 0x90\n"
The exact syntax is of course dependent on your assembler (and the appropriate machine language is dependent on your target platform). This is not much use for anything other than experimenting; it is not a good way to write code.

x86 assembly: Using #define'd constants as arguments in calls to to #define's macros

I'm working on manually constructing an IDT table in x86 assembly. I have the following macros defined using the C preprocessor in my .S file:
// sets up an entry in the idt for a trap type
#define SETUP_IDT_ENTRY( name, num, istrap, segment, dpl ) \
lea name, %edx; \
movl $(KCODE << 16), %eax; \
movw $0x8e00, %dx; \
lea (idt + (8 * num)), %edi; \
movl %eax, (%edi); \
movl %edx, 4(%edi);
// sample set of args to a call to setup_dt_entry
#define M_DIVIDE _t_divide_ep, T_DIVIDE, 0, KCODE, 0
// the call
SETUP_IDT_ENTRY( M_DIVIDE )
However, gcc complains: error: macro "SETUP_IDT_ENTRY" requires 5 arguments, but only 1 given
I thought that #define'd arguments to #define'd functions were expanded before the function call was evaluated, in which case M_DIVIDE would expand to the five arguments required and SETUP_IDT_ENTRY would be happy. I've tried various combinations of parentheses and nothing seems to be working; is there a way to make this work?
Note: I know there are alternate approaches for building IDT's in x86 assembly, but that's not the question I'm trying to answer here; I'm just trying to figure out if macros can be expanded as macro arguments.
The arguments themselves are expanded, but the number of arguments must match the macro definition. You'll need an extra macro to make it work:
#define IDT1(x) SETUP_IDT_ENTRY(x)
IDT1(M_DIVIDE)
More info here and here.
It can be done with another layer of indirection:
#define PLEASE_SETUP_IDT_ENTRY(...) SETUP_IDT_ENTRY(__VA_ARGS__)
// the delicate, civilized call
PLEASE_SETUP_IDT_ENTRY(M_DIVIDE)
(Variadic macro is not necessary if we want a new variant to accept one and only one argument. The above definition accepts one or multiple arguments).

Undefined reference to multiply

I'm trying to call C function in assembler. This is my code:
C:
int multiply(int what)
{
return what * 2;
}
ASM:
extern multiply
start:
mov eax, 10
push eax
call multiply
jmp $
;empty
times 510-($-$$) db 0
dw 0xAA55
I'm compiling C code to elf by gcc (MinGW) and ASM code by NASM. I'm compiling it without any problems, but when I'm trying to use this code(for creating .bin file):
gcc -o test.bin work.o test.o
I' getting this error:
Does anybody know how to call C function from ASM code, compile it and link it to working .bin file? Please help.
Try to add '_' to multiply:
extern _multiply
Works for me in this simple example:
global _main
extern _printf
section .data
text db "291 is the best!", 10, 0
strformat db "%s", 0
section .code
_main
push dword text
push dword strformat
call _printf
add esp, 8
ret
Try "global multiply" instead of "extern multiply" in your .asm file. You shouldn't need the underscore for ELF (I don't think), but you can get Nasm to automagically add an underscore to anything "extern" or "global" by adding "--prefix _" to Nasm's command line.
Edit: I take that back, "extern" is correct. You seem not to have a "main". Try adding "--nostartfiles"
(may be only one hyphen) to gcc's command line.
Best,
Frank

Resources