使用wprintf-linux-x86-64平台打印出汇编中的unicode字符



我使用的是linux,只是在试验nasm和gas。我可以使用wprintf和c++打印出unicode字符

#include <wchar.h>
#include <locale.h>
#include <stdio.h>
int main() 
{
  //printf("helloworld"); // can't do this AND wprintf in same program
  setlocale(LC_ALL, "");
  wprintf(L"%lc",0x307E); //prints out japanese hiragana ma ま
}

然而,我对尝试在汇编(intel和gas语法)中进行这项操作感到非常困惑。我的主要困惑是.data部分。我甚至给gcc设置了-S开关,看看他们是如何做到这一点的。他们用13个.string语句来格式化字符串,其中许多是空白字符串,每个字符都在一个单独的.string上。我读到,在nasm中,通过将字符串放在dw而不是db中,基本上可以将常规字符串变成宽字符串。所以我当然试过用.int表示气体,但效果不太好。我的意思是它会打印出额外的灰色问号。这是我当前的代码

.section .data
locale:
  .string ""
printformat:
  .int '%','l','c'
printwide:
  .int 0x307E,0
.section .text
.global _start
_start:
movq    $locale,%rsi
movq    $6,%rdi
call    setlocale
movq    $printformat,%rdi
movq    $printwide,%rsi
movq    $0,%rax
call    wprintf
movq    $2,%rdi
call    exit

这导致5个灰色的问号,然后是平假名ま(ma)。你可能会认为在"%"、"l"、"c"之后应该有一个,0,但这不起作用——这样做之后只会输出问号。我能够打印出平假名ma而不打问号的唯一方法是跳过格式字符串,将printwide加载到rdi中。

同样,目前这是出于教育目的。所以基本上,如何在&t语法和intel?在c++中,你只需在它前面加一个L。(是的,我想你可以把%lc改成十六进制,但我不想那样做)

EDIT这是有效的(我把$printwide改成了printwide,把printformat:改成了.strings,就像gcc-S清单一样。)但是为什么它有效呢?除了使用这么多.string语句之外,还有更好的方法来写格式吗?在intel语法中,你会怎么做?

.section .data
locale:
    .string ""
printformat:
    .string "%"
    .string ""
    .string ""
    .string "l"
    .string ""
    .string ""
    .string "c"
    .string ""
    .string ""
    .string ""
    .string ""
    .string ""
    .string ""
printwide:
    .word 0x307E
.section .text
.global _start
_start:
movq    $locale,%rsi
movq    $6,%rdi
call    setlocale
movq    $printformat,%rdi
movq    printwide,%rsi
movq    $0,%rax
call    wprintf
movq    $2,%rdi
call    exit

我对这个答案感到惊讶。我猜64位宽的字符是32位的。我是通过阅读nasm发现这一点的。您可以通过以下在intel语法中生成字符串utf-16

printformat dw __utf16__("%lc"),0

然而,它只有在我做时才起作用

printformat dd __utf32__("%lc"),0

因此at&t语法为

.long '%','l','c',0

我想gcc-S的列表使用了这么多字符串,使其成为32位宽的

.string"%"=16位(%和自动零),然后用空字符串再加8位,然后用另一个空字符串再加8位。

最新更新