// Minimal startup replacement for JudgeDuck (duck.ac) static binaries.
//
// Replaces glibc's __libc_start_main, which costs ~2.4us on the judge.
// Provides: TLS setup (wrfsbase), __environ, IRELATIVE relocation processing,
// then calls main() and exits via the duck exit syscall.
#ifndef DUCKSTART_H
#define DUCKSTART_H
typedef unsigned long long u64;
typedef unsigned int u32;
typedef long i64;
struct DuckInfo_t {
u64 abi_version;
const char *stdin_ptr;
u64 stdin_size;
char *stdout_ptr;
u64 stdout_limit;
u64 stdout_size;
char *stderr_ptr;
u64 stderr_limit;
u64 stderr_size;
const char *IB_ptr;
u64 IB_limit;
char *OB_ptr;
u64 OB_limit;
u64 tsc_frequency;
} __attribute__((packed));
struct Elf64_Phdr_ {
u32 p_type; u32 p_flags; u64 p_offset; u64 p_vaddr; u64 p_paddr;
u64 p_filesz; u64 p_memsz; u64 p_align;
};
struct Rela_ { u64 r_offset; u64 r_info; i64 r_addend; };
extern "C" char **environ;
static inline void duck_raw_exit(int code) {
register long rax __asm__("rax") = 60;
register long rdi __asm__("rdi") = code;
__asm__ volatile("syscall" :: "a"(rax), "D"(rdi) : "rcx", "r11", "memory");
__builtin_unreachable();
}
static inline char **duck_envp(int argc, char **argv) { return argv + argc + 1; }
static inline u64 *duck_auxv(int argc, char **argv) {
char **env = argv + argc + 1;
while (*env) env++;
return (u64 *)(env + 1);
}
static inline u64 duck_aux(int argc, char **argv, u64 type) {
u64 *p = duck_auxv(argc, argv);
for (; p[0]; p += 2) if (p[0] == type) return p[1];
return 0;
}
static inline DuckInfo_t *duck_info(int argc, char **argv) {
return (DuckInfo_t *) duck_aux(argc, argv, 0x6b637564ULL); // AT_DUCK
}
// ---- TLS -------------------------------------------------------------
static void duck_setup_tls(int argc, char **argv) {
u64 phdr = duck_aux(argc, argv, 3); // AT_PHDR
u64 phent = duck_aux(argc, argv, 4); // AT_PHENT
u64 phnum = duck_aux(argc, argv, 5); // AT_PHNUM
if (!phdr || !phent) return;
const char *init = 0; u64 filesz = 0, memsz = 0, align = 64;
for (u64 i = 0; i < phnum; i++) {
const Elf64_Phdr_ *ph = (const Elf64_Phdr_ *)(phdr + i * phent);
if (ph->p_type == 7) { // PT_TLS
init = (const char *)ph->p_vaddr; filesz = ph->p_filesz;
memsz = ph->p_memsz; align = ph->p_align; break;
}
}
if (!memsz) return;
if (align < 16) align = 16;
u64 tls_size = (memsz + align - 1) / align * align;
static char area[1 << 16] __attribute__((aligned(64)));
char *block = area;
char *tp = block + tls_size;
for (u64 i = 0; i < tls_size; i++) block[i] = 0;
for (u64 i = 0; i < filesz; i++) block[tls_size - filesz + i] = init[i];
static void *dtv[4];
dtv[0] = (void *)1; dtv[1] = block; dtv[2] = 0; dtv[3] = 0;
void **tcb = (void **)tp;
tcb[0] = tp; // tcb
tcb[1] = &dtv[0]; // dtv
tcb[2] = tp; // self
((int *)tp)[6] = 0; // multiple_threads
__asm__ volatile("wrfsbase %0" :: "r"((u64)tp));
}
// ---- IRELATIVE -------------------------------------------------------
static void duck_irel(void) {
extern const Rela_ __rela_iplt_start[] __attribute__((weak));
extern const Rela_ __rela_iplt_end[] __attribute__((weak));
if (!__rela_iplt_start || !__rela_iplt_end) return;
for (const Rela_ *p = __rela_iplt_start; p < __rela_iplt_end; p++) {
if ((u32)p->r_info == 37) { // R_X86_64_IRELATIVE
void *(*resolver)(void) = (void *(*)(void))p->r_addend;
*(void **)p->r_offset = resolver();
}
}
}
// ---- entry -----------------------------------------------------------
extern "C" int __libc_start_main(int (*main)(int, char **, char **), int argc, char **argv,
void (*init)(void), void (*fini)(void),
void (*rtld_fini)(void), void *stack_end) {
char **envp = duck_envp(argc, argv);
environ = envp;
#ifndef DUCK_NO_IREL
duck_irel();
#endif
#ifndef DUCK_NO_TLS
duck_setup_tls(argc, argv);
#endif
if (init) init();
main(argc, argv, envp);
duck_raw_exit(0);
return 0;
}
#endif
static __thread int tv = 42;
int main(){ volatile int x = tv; if(x==99) return 1; return 0; }
| Compilation | N/A | N/A | Compile OK | Score: N/A | 显示更多 |
| Testcase #1 | 3.23 us | 8 KB | Accepted | Score: 100 | 显示更多 |