EDK2 Shell Application using Variable Arguments built with GCC causes Page Fault when run - c

I am having issues with using variable arguments under EDK2 (x64 shell application) when built under a Linux host with gcc. Program builds but when executed it will cause a page fault at the point VA_ARG() is executed.
The same code when built under a Windows host with VS2015 works without issue.
This seems related to GCC bug 50818 but I can find no solution.
#include <Uefi.h>
#include <Library/UefiLib.h>
#include <Library/PrintLib.h>
#include <Library/ShellCEntryLib.h>
VOID PrintInts(UINTN n, ...)
{
VA_LIST vl;
VA_START(vl, n);
Print(L"Printing integers:");
for (UINTN i=0; i<n; i++) {
UINTN val = 0;
val = VA_ARG(vl, UINTN);
Print(L" [%d]", val);
}
VA_END(vl);
Print(L"\n");
}
INTN EFIAPI ShellAppMain(IN UINTN Argc, IN CHAR16 **Argv)
{
UINTN a = 3;
UINTN b = 10;
UINTN c = 9;
PrintInts(3, a, b, c);
return 0;
}

I have found a fix and that is to define the function with the EFIAPI tag and this fixes the issue, i.e.
VOID EFIAPI PrintInts(UINTN n, ...)
From this link:
When creating a 32-bit UEFI application, EFIAPI is empty; GCC will compile the "efi_main" function using the standard C calling convention. When creating a 64-bit UEFI application, EFIAPI expands to "__attribute__((ms_abi))" and GCC will compile the "efi_main" function using Microsoft's x64 calling convention, as specified by UEFI. Only functions that will be called directly from UEFI (including main, but also callbacks) need to use the UEFI calling convention.
Also it only seem to be an issue with GCC as if I use CLANG I do not need to specify EFIAPI.

Related

Is it possible for an LD_PRELOAD to only affect the main executable?

The Actual Problem
I have an executable that by default uses EGL and SDL 1.2 to handle graphics and user input respectively. Using LD_PRELOAD, I have replaced both with GLFW.
This works normally unless the user has installed the Wayland version of GLFW, which depends on EGL itself. Because all the EGL calls are either stubbed to do nothing or call GLFW equivalents, it doesn't work (ie. eglSwapBuffers calls glfwSwapBuffers which calls eglSwapBuffers and so on). I can't remove the EGL stubs because then it would call both EGL and GLFW and the main executable is closed-source so I can't modify that.
Is there any way to make LD_PRELOAD affect the main executable but not GLFW? Or any other solution to obtain the same effect?
The Simplified Problem
I made a simplified example to demonstrate the problem.
Main Executable:
#include <stdio.h>
extern void do_something();
int main() {
do_something();
fputs("testing B\n", stderr);
}
Shared Library:
#include <stdio.h>
void do_something() {
fputs("testing A\n", stderr);
}
Preloaded Library:
#include <stdio.h>
int fputs(const char *str, FILE *file) {
// Do Nothing
return 0;
}
When the preloaded library isn't used, the output is:
testing A
testing B
When it is used, the output is nothing.
I'm looking for a way to make the preloaded library only affect the main executable, that the output would be:
testing A
Thank you!
You can check if the return address is in the executable or the library, and then call either the "real" function or do your stub code, like this:
#define _GNU_SOURCE
#include <dlfcn.h>
#include <link.h>
#include <stdio.h>
#include <stdlib.h>
static struct {
ElfW(Addr) start, end;
} *segments;
static int n;
static int (*real_fputs)(const char *, FILE *);
static int callback(struct dl_phdr_info *info, size_t size, void *data) {
n = info->dlpi_phnum;
segments = malloc(n * sizeof *segments);
for(int i = 0; i < n; ++i) {
segments[i].start = info->dlpi_addr + info->dlpi_phdr[i].p_vaddr;
segments[i].end = info->dlpi_addr + info->dlpi_phdr[i].p_vaddr + info->dlpi_phdr[i].p_memsz;
}
return 1;
}
__attribute__((__constructor__))
static void setup(void) {
real_fputs = dlsym(RTLD_NEXT, "fputs");
dl_iterate_phdr(callback, NULL);
}
__attribute__((__destructor__))
static void teardown(void) {
free(segments);
}
__attribute__((__noinline__))
int fputs(const char *str, FILE *file) {
ElfW(Addr) addr = (ElfW(Addr))__builtin_extract_return_addr(__builtin_return_address(0));
for(int i = 0; i < n; ++i) {
if(addr >= segments[i].start && addr < segments[i].end) {
// Do Nothing
return 0;
}
}
return real_fputs(str, file);
}
This has some caveats, though. For example, if your executable calls a library function that tail-calls a function you're hooking, then this will incorrectly consider that library call an executable call. (You could mitigate this problem by adding wrappers for those library functions too, that unconditionally forward to the "real" function, and compiling the wrapper code with -fno-optimize-sibling-calls.) Also, there's no way to distinguish whether anonymous executable memory (e.g., JITted code) originally came from the executable or a library.
To test this, save my code as hook_fputs.c, your main executable as main.c, and your shared library as libfoo.c. Then run these commands:
clang -fPIC -shared hook_fputs.c -ldl -o hook_fputs.so
clang -fPIC -shared libfoo.c -o libfoo.so
clang main.c ./libfoo.so
LD_PRELOAD=./hook_fputs.so ./a.out
Implement the interposing library separately for the two cases.
Create a wrapper script or program that uses ldd to find out the exact EGL library version and their paths the target binary is dynamically linked against; then, using ldd on the the GLFW library, to find out whether it is linked against EGL or not. Finally, have it execute the target binary with the path to the appropriate interposing library in LD_PRELOAD environment variable.

Why does rl_bind_key with custom function fail in readline on OSX/macOS

I built a shell that tries to make the tab (\t) key do something custom using rl_bind_key(), but it didn't work in macOS Sierra, but it works on Ubuntu, Fedora, and CentOS. Here's the mcve:
#include <stdlib.h>
#include <stdio.h>
#include <readline/readline.h>
static int cmd_complete(int count, int key)
{
printf("\nCustom tab action goes here...\n");
rl_forced_update_display();
return 0;
}
char *interactive_input()
{
char *buffer = readline(" > ");
return buffer;
}
int main(int argc, char **argv)
{
rl_bind_key('\t', cmd_complete); // this doesn't seem to work in macOS
char *buffer = 0;
while (!buffer || strncmp(buffer, "exit", 4)) {
if (buffer) { free(buffer); buffer=0; }
// get command
buffer = interactive_input();
printf("awesome command: %s\n", buffer);
}
free(buffer);
return 0;
}
I compile using Clang like this:
$ cc -lreadline cli.c -o cli
What is the cause of this behavior and how do I fix it?
I was using the flag -lreadline, however unbeknownst to me, Clang appears to secretly use libedit (I've seen it called editline also). In libedit, for some reason (which merits another question), rl_bind_key appears to not work with anything except rl_insert.
So one solution that I found is to use Homebrew to install GNU Readline (brew install readline), and then to ensure I use that version, I compile thusly:
$ cc -lreadline cli.c -o cli -L/usr/local/opt/readline/lib -I/usr/local/opt/readline/include
In fact, when you install readline, it will tell you this at the end of the installation or if you do brew info readline:
gns-mac1:~ gns$ brew info readline
readline: stable 7.0.3 (bottled) [keg-only]
Library for command-line editing
https://tiswww.case.edu/php/chet/readline/rltop.html
/usr/local/Cellar/readline/7.0.3_1 (46 files, 1.5MB)
Poured from bottle on 2017-10-24 at 12:21:35
From: https://github.com/Homebrew/homebrew-core/blob/master/Formula/readline.rb
==> Caveats
This formula is keg-only, which means it was not symlinked into /usr/local,
because macOS provides the BSD libedit library, which shadows libreadline.
In order to prevent conflicts when programs look for libreadline we are
defaulting this GNU Readline installation to keg-only..
For compilers to find this software you may need to set:
LDFLAGS: -L/usr/local/opt/readline/lib
CPPFLAGS: -I/usr/local/opt/readline/include
Source of libedit rl_bind_key
So this is why it doesn't work in libedit. I downloaded the source and this is how the rl_bind_key function is defined:
/*
* bind key c to readline-type function func
*/
int
rl_bind_key(int c, rl_command_func_t *func)
{
int retval = -1;
if (h == NULL || e == NULL)
rl_initialize();
if (func == rl_insert) {
/* XXX notice there is no range checking of ``c'' */
e->el_map.key[c] = ED_INSERT;
retval = 0;
}
return retval;
}
So it seems designed to not work with anything except rl_insert. That seems like a bug, not a feature. I wish I knew how to become a contributor to libedit.

How can I Pass variables to C programm using gcc

How can I Pass variables to C program using gcc ??
For example
gcc -o server ./server.c --host=localhost --port=1234
how to access these variables in my code ?
Thank you.
Your question isn't clear; there are at least two things you might be asking about: how to access command line arguments passed to your program when it is run and how to access arguments passed to the compiler when your program is compiled.
Command line arguments:
./server --host=localhost --port=1234
These are accessed via arguments to main():
int main(int argc, char *argv[]) {
for (int i=0; i<argc; ++i) {
std::cout << argv[i] << '\n';
}
}
getopt is a pretty common way to parse these command line options, though it isn't part of the C or C++ standards.
Compiler arguments:
You can't necessarily access arguments passed to the compiler, but for the arguments you can detect you detect them through changes to the compile environment. For example if the compiler takes an option to enable a language feature then you can detect when that option is passed by detecting if the feature is enabled.
gcc -std=c11 main.cpp
int main() {
#if 201112L <= __STDC_VERSION__
printf("compiler was set to C11 mode (or greater).\n");
#else
printf("compiler set to pre-C11 mode.\n");
#endif
}
Additionally you can directly define macros in command line arguments to the compiler that the program will be able to access.
gcc -DHELLO="WORLD" main.cpp
int main() {
#if defined(HELLO)
printf("%s\n", HELLO);
#else
printf("'HELLO' is not defined\n");
#endif
}
If you want to define them at compile-time see the -D param, if you want to define them at runtime use something like
int main(int,char**);
int main(int argsc/*argument count*/, char**argv/*argument vector*/)
{
int i;
for(i=0;i<argsc;i++)
{
printf("%s\n",argsv[i]);
}
return 0;
}
If you want to pass variables to your program execution, you can use environment variables. Like this:
char* myOption = getenv("MY_OPTION_NAME");
if(!myOption) myOption = "my default value";
//Do whatever you like with the value...
And when you call your program, you can set the variables inline by assigning them before the program name:
MY_OPTION_NAME="foo" ./server
You could also set your environment variables once and for all using
export MY_OPTION_NAME="foo"

Procedural parameters in xcode

is it possible to get procedural paramters working in xcode? I am working on an assignment for university, and would like to use the debugger in xcode to help me learn whats going on.
I know the code is at the very minimum compilable, because i was able to compile it with gcc, but xcode does not recognize the syntax.
the code i'm trying to run in xcode is:
#include <stdlib.h>
#include <stdio.h>
int main() {
int a = 50;
int b = 100;
void P(int *c, void R(int)) {
void Q(int p) {
printf("%d\n", p);
R(p+100);
}
if (a == b) R(b);
else {c = c + 25;
P(c, Q);
}
}
void Q(int p) {
printf("%d\n", p);
}
P(&a,Q);
}
Xcode uses the clang compiler by default, which does not support nested functions. To use gcc in Xcode, go to your project settings, select your target and change Compiler for C/C++/Objective-C to LLVM GCC 4.2. Now if you compile, gcc will complain, that nested functions are not enabled. Go back to your target settings, LLVM GCC 4.2 Language and under Other C Flags add -fnested-functions. Your project should compile now.

How to execute some code before entering the main() routine in VC?

I am reading Microsoft's CRT source code, and I can come up with the following code, where the function __initstdio1 will be executed before main() routine.
The question is, how to execute some code before entering the main() routine in VC (not VC++ code)?
#include <stdio.h>
#pragma section(".CRT$XIC",long,read)
int __cdecl __initstdio1(void);
#define _CRTALLOC(x) __declspec(allocate(x))
_CRTALLOC(".CRT$XIC") static pinit = __initstdio1;
int z = 1;
int __cdecl __initstdio1(void) {
z = 10;
return 0;
}
int main(void) {
printf("Some code before main!\n");
printf("z = %d\n", z);
printf("End!\n");
return 0;
}
The output will be:
Some code before main!
z = 10
End!
However, I am not able to understand the code.
I have done some google on .CRT$XIC but no luck is found. Can some expert explain above code segment to me, especially the followings:
What does this line _CRTALLOC(".CRT$XIC") static pinit = __initstdio1; mean? What is the significance of the variable pinit?
During compilation the compiler (cl.exe) throws a warning saying as below:
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 15.00.30729.01 for 80x86
Copyright (C) Microsoft Corporation. All rights reserved.
stdmacro.c
stdmacro.c(9) : warning C4047: 'initializing' : 'int' differs in levels of indirection from 'int (__
cdecl *)(void)'
Microsoft (R) Incremental Linker Version 9.00.30729.01
Copyright (C) Microsoft Corporation. All rights reserved.
/out:stdmacro.exe
stdmacro.obj
What is the corrective action needs to be done to remove the warning message?
Thanks in advance.
Added:
I have modified the code and give type to pinit as _PIFV. Now the warning message is gone.
The new code is as follows:
#include <stdio.h>
#pragma section(".CRT$XIC1",long,read)
int __cdecl __initstdio1(void);
typedef int (__cdecl *_PIFV)(void);
#define _CRTALLOC(x) __declspec(allocate(x))
_CRTALLOC(".CRT$XIC1") static _PIFV pinit1 = __initstdio1;
int z = 1;
int __cdecl __initstdio1(void) {
z = 100;
return 0;
}
int main(void) {
printf("Some code before main!\n");
printf("z = %d\n", z);
printf("End!\n");
return 0;
}
A simple way to do this.
#include <iostream>
int before_main()
{
std::cout << "before main" << std::endl;
return 0;
}
static int n = before_main();
void main(int argc, char* argv[])
{
std::cout << "in main" << std::endl;
}
This is what _CRTALLOC is defined as:
extern _CRTALLOC(".CRT$XIA") _PVFV __xi_a[];
extern _CRTALLOC(".CRT$XIZ") _PVFV __xi_z[];// C initializers
extern _CRTALLOC(".CRT$XCA") _PVFV __xc_a[];
extern _CRTALLOC(".CRT$XCZ") _PVFV __xc_z[];// C++ initializers
It's a table of things to pre-initialise, of which a pointer to your function __initstdio1 is placed.
This page described CRT initialisation:
http://msdn.microsoft.com/en-us/library/bb918180.aspx
In C++ at least, you don't need all that implementation specific stuff:
#include <iostream>
struct A {
A() { std::cout << "before main" << std::endl; }
};
A a;
int main() {
std::cout << "in main" << std::endl;
}
I wrote an award-winning article about this on CodeGuru a while ago.
There's some information here (search for CRT). The significance of variable pinit is none, it's just a piece of data placed in the executable, where the runtime can find it. However, I would advise you to give it a type, like this:
_CRTALLOC(".CRT$XIC") static void (*pinit)()=...
The linker warning probably just warns you you have a function that has int return type, but doesn't return anything (probably you'd better change the return type to void).
Even in C, there is a need for some code to be run before main() is entered, if only to transform the command line into the C calling convention. In practice, the standard library needs some initialization, and the exact needs can vary from compile to compile.
The true program entry point is set at link time, and is usually in a module named something like crt0 for historical reasons. As you've found, the source to that module is available in the crt sources.
To support initializations that are discovered at link time, a special segment is used. Its structure is a list of function pointers of fixed signature, which will be iterated early in crt0 and each function called. This same array (or one very much like it) of function pointers is used in a C++ link to hold pointers to constructors of global objects.
The array is filled in by the linker by allowing every module linked to include data in it, which are all concatenated together to form the segment in the finished executable.
The only significance to the variable pinit is that it is declared (by the _CRTALLOC() macro) to be located in that segment, and is initialized to the address of a function to be called during the C startup.
Obviously, the details of this are extremely platform-specific. For general programming, you are probably better served by wrapping your initialization and your current main inside a new main():
int main(int argc, char **argv) {
early_init();
init_that_modifies_argv(&argc, &argv);
// other pre-main initializations...
return real_main(argc,argv);
}
For special purposes, modifying the crt0 module itself or doing compiler-specific tricks to get additional early initialization functions called can be the best answer. For example, when building embedded systems that run from ROM without an operating system loader, it is common to need to customize the behavior of the crt0 module in order to have a stack at all on which to push the parameters to main(). In that case, there may be no better solution than to modify crt0 to initialize the memory hardware to suit your needs.

Resources