Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,13 @@ BUILTIN_LIBC_HEADER := c.h
STAGE0_FLAGS ?= --dump-ir
STAGE1_FLAGS ?=
DYNLINK ?= 0
BINDING ?= lazy

COMMENTFLOW ?= commentflow
SHFMT ?= shfmt
ifeq ($(DYNLINK),1)
STAGE0_FLAGS += --dynlink
STAGE1_FLAGS += --dynlink
STAGE0_FLAGS += --dynlink -z $(BINDING)
STAGE1_FLAGS += --dynlink -z $(BINDING)
Comment thread
cubic-dev-ai[bot] marked this conversation as resolved.
endif

SRCS := $(wildcard $(patsubst %,%/main.c, $(SRCDIR)))
Expand Down Expand Up @@ -183,11 +184,11 @@ uninstall-hooks:

check-stage0: $(OUT)/$(STAGE0) tests/driver.sh
$(VECHO) " TEST STAGE 0\n"
tests/driver.sh 0 $(DYNLINK)
tests/driver.sh 0 $(DYNLINK) $(BINDING)

check-stage2: $(OUT)/$(STAGE2) tests/driver.sh
$(VECHO) " TEST STAGE 2\n"
tests/driver.sh 2 $(DYNLINK)
tests/driver.sh 2 $(DYNLINK) $(BINDING)

check-sanitizer: $(OUT)/$(STAGE0)-sanitizer tests/driver.sh
$(VECHO) " TEST STAGE 0 (with sanitizers)\n"
Expand All @@ -196,10 +197,10 @@ check-sanitizer: $(OUT)/$(STAGE0)-sanitizer tests/driver.sh
$(Q)rm $(OUT)/shecc

check-abi-stage0: $(OUT)/$(STAGE0)
tests/$(ARCH)-abi.sh 0 $(DYNLINK);
tests/$(ARCH)-abi.sh 0 $(DYNLINK) $(BINDING);

check-abi-stage2: $(OUT)/$(STAGE2)
tests/$(ARCH)-abi.sh 2 $(DYNLINK);
tests/$(ARCH)-abi.sh 2 $(DYNLINK) $(BINDING);

# Both prerequisites are order-only, and both exist because "make -j" would
# otherwise let a compile start beside the thing it reads. Selecting a target
Expand Down
1 change: 0 additions & 1 deletion mk/arm64.mk
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ ARCH_DEFS = \
\#define PLT_ENT_SIZE 16\n$\
\#define RESERVED_GOT_NUM 3\n$\
\#define R_ARCH_JUMP_SLOT 1026 /* R_AARCH64_JUMP_SLOT */\n$\
\#define DYN_BIND_NOW 1\n$\
"

# An Arm64 Linux host runs this target's output itself, so nothing has to stand
Expand Down
1 change: 0 additions & 1 deletion mk/x64.mk
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ ARCH_DEFS = \
\#define RESERVED_GOT_NUM 3\n$\
\#define R_ARCH_JUMP_SLOT 7 /* R_X86_64_JUMP_SLOT */\n$\
\#define REG_CNT 11 /* rdi rsi rdx rcx r8 r9 rax rbx r14 r12 r13 */\n$\
\#define DYN_BIND_NOW 1 /* this PLT has no lazy-resolution path */\n$\
\#define HAVE_COND_MOVE 1 /* CMOVcc */\n$\
\#define CALLEE_SAVED_REGS 4 /* the file ends rbx r14 r12 r13 */\n$\
"
7 changes: 0 additions & 7 deletions src/defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -177,13 +177,6 @@
#define ALIGN_UP(val, align) (((val) + (align) - 1) & ~((align) - 1))
#endif

/* Targets whose PLT has no lazy-resolution path ask the loader to bind every
* PLT entry at load time.
*/
#ifndef DYN_BIND_NOW
#define DYN_BIND_NOW 0
#endif

#define ELF_MACHINE_ARM32 0x28
#define ELF_MACHINE_RV32 0xf3
#define ELF_MACHINE_X86_64 0x3e
Expand Down
11 changes: 7 additions & 4 deletions src/elf.c
Original file line number Diff line number Diff line change
Expand Up @@ -1086,14 +1086,17 @@ void elf_generate_dynamic_sections(void)
elf_write_dyn(dynamic_sections.elf_dynamic, 0x3,
dynamic_sections.elf_got_start);
elf_write_dyn(dynamic_sections.elf_dynamic, 0x1, 0x1);
#if DYN_BIND_NOW == 1

/* Resolve every PLT entry at load time. This target's PLT[0] does not
* arrange the GOT[1]/GOT[2] hand-off the lazy resolver needs, so the loader
* writes the final addresses straight into the GOT instead.
*/
elf_write_dyn(dynamic_sections.elf_dynamic, 0x18, 0x0); /* DT_BIND_NOW */
elf_write_dyn(dynamic_sections.elf_dynamic, 0x1e, 0x8); /* DF_BIND_NOW */
#endif
if (imm_binding) {
elf_write_dyn(dynamic_sections.elf_dynamic, 0x18,
0x0); /* DT_BIND_NOW */
elf_write_dyn(dynamic_sections.elf_dynamic, 0x1e,
0x8); /* DF_BIND_NOW */
}
elf_write_dyn(dynamic_sections.elf_dynamic, 0x0, 0x0);
}

Expand Down
1 change: 1 addition & 0 deletions src/globals.c
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ dynamic_sections_t dynamic_sections;

/* Command line compilation flags */
bool dynlink = false;
bool imm_binding = false;
bool libc = true;
bool expand_only = false;
bool dump_ir = false;
Expand Down
26 changes: 24 additions & 2 deletions src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,18 @@ int main(int argc, char *argv[])
libc = false;
else if (!strcmp(argv[i], "--dynlink"))
dynlink = true;
else if (!strcmp(argv[i], "-E"))
else if (!strcmp(argv[i], "-z")) {
if (i + 1 >= argc)
usage_error("-z requires \"lazy\" or \"now\"");

if (!strcmp(argv[i + 1], "lazy"))
imm_binding = false;
else if (!strcmp(argv[i + 1], "now"))
imm_binding = true;
else
usage_error("-z requires \"lazy\" or \"now\"");
i++;
} else if (!strcmp(argv[i], "-E"))
Comment thread
cubic-dev-ai[bot] marked this conversation as resolved.
expand_only = true;
else if (!strcmp(argv[i], "-o")) {
if (i + 1 < argc) {
Expand All @@ -131,10 +142,21 @@ int main(int argc, char *argv[])
in = argv[i];
}

if (dynlink) {
switch (ELF_MACHINE) {
/* The following 64-bit targets have no lazy-resolution path, so
* immediate binding must be used.
*/
case ELF_MACHINE_X86_64:
case ELF_MACHINE_AARCH64:
imm_binding = true;
}
}

if (!in) {
printf(
"Usage: shecc [-o output] [+m] [--dot] [--dump-ir] [--no-libc] "
"[--dynlink] [-E] <input.c>\n");
"[--dynlink] [-z <lazy | now>] [-E] <input.c>\n");
usage_error("Missing source file");
}

Expand Down
6 changes: 4 additions & 2 deletions tests/arm-abi.sh
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,10 @@ fi

# Command Line Arguments
if [ "$#" -lt 1 ]; then
echo "Usage: $0 <stage> [<dynlink>]"
echo "Usage: $0 <stage> [<dynlink> [<binding>]]"
echo " stage: 0 (host compiler), 1 (stage1), or 2 (stage2)"
echo " dynlink: 0 (static linking), 1 (dynamic linking)"
echo " binding: lazy, now"
echo ""
echo "Environment Variables:"
echo " VERBOSE=1 Enable verbose output"
Expand Down Expand Up @@ -73,6 +74,7 @@ case "$1" in
esac

DYNLINK="${2:-0}"
BINDING="${3:-lazy}"

# Banner
echo -e "${BLUE}${BOLD}========================================${NC}"
Expand Down Expand Up @@ -144,7 +146,7 @@ run_abi_test()
# Compile
local compile_cmd="$SHECC"
if [[ "$DYNLINK" == "1" ]]; then
compile_cmd="$compile_cmd --dynlink"
compile_cmd="$compile_cmd --dynlink -z $BINDING"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: When the binding argument contains shell syntax, this line inserts it into an eval string, so the ABI test executes it as a separate command. Escape the value or execute the compiler through an argv array.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At tests/arm-abi.sh, line 149:

<comment>When the binding argument contains shell syntax, this line inserts it into an `eval` string, so the ABI test executes it as a separate command. Escape the value or execute the compiler through an argv array.</comment>

<file context>
@@ -144,7 +146,7 @@ run_abi_test()
     local compile_cmd="$SHECC"
     if [[ "$DYNLINK" == "1" ]]; then
-        compile_cmd="$compile_cmd --dynlink"
+        compile_cmd="$compile_cmd --dynlink -z $BINDING"
     fi
     compile_cmd="$compile_cmd -o /tmp/shecc_abi_test_$$.elf $test_file"
</file context>
Suggested change
compile_cmd="$compile_cmd --dynlink -z $BINDING"
compile_cmd="$compile_cmd --dynlink -z $(printf '%q' "$BINDING")"

fi
compile_cmd="$compile_cmd -o /tmp/shecc_abi_test_$$.elf $test_file"

Expand Down
4 changes: 2 additions & 2 deletions tests/arm64-abi.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
set -eu

if [ "$#" -lt 1 ]; then
echo "Usage: $0 <stage> [<dynlink>]" >&2
echo "Usage: $0 <stage> [<dynlink> [<binding>]]" >&2
exit 2
fi

Expand All @@ -23,7 +23,7 @@ case "$1" in
esac

if [ "${2:-0}" = 1 ]; then
shecc+=(--dynlink)
shecc+=(--dynlink -z "${3:-lazy}")
link_mode=dynamic
else
link_mode=static
Expand Down
2 changes: 1 addition & 1 deletion tests/driver.sh
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ case "$1" in
esac

if [ $# -ge 2 ] && [ "$2" = "1" ]; then
readonly SHECC_CFLAGS="--dynlink"
readonly SHECC_CFLAGS="--dynlink ${3:-lazy}"
readonly LINK_MODE="dynamic"
else
readonly SHECC_CFLAGS=""
Expand Down
6 changes: 4 additions & 2 deletions tests/riscv-abi.sh
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,10 @@ fi

# Command Line Arguments
if [ "$#" -lt 1 ]; then
echo "Usage: $0 <stage> [<dynlink>]"
echo "Usage: $0 <stage> [<dynlink> [<binding>]]"
echo " stage: 0 (host compiler), 1 (stage1), or 2 (stage2)"
echo " dynlink: 0 (static linking), 1 (dynamic linking)"
echo " binding: lazy, now"
echo ""
echo "Environment Variables:"
echo " VERBOSE=1 Enable verbose output"
Expand Down Expand Up @@ -73,6 +74,7 @@ case "$1" in
esac

DYNLINK="${2:-0}"
BINDING="${3:-lazy}"

# Banner
echo -e "${BLUE}${BOLD}========================================${NC}"
Expand Down Expand Up @@ -144,7 +146,7 @@ run_abi_test()
# Compile
local compile_cmd="$SHECC"
if [[ "$DYNLINK" == "1" ]]; then
compile_cmd="$compile_cmd --dynlink"
compile_cmd="$compile_cmd --dynlink -z $BINDING"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: An unvalidated binding argument is inserted into a command string executed by eval, so invoking this test script with a crafted third argument executes arbitrary shell commands. Validate the value against lazy|now or shell-escape it before constructing the command.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At tests/riscv-abi.sh, line 149:

<comment>An unvalidated `binding` argument is inserted into a command string executed by `eval`, so invoking this test script with a crafted third argument executes arbitrary shell commands. Validate the value against `lazy|now` or shell-escape it before constructing the command.</comment>

<file context>
@@ -144,7 +146,7 @@ run_abi_test()
     local compile_cmd="$SHECC"
     if [[ "$DYNLINK" == "1" ]]; then
-        compile_cmd="$compile_cmd --dynlink"
+        compile_cmd="$compile_cmd --dynlink -z $BINDING"
     fi
     compile_cmd="$compile_cmd -o /tmp/shecc_abi_test_$$.elf $test_file"
</file context>
Suggested change
compile_cmd="$compile_cmd --dynlink -z $BINDING"
compile_cmd="$compile_cmd --dynlink -z $(printf '%q' "$BINDING")"

fi
compile_cmd="$compile_cmd -o /tmp/shecc_abi_test_$$.elf $test_file"

Expand Down
6 changes: 4 additions & 2 deletions tests/x64-abi.sh
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,10 @@ fi

# Command Line Arguments
if [ "$#" -lt 1 ]; then
echo "Usage: $0 <stage> [<dynlink>]"
echo "Usage: $0 <stage> [<dynlink> [<binding>]]"
echo " stage: 0 (host compiler), 1 (stage1), or 2 (stage2)"
echo " dynlink: 0 (static linking), 1 (dynamic linking)"
echo " binding: lazy, now"
echo ""
echo "Environment Variables:"
echo " VERBOSE=1 Enable verbose output"
Expand Down Expand Up @@ -74,6 +75,7 @@ case "$1" in
esac

DYNLINK="${2:-0}"
BINDING="${3:-lazy}"

# Banner
echo -e "${BLUE}${BOLD}========================================${NC}"
Expand Down Expand Up @@ -149,7 +151,7 @@ run_abi_test()
# Compile
local compile_cmd="$SHECC"
if [[ "$DYNLINK" == "1" ]]; then
compile_cmd="$compile_cmd --dynlink"
compile_cmd="$compile_cmd --dynlink -z $BINDING"
fi
compile_cmd="$compile_cmd -o /tmp/shecc_abi_test_$$.elf $test_file"

Expand Down