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

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).

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.

Define a unique and global assembly label/symbol inside C functions

I want to mark specific C lines with sort of assembler label/symbol which will not occupy any space in the binary but by examining the linker output map file I will know all occurrences of such generated labels and, eventually, of the C code that was "marked" this way. So I want to be able to define such labels, and to make them global, and used so the linker does not throw it away
I also need some macros magic to have those labels have a unique name each time the C code is preprocessed ( to make sure each inlined instance of the function has its own label - otherwise I will have duplicate symbols, I guess )
Example :
// my build system will pass -DMYFILE_ID for each file, here I am trying to create a unique literal for each inline instance of the function
#define UN(X) #X
#define UNIQUE(X,Y) UN(X##Y)
void my_func(void)
{
_asm("GLOBAL_LABEL_"UNIQUE(MYFILE_ID,__LINE__)":\n\t")
my_c_code_I_want_to_track();
}
And what I would like to have at the end, is in the linker output symbols map file, something like that
0xsome_address GLOBAL_LABEL_12_1
0xdifferent_address GLOBAL_LABEL_12_2
0xyeanotheraddress GLOBAL_LABEL_13_1
which basically should give me an idea at which addresses my_c_code_i_want_to_track got instantiated
The whole idea is sort of inspired by how the labels in assembly are actually "symbols" that have a placement and so their addresses can be checked but they dont actually occupy its own space.
Problems :
1. Is it even possible to have assembly labels be defined like that
2. How to make those labels stay and appear in the output symbols map file
3. Something is wrong with the UNIQUE macro as I get "label redefined" when trying to compile
You can use %= (e.g. label%=:) inside an Extended-asm template to get the compiler to generate a unique number to avoid name collisions when a function containing inline-asm is inlined multiple times in one compilation unit.
#define STRINGIFY(x) #x
#define STR(x) STRINGIFY(x)
int foo(int x) {
asm("marker" __FILE__ "_line" STR(__LINE__) "_uniqueid%=:" :::);
return x+1;
}
int caller1(int x) {
return foo(x);
}
int caller2(int x) {
return foo(x);
}
compiles to the following asm with gcc -O3 (on Godbolt):
foo(int):
marker/tmp/compiler-explorer-compiler11899-55-1ki0cth.pehm/example.cpp_line4_uniqueid7:
lea eax, [rdi+1]
ret
caller1(int):
marker/tmp/compiler-explorer-compiler11899-55-1ki0cth.pehm/example.cpp_line4_uniqueid22:
lea eax, [rdi+1]
ret
caller2(int):
marker/tmp/compiler-explorer-compiler11899-55-1ki0cth.pehm/example.cpp_line4_uniqueid41:
lea eax, [rdi+3]
ret
This of course won't assemble because / isn't a valid label character in GAS.
Using MYFILE_ID which contains only characters that can appear in symbol names, this would assemble just fine, and you should be able to see all the marker labels in nm output.
One problem is that you may get multiple copies of the same label due to inlining. Add the following attribute to functions containing these labels:
__attribute__((noinline))
Also note that you need to mark the symbol as global. Let's extract this into a macro so we can format nicely without changing the value of __LINE__:
#define MAKE_LABEL \
__asm__( \
"GLOBAL_LABEL_" UNIQUE(MYFILE_ID, __LINE__) ":" \
"\n\t.global GLOBAL_LABEL_" UNIQUE(MYFILE_ID, __LINE__) \
)
But the macro-expansion is off. Unfortunately, I cannot explain to you why this works. But here is the correct macro definition:
#define UN(X) #X
#define UNIQUE2(X,Y) UN(X##Y)
#define UNIQUE(X,Y) UNIQUE2(X,Y)
Otherwise you will get __LINE__ instead of, say, 23.

What does "stack;" on a line by itself as used in the LVM2 source code mean in C?

What does the statement:
stack;
on a line by itself, as used in the LVM2 source code mean? https://www.sourceware.org/lvm2/
if (!_mountinfo_parse_line(buffer, &maj, &min, target) ||
!read_fn(buffer, maj, min, target, cb_data)) {
stack;
r = 0;
break;
}
I see that in gdb the statement "stack;" is compiled to:
lea r8,[rip+0x936db] # 0xdd704
lea rsi,[rip+0xa2f5d] # 0xecf8d
xor ecx,ecx
mov edx,0xb37
mov edi,0x7
xor eax,eax
call 0x80950 <print_log>
I also noticed that I cannot assign the results to a variable:
error: void value not ignored as it ought to be
Cannot be called as stack() or given arguments as in e.g. stack(0):
error: called object is not a function or function pointer
I also tried to grep through the source code for "stack" to see how it is derived or defined, but I couldn't find it.
Found it for you. It's a macro at lib\log\log.h.
Line 90 - #define stack log_debug("<backtrace>") /* Backtrace on error */
It's a debug print statement.
After a little bit of searching:
#define stack log_debug("<backtrace>") /* Backtrace on error */
#define log_debug(x...) LOG_LINE(_LOG_DEBUG, x)
#define LOG_LINE(l, x...) \
print_log(l, __FILE__, __LINE__ , 0, ## x)
Sort of just calls the print_log function with the string "<backtrace>" as an argument. This function then prints the argument and the file name and current line, along with a little extra stuff.

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.

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

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

Resources