「7f  ELF」から「LIFULL」を作る（四則演算、ビットシフト使用禁止縛り）

[強いエンジニアにHelloWorldさせてみた(縛りあり)](https://qiita.com/imishinist/items/1883b5eef836aeee93ff)

…という記事のお題が面白かったので、僕もコメント欄に参加させていただきました。

僕は以下のようなコードを書きました。すなわち、自分自身のELFヘッダからマジックナンバー「`ELF`」を抜いてきて、無理やり「`LIFULL`」に繋げようとしたコードなのですが…

```c:C99
#include <stdio.h>                                                                             
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

int main(int argc, char *argv[])
{

    struct stat sb; 

    int fd = open(*argv, O_RDONLY);
    fstat(fd, &sb);
    unsigned char *head = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fd, sizeof(char) - sizeof(char));

    size_t iti = sizeof(char);
    size_t ni = iti + iti;
    size_t san = iti + ni; 
    size_t yon = ni + ni; 

    char E = head[iti];
    char L = head[ni];
    char F = head[san];
    /* ↓↓↓ ここのオチが弱い ↓↓↓ */
    char I = (F + L) / ni; 
    char U = E | iti<<yon;
    /* ↑↑↑ ここのオチが弱い ↑↑↑ */
    char NUL = sizeof(char) - sizeof(char);

    const char fudosan_to_jutaku_no_kotonara[] = { L, I, F, U, L, L, NUL };

    puts(fudosan_to_jutaku_no_kotonara);

    munmap(head, sb.st_size);
    close(fd);
}
```

`ELF`（`0x45 0x4c 0x46`）から`LIFULL`（`0x4c 0x49 0x46 0x55 0x4c 0x4c`）を作るにあたり、不足した文字`I`（`0x49`）と`U`（`0x55`）を作成する必要があります。そこは御多分に漏れず、足し算やビットシフトを用いてASCIIコードを作っています。

しかし、これではオチが弱いのではないかと...。これでは真に「`ELF`から`LIFULL`を作った」ことにはならない、と。

そこで独自の縛り（以下）を加えて、あらためてチャレンジしました。

#独自縛り
##×使用してはいけない演算子
ソースコード中に、以下の演算子が出現してはならない。

* 二項`+`、二項`-`、二項`*`、`%`、`/`
* 前置/後置`++`
* 前置/後置`--`
* `sizeof`演算子
* `!`演算子
* ビット単位シフト演算子`<<``>>`
* 関係演算子`==``!=``<=``>=``<``>`

##〇使用してよい演算子
ソースコード中に、以下の演算子は出現してよい。

* 単項`-`演算子
* ビット単位AND`&`、ビット単位OR`|`、ビット単位排他OR`^`
* `~`演算子
* 添字演算子`[]`
* 代入演算子`=`
* アドレス演算子`&`、単項`*`演算子
* 関数呼出し`()`演算子

#書いてみた

上記縛りが無いもとでは、数値`1`さえ作ってしまえば後は地道な四則演算でどうとでもなりましたが、今回は四則演算もビットシフトも禁止なため、`1`を作るところから、ちょっとハードルが高かったです。

今回は、最初に使える材料が「0x7f」のみで、そこから`E`を参照するための添字をビット操作で作成し、取得した`E`をビット操作して`L`と`F`を参照する添字を作成し…と材料を増やしていき、最後は`ELF`からビット操作で`I`と`U`をひねり出して、なんとか`LIFULL`まで辿り着きました。

できたコードが、これです。

```c:C99
#include <stdio.h>                   
#include <fcntl.h>                   
#include <sys/mman.h>                
#include <sys/types.h>               
#include <sys/stat.h>                
#include <unistd.h>                  
                                     
int main(int argc, char *argv[])  
{                                    
    struct stat sb;                  
                                     
    int fd = open(*argv, O_RDONLY);
    fstat(fd, &sb);                  
    unsigned char *head = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fd, argc ^ argc);
                                     
    char magic = *head;                
    char E = head[magic & -magic];       
    char L = head[~E & -~E];         
    char F = head[~(~-E | -~-E)];                                                                        
    char I = -(-L | ~L);             
    char U = -(-L&~L) & (~-~(-(-L|~L))) | E;
    char NUL = E ^ E;                
                                     
    const char fudosan_to_jutaku_no_kotonara[] = { L, I, F, U, L, L, NUL };
                                     
    puts(fudosan_to_jutaku_no_kotonara);
                                     
    munmap(head, sb.st_size);        
    close(fd);                       
} 
```

```bash:実行結果
$ ./lifull 
LIFULL
```