Why does macOS kill static executables created by clang? - macos

I have a minimal c program for the m1 arm cpu that returns 42:
void _start() {
asm("mov x0, #42;");
asm("mov x16, #1;");
asm("svc 0x80;");
}
This code compiles after telling clang to use the _start symbol and returns the correct value.
clang -Wl,-e, -Wl,__start test.c -o dyn.out
./dyn.out ; echo $?
42
However this binary still has dynamic links according to otool:
otool -L ./dyn.out
./dyn.out:
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1311.100.3)
After telling clang to produce a unsigned static binary however macOS then immediately kills the binary when trying to run.
clang -Wl,-e, -Wl,__start -static -nostdlib test.c -o static_no_sign.out
zsh: killed ./static_no_sign.out
Signing the binary before running also produces the same problem.
clang -Wl,-e, -Wl,__start -static -nostdlib test.c -o static_sign.out
codesign -s - static_sign.out
./static_sign.out
zsh: killed ./static_sign.out
The following messages are produced in Console:
taskgated: UNIX error exception: 3
taskgated: no signature for pid=93166 (cannot make code: UNIX[No such process])
But codesign can verify the signature
codesign -v -v static_sign.out
static_sign.out: valid on disk
static_sign.out: satisfies its Designated Requirement
Can anyone clarify why macOS is deciding to kill the clang produced binaries?

Because static binaries are explicitly disallowed on any architecture other than x86_64.
XNU contains this code piece in the Mach-O loader:
case MH_EXECUTE:
if (depth != 1 && depth != 3) {
return LOAD_FAILURE;
}
if (header->flags & MH_DYLDLINK) {
/* Check properties of dynamic executables */
if (!(header->flags & MH_PIE) && pie_required(header->cputype, header->cpusubtype & ~CPU_SUBTYPE_MASK)) {
return LOAD_FAILURE;
}
result->needs_dynlinker = TRUE;
} else if (header->cputype == CPU_TYPE_X86_64) {
/* x86_64 static binaries allowed */
} else {
/* Check properties of static executables (disallowed except for development) */
#if !(DEVELOPMENT || DEBUG)
return LOAD_FAILURE;
#endif
}
break;
If you do the exact same thing on x86_64, it works:
void _start()
{
__asm__ volatile
(
".intel_syntax noprefix\n"
"mov eax, 0x2000001\n"
"mov edi, 42\n"
"syscall"
);
}
% clang -Wl,-e,__start -static -nostdlib t.c -o t -arch x86_64
% ./t
% echo $?
42

Related

Junks ax after expression

This code works as a IN func for i/o ports in inline c:
int func(short port)
{
short data;
__asm__(
".intel_syntax \n\t"
"in byte %0, %1\n\t"
".att_syntax\n\t"
:"=a" (data)
:"dN" (port)
:
);
return data;
}
but on compiling the c code the assembler outputs:
file.c:5: Error: junk `ax' after expression
Here is the compiling command
gcc -ffreestanding -m32 -c file.c -o file.o
I tried viewing the code in assemly using -S flag but it seems to be fine

Dart VM embedding (libdart_jit.a) on MacOS produces "dyld: Symbol not found: __ZN4dart13FLAG_profilerE"

I am trying to make my first C++ app with embedded Dart VM. I have a problem with minimal setup of compiler on my MacOS 10.14.6. My build is successful, but when I start the app, it crashed with:
$ clang++ -I ${HOME}/opt/dart-sdk --define-macro DART_SHARED_LIB=1 -L ./libs/debug -ldart_jit -lm -lz -O2 -undefined dynamic_lookup -o reproduce *.cpp
$ ./reproduce
dyld: Symbol not found: __ZN4dart13FLAG_profilerE
Although symbol __ZN4dart13FLAG_profilerE presents inside binary
$ nm reproduce | grep __ZN4dart13FLAG_profilerE
U __ZN4dart13FLAG_profilerE
How to compile/link this properly?
My reproduce program is:
#include <iostream>
#include <include/dart_api.h>
int main(int argc, const char * argv[]) {
char* setVMFlagsError = Dart_SetVMFlags(argc, argv);
if (setVMFlagsError != nullptr) {
std::cerr << "Error while set Dart VM flags: " << setVMFlagsError << "\n";
::free(setVMFlagsError);
return 1;
} else {
Dart_InitializeParams params = {};
std::cout << "Hello, World!\n";
return 0;
}
}
Dart SDK was built following by official documentation
(dart-sdk-pyenv) ~/tmp/dart-sdk/sdk $ ./tools/build.py --mode all --arch x64 create_sdk
(dart-sdk-pyenv) ~/tmp/dart-sdk/sdk $ cp -a ~/tmp/dart-sdk/sdk/xcodebuild/DebugX64/dart-sdk ~/opt/

When compiled inb and outb in inline assembly produce "Error: operand type mismatch"

I'm trying to code the simplest of the kernels for 64 bits arch and I'm having trouble with keyboard input.
I'm currently implementing this two functions to manage I/O
unsigned char inportb (unsigned short _port)
{
unsigned char rv;
__asm__ __volatile__ ("inb %1, %0" : "=a" (rv) : "dN" (_port));
return rv;
}
void outportb (unsigned short _port, unsigned char _data)
{
__asm__ __volatile__ ("outb %1, %0" : : "dN" (_port), "a" (_data));
}
But I'm getting this assembler error:
main.c: Mensajes del ensamblador:
main.c:51: Error: no coincide el tipo de operando para «in»
main.c:61: Error: no coincide el tipo de operando para «out»
Or in English:
main.c: Assembler messages:
main.c:51: Error: operand type mismatch for `in'
main.c:61: Error: operand type mismatch for `out'
My guess is that this code (that I got from http://www.osdever.net/bkerndev/Docs/creatingmain.htm) is designed for 32 bits assembly.
Any help on how to solve my problem would be greatly appreciated.
I build and run everything with this script
#!/bin/bash
nasm -f bin boot.asm -o boot.bin
nasm -f elf64 loader.asm -o loader.o
#cc -m64 -ffreestanding -fno-builtin -nostdlib -c main.c
cc -m64 -masm=intel -c main.c
ld -Ttext 0x100000 -o kernel.elf loader.o main.o
objcopy -R .note -R .comment -S -O binary kernel.elf kernel.bin
dd if=/dev/zero of=image.bin bs=512 count=2880
dd if=boot.bin of=image.bin conv=notrunc
dd if=kernel.bin of=image.bin conv=notrunc bs=512 seek=1
rm ./boot.bin ./kernel.bin ./main.o ./loader.o ./kernel.elf
qemu-system-x86_64 image.bin
By default GCC uses AT&T assembly syntax when generating assembly code from C code. This can be overridden by using the -masm=intel GCC compile option. In the update to your question you have -masm=intel in your GCC command line:
cc -m64 -masm=intel -c main.c
The code you found was designed for AT&T syntax where the source operand of an instruction is first and the destination is second. -masm=intel option has reversed that behavior. You have two choices. Reverse the operands in the inline assembly so they are destination, source (intel syntax) like this:
unsigned char inportb (unsigned short _port)
{
unsigned char rv;
__asm__ __volatile__ ("inb %0, %1" : "=a" (rv) : "dN" (_port));
return rv;
}
void outportb (unsigned short _port, unsigned char _data)
{
__asm__ __volatile__ ("outb %0, %1" : : "dN" (_port), "a" (_data));
}
The other option is to remove -masm=intel option from your GCC command line and keep the code as is. This might be preferable as a significant amount of OS Development code uses AT&T syntax for inline assembly.
Note: You might want to consider using gcc instead of just cc

gcc warning different when using --preprocessed

When compiling ltrace with icecc we run into a compilation problem. This is the minimal example:
main.c
#include <assert.h>
int main(int argc, char **argv) {
assert(argc != argc);
return 0;
}
test.sh:
#!/bin/bash
set -x
# one step compilation (no warning)
gcc -Wall main.c
# splitted compilation (warning)
gcc -Wall -E main.c -o main.i
gcc -Wall --preprocessed main.i
output:
++ gcc -Wall main.c
++ gcc -Wall -E main.c -o main.i
++ gcc -Wall --preprocessed main.i
main.c: In function ‘main’:
main.c:4:10: warning: self-comparison always evaluates to false [-Wtautological-compare]
assert(argc != argc);
^~
As you can see the result is different when compiling in one step and when preprocessing and compiling in two steps. Is this intended behavior?
I use gcc 6.3, the issue also appears in gcc 6.2 for ARM. I also cannot ignore this, as the full example uses -Werror.

Can't compile flex & bison (Symbols not found x86_64)

I am trying to compile a simple program on Flex & Bison on my Mac running Yosemite but get the following error:
Undefined symbols for architecture x86_64:
"_yyerror", referenced from:
_yyparse in pr1-19c182.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
My two files look like this, they compile on my teacher's Ubuntu installation but I can't get them to work on my Mac:
pr1.y
%{
#include <stdio.h>
%}
%%
expr : expr '+' term {printf(" + ");}
| term
;
term : term '*' fact {printf(" * ");}
| fact
;
fact : "(" expr ")"
| '0' {printf("0");}
| '1' {printf("1");}
| '2' {printf("2");}
| '3' {printf("3");}
| '4' {printf("4");}
| '5' {printf("5");}
| '6' {printf("6");}
| '7' {printf("7");}
| '8' {printf("8");}
| '9' {printf("9");}
%%
pr1.l
%{
#include "pr1.tab.h"
%}
%%
[0-9] {return (yytext[0]);}
[+*()] {return (yytext[0]);}
\n {return (0);}
. {}
%%
I compile everything using the following commands:
bison -d pr1.y
flex pr1.l
gcc -o result lex.yy.c pr1.tab.c -lfl -std=gnu89
The reason I use the -std flag is because the default is c99 and the code generated by flex and bison gets warnings and errors. Any ideas???
You need to define yyerror in your bison input file (pr1.y). And you need to declare yylex or you will get another warning.
The following would be fine:
%{
#include <stdio.h>
void yyerror(const char* msg) {
fprintf(stderr, "%s\n", msg);
}
int yylex();
%}
I have no idea how it works without that on your teacher's machine.
Also, Mac OS X has very old versions of bison and flex. You might want to upgrade.
Check out the 2nd comment of the answer on this post Unable to compile output of lex
On Mac OS X, if you're trying to compile from the command line, you need to link against the libl.a library, by using -ll instead of -lfl. Apparently OS X has no libfl.a library. So try this...
gcc -o result lex.yy.c pr1.tab.c -ll
Don't know about your need for the -std=gnu89 option.

Resources