This file is indexed.

/usr/src/ndiswrapper-1.59/win2lin_stubs.S is in ndiswrapper-dkms 1.59-2.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
/*
 *  Copyright (C) 2005 Karl Vogel, Giridhar Pemmasani
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 *  GNU General Public License for more details.
 *
 */

#include <linux/linkage.h>

#ifdef CONFIG_X86_64

/*
# Windows <---> Linux register usage conversion when calling functions
# V = Volatile
# NV = Non Volatile (needs to be saved)
#
#         Win                     Lin
# ---------------------------------------
# Rax    Return           V       Return          V
# Rbx                     NV                      NV
# Rcx     Arg1            V       Arg4            V
# Rdx     Arg2            V       Arg3            V
# Rsi                     NV      Arg2            V
# Rdi                     NV      Arg1            V
# Rsp                     NV                      NV
# Rbp                     NV                      NV
# R8      Arg3            V       Arg5            V
# R9      Arg4            V       Arg6            V
# R10                     V                       V
# R11                     V                       V
# R12                     NV                      NV
# R13                     NV                      NV
# R14                     NV                      NV
# R15                     NV                      NV
#
# In addition, Linux uses %rax to indicate number of SSE registers used
# when variadic functions are called. Since there is no way to obtain this
# from Windows, for now, we just assume this is 0 (hence %rax is cleared).
#
# Windows pushes arguments 5 and higher onto stack in case of integer
# variables and 4 and higher in case of floating point variables (passed
# in SSE registers).

In a windows function, the stackframe/registers look like this:

# 0x0048 ....
# 0x0040 arg8
# 0x0038 arg7
# 0x0030 arg6
# 0x0028 arg5
# 0x0020 shadow/spill space for arg4
# 0x0018 shadow/spill space for arg3
# 0x0010 shadow/spill space for arg2
# 0x0008 shadow/spill space for arg1
# 0x0000 ret

# register spill space is same irrespective of number of arguments - even
# if Windows function takes less than 4 arguments, 32 bytes above return
# address is reserved for the function

In Linux it should look like:

# 0x0018 ....
# 0x0010 arg8
# 0x0008 arg7
# 0x0000 ret

*/

	.text

#define LINUX_REG_ARGS 6
#define LOOP_THRESHOLD 9
#define WORD_BYTES 8

/*
 * %rsi and %rdi must be saved because they are not saved by Linux calls, but
 * Windows callers expect them to be saved.  %rbp is saved to create a stack
 * frame, which can help with debugging.  We need to reserve space for an odd
 * number of registers anyway to keep 16-bit alignment of the stack (one more
 * position is used by the return address).
 */
#define SAVED_REGS 3

/*
 * When calling the Linux function, several registers are saved on the stack.
 * When passing more than 6 arguments, arguments starting with argument 7 are
 * pushed to the stack as well.
 *
 * We also need to allocate an additional word on the stack to keep it aligned
 * to the 16-bit boundary if the number of saved arguments plus one (for the
 * return address) is odd.
 */

/*
 * Number of arguments we pass on stack to the Linux function.
 * The value of true is -1 in assembler, so we multiply it by another true
 * value.
 */
#define stack_args(argc)					\
	((0 < 1) * (argc > LINUX_REG_ARGS) * (argc - LINUX_REG_ARGS))

/* Full required change of stack pointer, in words */
#define stack_words_raw(argc) (stack_args(argc) + SAVED_REGS + 1)

/* Full actual change of stack pointer, in words (must be even) */
#define stack_words_aligned(argc) ((stack_words_raw(argc) + 1) & ~1)

/* Space allocated for Linux arguments on stack */
#define stack_space(argc) \
	((stack_words_aligned(argc) - SAVED_REGS - 1) * WORD_BYTES)

/*
 * win2lin_win_arg(N, ARGC) gives the address of the Windows argument N out of
 * total ARGC after the stack has been prepared for the Linux function call.
 *
 * When called from Windows, the Nth argument is at (N * 8)(%rsp).  We add the
 * stack space allocated by the Linux function to compensate for %rsp change.
 *
 * Don't call with N less than 5!
 */
#define win2lin_win_arg(n, argc) \
	((n + SAVED_REGS) * WORD_BYTES + stack_space(argc))(%rsp)

/*
 * win2lin_lin_arg(N) gives the address of the Nth Linux argument on the extra
 * Linux stack frame.  When more than 6 arguments are used, %rsp points to the
 * 7th argument.  The Nth argument is therefore at ((N - 7) * 8)(%rsp).
 *
 * Don't call with N less than 7!
 */
#define win2lin_lin_arg(n) ((n - 1 - LINUX_REG_ARGS) * WORD_BYTES)(%rsp)

/* Declare function LONGNAME, call function SHORTNAME with ARGC arguments */
.macro win2linm longname, shortname, argc
	.type \longname, @function
	ENTRY(\longname)

	/* Create a call frame - it's optional, but good for debugging */
	.cfi_startproc
	push %rbp
	.cfi_def_cfa %rsp, 2 * WORD_BYTES
	.cfi_offset %rbp, -2 * WORD_BYTES
	mov %rsp, %rbp
	.cfi_def_cfa %rbp, 2 * WORD_BYTES

	/*
	 * Registers %rdi and %rsi are volatile on Linux, but not on Windows,
	 * so save them on the stack.
	 */
	push %rsi
	push %rdi

	/* Allocate extra stack space for arguments 7 and up */
	sub $stack_space(\argc), %rsp

	/*
	 * Copy arguments 7 and up.  We do it early, before %rdi and %rsi
	 * are used for arguments 1 and 2, so we don't have to save them.
	 * We still need to save %rcx if using a string copy.
	 */
	.if (\argc < LOOP_THRESHOLD)
		/* If a few arguments, copy them individually through %r11 */
		.if (\argc >= 7)
			mov win2lin_win_arg(7, \argc), %r11
			mov %r11, win2lin_lin_arg(7)
		.endif
		.if (\argc >= 8)
			mov win2lin_win_arg(8, \argc), %r11
			mov %r11, win2lin_lin_arg(8)
		.endif
	.else
		/* If there are many arguments, copy them in a loop */
		/* Save arg1 to %r11 */
		mov %rcx, %r11
		/* Source and destination */
		lea win2lin_win_arg(LINUX_REG_ARGS + 1, \argc), %rsi
		lea win2lin_lin_arg(LINUX_REG_ARGS + 1), %rdi
		/* Number of arguments to copy (%ecx zero-extends to %rcx) */
		mov $(\argc - LINUX_REG_ARGS), %ecx
		rep movsq
		/* Restore arg1 directly to %rdi */
		mov %r11, %rdi
	.endif

	/*
	 * Argument 1 - %rcx on Windows, %rdi on Linux
	 * Micro-optimization - if we used loop, arg1 is already in %rdi
	 */
	.if (\argc >= 1) && (\argc < LOOP_THRESHOLD)
		mov %rcx, %rdi
	.endif

	/* Argument 2 - %rdx on Windows, %rsi on Linux */
	.if (\argc >= 2)
		mov %rdx, %rsi
	.endif

	/* Argument 3 - %r8 on Windows, %rdx on Linux */
	.if (\argc >= 3)
		mov %r8, %rdx
	.endif

	/* Argument 4 - %r9 on Windows, %rcx on Linux */
	.if (\argc >= 4)
		mov %r9, %rcx
	.endif

	/* Argument 5 - first argument on stack on Windows, %r8 Linux */
	.if (\argc >= 5)
		mov win2lin_win_arg(5, \argc), %r8
	.endif

	/* Argument 6 - second argument on stack on Windows, %r9 Linux */
	.if (\argc >= 6)
		mov win2lin_win_arg(6, \argc), %r9
	.endif

	/* %rax on Linux is the number of arguments in SSE registers (zero) */
	xor %rax, %rax

	/* Call the function */
	call \shortname

	/* Free stack space for arguments 7 and up */
	add $stack_space(\argc), %rsp

	/* Restore saved registers */
	pop %rdi
	pop %rsi

	/* Return to Windows code */
	leave
	.cfi_def_cfa %rsp, WORD_BYTES
	.cfi_restore %rbp
	ret
	.cfi_endproc
	.size \longname, (. - \longname)
.endm

#define win2lin(name, argc) win2linm win2lin_ ## name ## _ ## argc, name, argc

#include "win2lin_stubs.h"

#endif	/* CONFIG_X86_64 */